繁体   English   中英

g ++链接错误 - 解决方法的工作原理

[英]A g++ link error - why the workaround works


我在一个大项目中工作。 现在遇到链接错误。
解决方法可以避免此错误,但我无法弄清楚它为何起作用。

这是与我的问题相关的文件结构:

project
  |-package_a
    |--a.cpp
    |--...
  |-package_b
    |--b.cpp
    |--c.cpp
    |--...
  |-package_others


package_a中的所有* .o将打包到aa中,package_b中的* .o将打包到ba中

"g++ -o exec -Bstatic ba aa ..."用于生成二进制文件。

在package_b / b.cpp中,我添加了一个函数foo()。
在package_a / a.cpp中,我使用了这个函数。

但是在这里我会得到一个链接错误,说明在ao中未定义的foo()引用
我可以验证(通过objdump)foo()已经在bo中

通过将link命令更改为"g++ -o exec -Bstatic aa ba ..." ,可以成功构建二进制文件。 我现在明白链接器确实关心链接列表中的顺序 但请理解这是一个大项目,我无权更改项目配置,因此必须保留原始链接顺序。

然后我在package_b / c.cpp中添加了一个虚拟函数bar(),除了调用foo()之外什么都不做,然后原始的"g++ -o exec -Bstatic ba aa ..."会在没有任何链接错误的情况下运行。

任何人都可以告诉我为什么在这种情况下在同一个包中添加一个虚拟函数会有效吗?

我正在使用g ++ 4.4.4和linux 2.6.18-194.el5

任何评论将不胜感激

这很正常。 链接时,链接器经过对象的文件列表中,找到未定义的引用,然后由它的到来,其他目标文件/库纳。

您可以通过以下方式更改此行为

  • 包括其中一个档案两次,如

     g++ -o exec aa ba aa 
  • 使用-(构造

     g++ -o exec -( aa ba -) 

但请理解这是一个大项目,我无权更改项目配置,因此必须保留原始链接顺序。

运气好......也许经理或者只是不想让你使用b函数a

然后我在package_b / c.cpp中添加了一个虚拟函数bar(),除了调用foo()之外什么都不做,然后原始的“g ++ -o exec -Bstatic ba aa ...”会在没有任何链接错误的情况下运行。

可能是package_b/c.cpp另一个函数已被引用,并且链接器使用了bar() (因为它们在同一个文件中)并且这引用了foo() ,它随后也包含在输出中。 它成功了,因为foo也在ba

您可能希望了解链接器的工作原理 BTW, -Bstatic标志是不必要的,因为.a. 目标文件仅以静态方式存档链接(就好像命令行中指定了.a中包含的目标文件列表而不是.a )。

或者,您始终可以使用--start-group / --end-group选项包装存档列表,以使链接器多次扫描存档列表,这样就不需要对存档进行排序(如MS VC ++ ):

g++ -o exec -Wl,--start-group a.a b.a -Wl,--end-group

man ld

   -( archives -)
   --start-group archives --end-group
       The archives should be a list of archive files.  They may be either
       explicit file names, or -l options.

       The specified archives are searched repeatedly until no new
       undefined references are created.  Normally, an archive is searched
       only once in the order that it is specified on the command line.
       If a symbol in that archive is needed to resolve an undefined
       symbol referred to by an object in an archive that appears later on
       the command line, the linker would not be able to resolve that
       reference.  By grouping the archives, they all be searched
       repeatedly until all possible references are resolved.

       Using this option has a significant performance cost.  It is best
       to use it only when there are unavoidable circular references
       between two or more archives.

与Visual-C ++链接器不同,GCC需要按顺序提供静态库,以便在使用之前定义引用。 不要问我为什么,但是你总是要检查你是否正确列出了与GCC正确连接的文件。

有一个深入的解释在这里

当您使用静态库中的函数时,必须首先在命令行上放置使用该函数的文件,然后是定义函数的库。 否则,如果首先放置定义,gcc(或更具体地说,ld)将丢弃“未使用”函数。 这就是gcc的工作原理,抱歉。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM