【问题标题】:Is using --start-group and --end-group when linking faster than creating a static library?链接比创建静态库更快时使用 --start-group 和 --end-group 吗?
【发布时间】:2011-10-26 13:18:46
【问题描述】:

如果一个人在自己的构建脚本中构建静态库,并且想要使用这些静态库来链接最终的可执行文件,那么提到 .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 文件放在一个带有索引的.a 文件中(GNU ar 的-s 选项),该索引说明文件需要按什么顺序排列链接。然后一个人只把那个.a文件给g++。

但我想知道这是否比使用组命令更快或更慢。这种方法有什么问题吗?我也想知道,有没有更好的方法来解决这些相互依赖的问题?


编辑:我编写了一个程序,它采用.a 文件列表并生成合并的.a 文件。适用于 GNU 通用 ar 格式。像这样将 LLVM 的所有静态库打包在一起

$ ./arcat -o combined.a ~/usr/llvm/lib/libLLVM*.a

我将速度与手动解压缩所有.a 文件然后使用ar 将它们放入一个新的.a 文件进行比较,重新计算索引。使用我的arcat 工具,我获得了大约 500 毫秒的一致运行时间。使用手动方式,时间变化很大,大约需要2s左右。所以我觉得值得。

Code is here。我把它放到公共领域:)

【问题讨论】:

    标签: linker static-libraries unix-ar .a


    【解决方案1】:

    您可以使用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 这样的相互/循环依赖。

    【讨论】:

    • 在问这个问题之前,我试图为 linux 找到 lorder,但我找不到它。我在互联网上找到的仅有的几个手册页说 lorder 已弃用,ar 取代了它。我找不到必须给ar 的WTF 命令,所以它与lorder 的作用相同。
    • Debian 和 Ubuntu 在 bsdmainutils 包中都有它。
    【解决方案2】:

    是否有第三种选择,您可以从构建一个库开始?我遇到了类似的问题,最终决定采用第三种选择。

    根据我的经验,组比统一 .a 文件要慢。您可以从存档中提取所有文件,然后从较小的文件中创建一个新的 .a 文件

    但是,您必须小心两个文件恰好包含相同定义的情况(您可以使用nm 明确检查这一点,以查看每个库中包含哪些定义)

    【讨论】:

    • +1 当两个库相互依赖时,创建两个库绝对没有意义。
    • @R..,我不明白。世界上到处都是依赖于其他库的库。以铿锵声为例。它的 libsema 依赖于它的 libast。将它们融合到一个库中并不好。将库分开的全部意义在于不要将完全不相关的功能拖到另一个库中。
    • 即使 libB 依赖于 libA,只要 libA 可以独立于 libB 使用,它们作为单独的库也是可以的。但是,如果两者之间存在相互依赖,那么将它们分开纯粹是一件麻烦事。
    • @R.. 在我描述的情况下,不一定存在相互依赖关系。在修改源文件以添加依赖项时,我不想修改构建脚本/生成文件以更改 .a 文件的顺序。在多人项目中,人员编程甚至不一定参与管理构建文件。
    • @FooBah 我的arcat 似乎有效。你不需要解决任何问题。您只需要在索引中说明符号所在的位置(在哪个存档成员中)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-16
    • 2016-06-28
    • 2011-08-04
    • 2020-07-21
    • 2020-12-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多