如果在一个构建脚本中构建静态库,并且想要在链接最终可执行文件时使用这些静态库,那么提及.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 ld手册说
使用此选项会产生显着的性能损失。最好只在两个或多个档案之间存在不可避免的循环引用时使用它。
所以我认为最好采用所有.a
文件并将它们放在一个带有索引(GNU ar的.a
选项)的-s
文件中,该文件说明了什么命令文件需要链接。然后,只有一个.a
文件给g++
。
但我想知道这是否比使用组命令更快或更慢。这种方法有什么问题吗?我也想知道,有没有更好的方法来解决这些相互依赖问题?
编辑:我编写了一个程序,该程序获取.a
个文件列表并生成合并的.a
文件。使用GNU通用ar
格式。将LLVM的所有静态库打包在一起就像这样工作
$ ./arcat -o combined.a ~/usr/llvm/lib/libLLVM*.a
我将速度与手动解压缩所有.a
文件进行比较,然后使用.a
将它们放入新的ar
文件中,重新计算索引。使用我的arcat
工具,我获得了大约500毫秒的一致运行时间。使用手动方式,时间变化很大,大约需要2秒。所以我认为这是值得的。
Code is here。我把它放到公共领域:)
答案 0 :(得分:3)
您可以使用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。
如果您没有为每个链接命令再次运行--start-group
和lorder
,则这可能只是高于tsort
的好处。此外,它不允许像--start-group
那样的相互/循环依赖。
答案 1 :(得分:2)
是否有第三个选项,您只需构建一个单独的库?我有一个类似的问题,我最终决定采用第三种选择。
根据我的经验,群组比仅统一.a文件慢。您可以从存档中提取所有文件,然后从较小的文件中创建一个新的.a文件
但是,您必须小心两个文件恰好包含相同定义的情况(您可以使用nm
显式检查这一点,以查看每个库中包含的定义)