gpt4 book ai didi

build - 构建共享库时,是否只需要依赖库的头文件?

转载 作者:行者123 更新时间:2023-12-02 16:59:30 32 4
gpt4 key购买 nike

假设共享库A 依赖于另一个共享库B

在这种情况下,当我构建A时,是否只需要B的头文件?因为只有当我构建一些需要 A 的程序时才需要 B。这样对吗?你能解释一下细节吗?

最佳答案

你是对的。这是一个具体的例子。

啊.h

#ifndef A_H
#define A_H

extern void aa(void);

#endif

交流

#include "a.h"
#include "b.h"

void aa(void)
{
bb();
}

b.h

#ifndef B_H
#define B_H

extern void bb(void);

#endif

BC

#include "b.h"
#include <stdio.h>

void bb(void)
{
puts(__func__);
}

ma​​in.c

#include "a.h"

int main(void)
{
aa();
return 0;
}

我们制作了一个共享库liba.so。先编译一个PIC (Position Independent)目标文件。

$ gcc -Wall -Wextra -o a.o -c -fPIC a.c

现在目标文件 a.o 包含对 bb 的 undefined reference :

$ readelf -s a.o

Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
...
10: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bb

链接共享库:

$ gcc -shared -o liba.so a.o

现在共享库还对 bb 进行了 undefined reference :

$ readelf --dyn-syms liba.so

Symbol table '.dynsym' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
...
2: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND bb
...

没关系。 链接器将创建一个包含 undefined reference 的共享库

以同样的方式制作另一个共享库libb.so:

$ gcc -Wall -Wextra -o b.o -c -fPIC b.c
$ gcc -shared -o libb.so b.o

这个共享库定义了bb:

$ readelf --dyn-syms libb.so

Symbol table '.dynsym' contains 12 entries:
Num: Value Size Type Bind Vis Ndx Name
...
11: 000000000000060a 19 FUNC GLOBAL DEFAULT 12 bb

接下来尝试做一个程序:

$ gcc -Wall -Wextra -o main.o -c main.c
$ gcc -o prog main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `aa'
collect2: error: ld returned 1 exit status

当我们既不链接 liba 也不链接 libb 时就会发生这种情况。链接器将不要创建包含 undefined reference 的程序。所以:

$ gcc -o prog main.o liba.so
liba.so: undefined reference to `bb'
collect2: error: ld returned 1 exit status

这就是我们链接 liba 而不是 libb 时发生的情况。如果我们链接两者都像:

$ gcc -o prog main.o liba.so libb.so

成功了!但是要小心。如果我们交换库的顺序:

$ gcc -o prog main.o libb.so liba.so
liba.so: undefined reference to `bb'
collect2: error: ld returned 1 exit status

联动再次失败。也是如此:

$ gcc -o prog libb.so liba.so main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `aa'
collect2: error: ld returned 1 exit status

链接器需要在其他之后看到一个库依赖于它的库或目标文件。所以main.o必须链接在liba之前,和 liba 必须在 libb 之前链接。

还有最后一个问题

$ gcc -o prog main.o liba.so libb.so

或等同于:

$ gcc -o prog main.o -L. -la -lb

成功链接程序 prog,但是:

$ ./prog
./prog: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory

它不会运行。因为运行时加载器仍然不知道在哪里寻找 libalibb

加载器知道 prog 需要一些名为 liba.solibb.so 的共享库,因为链接器已经写好了信息到 prog:

$ readelf -d prog

Dynamic section at offset 0xda8 contains 29 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [liba.so]
0x0000000000000001 (NEEDED) Shared library: [libb.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
...

就像链接器一样,有directories where the loader will search for shared libraries by default .它将在这些默认目录之一中找到 libc.so.6(GNU C 库)。但它不会找到我的 liba.solibb.so只是内置其中任何一个。

但是我可以告诉链接器为加载器提供缺少的信息,通过链接程序是这样的:

$ gcc -o prog main.o -L. -la -lb -Wl,-rpath=$PWD

使用 -Wl,-rpath=$PWD,我告诉 gcc 传递(扩展的)选项 -rpath=$PWD到链接器,如果我们这样做,我们将看到:

$ readelf -d prog

Dynamic section at offset 0xd98 contains 30 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [liba.so]
0x0000000000000001 (NEEDED) Shared library: [libb.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/home/imk/develop/so/scrap1]
...

现在当加载器加载 prog 时,它会看到 RUNPATH=/home/imk/develop/so/scrap1是一个非默认目录,它还应该在其中搜索任何 NEEDED 共享库。 编程然后可以成功加载其所有运行时依赖项:

$ ./prog
bb

关于build - 构建共享库时,是否只需要依赖库的头文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54779000/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com