简体   繁体   中英

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

is used to generate the binary. 用于生成二进制文件。

In package_b/b.cpp, I added a function foo().
And in package_a/a.cpp, I used this function.

But here I will get a link error saying undefined reference of foo() in ao
I can verify (by objdump) that foo() is already in bo

By changing the link command into , the binary can be built successfully. ,可以成功构建二进制文件。 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 will run through without any link error. 会在没有任何链接错误的情况下运行。

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

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 .

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.

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. It succeeded, because foo was in ba too.

You may like to read up on how linkers work . BTW, -Bstatic flag is unnecessary because .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 ).

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):

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

See 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. 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.

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. That's how gcc works, sorry.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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