使用GCC连接静态库的正确方法

24
为什么一些静态库(lib*.a)可以像共享库(lib*.so)一样通过链接(ld -l开关)链接,但有些不行?
我一直被教导说所有库,无论是静态的还是非静态的,都可以使用-l...进行链接,然而我遇到过一个库(GLFW),如果我尝试以这种方式链接它,它就会不停地输出“undefined reference”链接错误。
根据这个问题上的回答,连接静态库的“正确”方法是直接将它们包含在内,以及我的自己的目标文件,而不是使用-l。在GLFW库的情况下,这确实解决了问题。但我使用的其他所有静态库都可以通过使用-l进行链接。
所以:
  • 什么原因会导致这个库不能通过链接而必须直接包含?如果我知道原因,也许我可以编辑和重新编译库来修复这个问题。
  • 你是否应该以与链接共享库不同的方式链接静态库?(如果不是,为什么不是?)
  • 当以这种方式直接包含库时,链接器是否仍能消除未使用的库函数并从输出可执行文件中消除它们?
4个回答

28

感谢回复!事实证明问题是由于链接顺序引起的。显然,如果您使用了一个库,该库又具有其他库依赖关系,则这些其他依赖项必须在库之后而不是像我一直在做的那样放在库之前。学到了新的东西!


不回答问题。是的,它解决了一些特定的问题,可能促使您提出这个普遍的问题。不幸的是,大多数人会来这里寻求按照问题(和子问题)所问的答案。 - BeeOnRope
顺便说一下,我之所以谷歌这个问题是因为我认为我链接错误了,但事实证明顺序是错误的。所以,这对我来说也是答案。 - Suchipi

7

您是否考虑通过使用-L参数指定库的路径来告诉GCC?如果仅使用-l参数,GCC只能链接标准目录中可用的库。

-L[path] -l[lib]

是的,在相应的 -l 标志之前,可以使用 -L 提供每个库的路径。GCC 可以找到库,但会在库内部产生大量未定义引用错误。 - Nairou

6
正确链接静态库的方法是使用-l,但前提是库能在搜索路径上找到。如果没有找到,您可以使用-L将目录添加到列表中或按名称命名文件,就像你所说的那样。
实际上,对于共享库来说也是一样的,尽管它们可能更容易被找到。

然而,使用-l链接静态库和将其放在链接行中没有任何-l前缀的.o之间有什么区别呢?请参阅原帖作者在问题末尾提出的问题。 - BeeOnRope
除了跳过搜索过程外,没有任何区别。 - ams

2
原因是历史原因。 "ar"工具最初是PDP11 unix上的文件存档工具,尽管后来完全被"tar"替代了。它将文件(在这种情况下是目标文件)存储在一个包中。还有一个单独的扩展名,其中包含链接器要使用的符号表。如果您手动管理存档中的文件,则可能会使符号表过时。
简短的答案是,您可以使用"ranlib"工具重新创建任何存档中的符号表。试试看。更广泛地说,请尝试找出损坏的库来自哪里,并修复它们。

2
我认为 OP 的意思是链接“对”一个库,而不是创建一个库。 - ams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接