如果您在构建脚本中构建静态库,并且希望在链接最终可执行文件时使用这些静态库,那么提到.a
文件的顺序很重要:
g++ main.o hw.a gui.a -o executable
如果gui.a
使用hw.a
中定义的东西,链接将失败,因为在处理hw.a
时,链接器还不知道稍后需要该定义,并且没有将其包含在存在中。生成的可执行文件。手动修改链接器行是不实际的,所以一个解决方案是使用--start-group
和--end-group
,这使得链接器在库中运行两次,直到没有发现未定义的符号为止。
g++ main.o -Wl,--start-group hw.a gui.a -Wl,--end-group -o executable
但是GNU手册说
使用这个选项会有很大的性能成本。最好只在两个或多个档案之间不可避免地存在循环引用时使用它。
所以我认为它可能是更好的把所有的.a
文件,并把它们放在一个.a
文件与索引(GNU ar的-s
选项),说在什么顺序的文件需要被链接。然后只给g++
一个.a
文件。
但是我想知道这是比使用组命令更快还是更慢。这种方法有什么问题吗?我也在想,有没有更好的办法来解决这些相互依赖的问题?
编辑:我写了一个程序,获取.a
文件列表并生成合并的.a
文件。适用于GNU通用ar
格式。将LLVM的所有静态库打包在一起的工作方式如下
$ ./arcat -o combined.a ~/usr/llvm/lib/libLLVM*.a
我比较了手动解包所有.a
文件的速度,然后使用ar
将它们放入新的.a
文件中,重新计算索引。使用我的arcat
工具,我得到了大约500ms的稳定运行时间。使用手动方式,时间变化很大,大约需要2s左右。所以我觉得很值得。
代码在这里。我把它放到公共领域了:)
您可以使用lorder
和tsort
实用程序来确定顺序,例如
libs='/usr/lib/libncurses.a /usr/lib/libedit.a'
libs_ordered=$(lorder $libs | tsort)
导致/usr/lib/libedit.a /usr/lib/libncurses.a
,因为libedit依赖libncurses。
如果您不为每个链接命令再次运行lorder
和tsort
,这可能只是--start-group
之上的一个好处。此外,它不允许像--start-group
那样的相互/循环依赖。
是否有第三种选择,您只是建立一个单一的库开始?我也遇到过类似的问题,最后我决定采用第三种方法。
根据我的经验,group比仅仅统一。a文件要慢。您可以从存档中提取所有文件,然后从较小的文件
创建一个新的。a文件。但是,您必须小心两个文件碰巧包含相同定义的情况(您可以通过使用nm
显式检查这一点,以查看每个库中包含的定义)