将档案链接到档案
Linking an archive to an archive
使用 Linux 上的 GCC,是否可以 link 将一个 .a 转换为另一个 .a,然后仅 link 将结果 .a 用于我的应用程序?或者我的应用程序必须知道一个存档与另一个存档之间的依赖关系,并且 link 它们都是?
我的理解是一定要在最后才知道依赖关系和link所有的存档,而不是在中间步骤,这样显得有点难看。
这与 How to merge two "ar" static libraries into one 略有不同,因为我在清楚地描述了这只能通过解决问题来实现,并且 link 以天真的方式将两个档案放在一起是不正确,将不起作用,以及原因。
让 libx.a
和 liby.a
成为您要合并的模块。你可以试试:-
mkdir tmp # create temporary directory for extracting
cd tmp
ar x ../libx.a # extract libx.a
cp ../liby.a ../libxy.a
ar -q ../libxy.a * # add extracted files to libxy.a
cd ..
rm -rf tmp
libxy.a
因此创建包含来自两个 .a
个文件
的 .o
个文件
是的,您的应用程序必须知道不同静态库之间的依赖关系。
- 假设您有两个静态库
a
和 b
.
a
有一个函数 void print_a()
,b
有一个调用 print_a()
的函数 void print_b()
。所以,b
取决于 a
.
- 他们的二进制文件看起来像
liba.a
和 libb.a
。
假设库 b
引用了库 a
- void print_b(void)
中定义的函数。
编译库 b
时,只有它的符号在二进制代码部分定义,而其他符号仍未定义:
host$ nm libb.a | grep print
U _print_a <--- Undefined
0000000000000000 T _print_b <--- Defined, in code section
0000000000000068 S _print_b.eh
U _printf
因此,在编译要使用这两个库的应用程序时,仅 link 到 libb.a
是不够的。您必须 link 向两个图书馆申请。每个库都会在代码部分提供自己的符号地址,然后您的应用程序将能够 link 两者。
类似于:
gcc -o main main.c libb.a liba.a
顺便说一句:在编译使用a
的库b
时,可以但没有必要link 到a
。结果还是一样。
为什么会这样
编译+ linking使用静态库的应用程序时,应用程序源文件中的符号必须在某处定义(动态linking除外,但这样做仅使用动态 libraries/shared 对象。这里我们处理静态对象)。
现在,请记住静态库只是对象的存档。创建时没有 linking 阶段。只是:
- 将源代码 (
*.c
) 编译为对象 (*.o
)
- 将它们一起存档在一个
libXXXX.a
文件中。
这意味着如果这个库(在我的例子中是库b
)使用了另一个库(a
)中定义的一些函数(void print_a(void)
),这个符号将不会'无法解决(不是作为编译错误,而是作为正常行为)。在创建库后,它将被设置为 Undefined 符号(正如我们在 nm
命令的输出中看到的),它将等待稍后被 linked到它的定义。没关系,因为静态库不可执行。
现在返回应用程序 - 应用程序的 linking 阶段需要找到所有符号的所有 定义。如果你只是给它 libb.a
作为参数,它就无法找到 print_a()
的定义,因为它不存在,它仍然是 undefined。它仅存在于 liba.a
.
因此,您必须同时提供这两个库。
使用 Linux 上的 GCC,是否可以 link 将一个 .a 转换为另一个 .a,然后仅 link 将结果 .a 用于我的应用程序?或者我的应用程序必须知道一个存档与另一个存档之间的依赖关系,并且 link 它们都是?
我的理解是一定要在最后才知道依赖关系和link所有的存档,而不是在中间步骤,这样显得有点难看。
这与 How to merge two "ar" static libraries into one 略有不同,因为我在清楚地描述了这只能通过解决问题来实现,并且 link 以天真的方式将两个档案放在一起是不正确,将不起作用,以及原因。
让 libx.a
和 liby.a
成为您要合并的模块。你可以试试:-
mkdir tmp # create temporary directory for extracting
cd tmp
ar x ../libx.a # extract libx.a
cp ../liby.a ../libxy.a
ar -q ../libxy.a * # add extracted files to libxy.a
cd ..
rm -rf tmp
libxy.a
因此创建包含来自两个 .a
个文件
.o
个文件
是的,您的应用程序必须知道不同静态库之间的依赖关系。
- 假设您有两个静态库
a
和b
. a
有一个函数void print_a()
,b
有一个调用print_a()
的函数void print_b()
。所以,b
取决于a
.- 他们的二进制文件看起来像
liba.a
和libb.a
。
假设库 b
引用了库 a
- void print_b(void)
中定义的函数。
编译库 b
时,只有它的符号在二进制代码部分定义,而其他符号仍未定义:
host$ nm libb.a | grep print
U _print_a <--- Undefined
0000000000000000 T _print_b <--- Defined, in code section
0000000000000068 S _print_b.eh
U _printf
因此,在编译要使用这两个库的应用程序时,仅 link 到 libb.a
是不够的。您必须 link 向两个图书馆申请。每个库都会在代码部分提供自己的符号地址,然后您的应用程序将能够 link 两者。
类似于:
gcc -o main main.c libb.a liba.a
顺便说一句:在编译使用a
的库b
时,可以但没有必要link 到a
。结果还是一样。
为什么会这样
编译+ linking使用静态库的应用程序时,应用程序源文件中的符号必须在某处定义(动态linking除外,但这样做仅使用动态 libraries/shared 对象。这里我们处理静态对象)。
现在,请记住静态库只是对象的存档。创建时没有 linking 阶段。只是:
- 将源代码 (
*.c
) 编译为对象 (*.o
) - 将它们一起存档在一个
libXXXX.a
文件中。
这意味着如果这个库(在我的例子中是库b
)使用了另一个库(a
)中定义的一些函数(void print_a(void)
),这个符号将不会'无法解决(不是作为编译错误,而是作为正常行为)。在创建库后,它将被设置为 Undefined 符号(正如我们在 nm
命令的输出中看到的),它将等待稍后被 linked到它的定义。没关系,因为静态库不可执行。
现在返回应用程序 - 应用程序的 linking 阶段需要找到所有符号的所有 定义。如果你只是给它 libb.a
作为参数,它就无法找到 print_a()
的定义,因为它不存在,它仍然是 undefined。它仅存在于 liba.a
.
因此,您必须同时提供这两个库。