简体   繁体   English

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

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


I am working in a big project. 我在一个大项目中工作。 And now encounter a link error. 现在遇到链接错误。
This error can be avoided by a workaround but I can not figure out why it works. 解决方法可以避免此错误,但我无法弄清楚它为何起作用。

Here is the file structure related to my problem: 这是与我的问题相关的文件结构:

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


All the *.o in package_a will be packed in to aa and *.o in package_b will be packed into ba package_a中的所有* .o将打包到aa中,package_b中的* .o将打包到ba中

"g++ -o exec -Bstatic ba aa ..." is used to generate the binary. "g++ -o exec -Bstatic ba aa ..."用于生成二进制文件。

In package_b/b.cpp, I added a function foo(). 在package_b / b.cpp中,我添加了一个函数foo()。
And in package_a/a.cpp, I used this function. 在package_a / a.cpp中,我使用了这个函数。

But here I will get a link error saying undefined reference of foo() in ao 但是在这里我会得到一个链接错误,说明在ao中未定义的foo()引用
I can verify (by objdump) that foo() is already in bo 我可以验证(通过objdump)foo()已经在bo中

By changing the link command into "g++ -o exec -Bstatic aa ba ..." , the binary can be built successfully. 通过将link命令更改为"g++ -o exec -Bstatic aa ba ..." ,可以成功构建二进制文件。 I now understand that the linker do care about the order in linkage list. 我现在明白链接器确实关心链接列表中的顺序 But please understand this is a big project I have no permission to change the project configuration so the original link order must be kept. 但请理解这是一个大项目,我无权更改项目配置,因此必须保留原始链接顺序。

Then I added a dummy function bar() in package_b/c.cpp, which do nothing but just calling foo(), then original "g++ -o exec -Bstatic ba aa ..." will run through without any link error. 然后我在package_b / c.cpp中添加了一个虚拟函数bar(),除了调用foo()之外什么都不做,然后原始的"g++ -o exec -Bstatic ba aa ..."会在没有任何链接错误的情况下运行。

Can anybody show me some light why just adding a dummy function in the same package will work in this case? 任何人都可以告诉我为什么在这种情况下在同一个包中添加一个虚拟函数会有效吗?

I'm using g++ 4.4.4 and linux 2.6.18-194.el5 我正在使用g ++ 4.4.4和linux 2.6.18-194.el5

Any comment will be appreciated 任何评论将不胜感激

This is normal. 这很正常。 When linking, the linker goes through the list of object files, finding undefined references which are then satisfied by other object files/libraries coming after it. 链接时,链接器经过对象的文件列表中,找到未定义的引用,然后由它的到来,其他目标文件/库纳。

You can change this behaviour by either 您可以通过以下方式更改此行为

  • including one of the archives twice, as in 包括其中一个档案两次,如

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

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

But please understand this is a big project I have no permission to change the project configuration so the original link order must be kept. 但请理解这是一个大项目,我无权更改项目配置,因此必须保留原始链接顺序。

Tough luck... Maybe the manager or whoever just doesn't want you to use functions in b from a . 运气好......也许经理或者只是不想让你使用b函数a

Then I added a dummy function bar() in package_b/c.cpp, which do nothing but just calling foo(), then original "g++ -o exec -Bstatic ba aa ..." will run through without any link error. 然后我在package_b / c.cpp中添加了一个虚拟函数bar(),除了调用foo()之外什么都不做,然后原始的“g ++ -o exec -Bstatic ba aa ...”会在没有任何链接错误的情况下运行。

Could be that another function of package_b/c.cpp was already referenced, and the linker took bar() with it (because they are in the same file) and this referenced foo() , which was subsequently included in the output, too. 可能是package_b/c.cpp另一个函数已被引用,并且链接器使用了bar() (因为它们在同一个文件中)并且这引用了foo() ,它随后也包含在输出中。 It succeeded, because foo was in ba too. 它成功了,因为foo也在ba

You may like to read up on how linkers work . 您可能希望了解链接器的工作原理 BTW, -Bstatic flag is unnecessary because .a. BTW, -Bstatic标志是不必要的,因为.a. object file archives link statically only (as if the list of object files contained in .a was specified on the command line instead of .a ). 目标文件仅以静态方式存档链接(就好像命令行中指定了.a中包含的目标文件列表而不是.a )。

Alternatively, you can always wrap a list of archives to link with --start-group / --end-group options to make the linker scan the list of archives multiple times, so that no ordering of archives is required (like MS VC++ does): 或者,您始终可以使用--start-group / --end-group选项包装存档列表,以使链接器多次扫描存档列表,这样就不需要对存档进行排序(如MS VC ++ ):

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

See man ld : 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.

GCC, unlike the Visual-C++-linker, requires static libraries to be supplied in an order so that references are defined before they are used. 与Visual-C ++链接器不同,GCC需要按顺序提供静态库,以便在使用之前定义引用。 Don't ask me why, but you will always have to check that you are listing the files to be linked in the correct order with GCC. 不要问我为什么,但是你总是要检查你是否正确列出了与GCC正确连接的文件。

There is an in-depth explanation here . 有一个深入的解释在这里

When you are using a function from a static library, you must on the command line first place the file from which the function is used, then the library where the function is defined. 当您使用静态库中的函数时,必须首先在命令行上放置使用该函数的文件,然后是定义函数的库。 Otherwise, if you place the definition first, gcc (or more specifically, ld) discards the "unused" function. 否则,如果首先放置定义,gcc(或更具体地说,ld)将丢弃“未使用”函数。 That's how gcc works, sorry. 这就是gcc的工作原理,抱歉。

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

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