Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
540 views
in Technique[技术] by (71.8m points)

linker - Does the order in which libraries appear on the gcc command line matter?

I always thought that libraries had to be listed after any object files that depended on them, but given this simple program:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

int main(int argc, char **argv) {
    double res;

    res = acos(2);
    printf("res = %f
", res);
    return 0;
}

If I build it without linking in libm, it fails as expected:

$ gcc -o mathtest mathtest.c 
/tmp/cc9x6HZA.o: In function `main':
mathtest.c:(.text+0x23): undefined reference to `acos'
collect2: error: ld returned 1 exit status

But I can list -lm either before or after the source file and it links successfully:

gcc -o mathtest -lm mathtest.c
gcc -o mathtest mathtest.c -lm

And I get the same behavior if I compile the source to an object file first and then link it as above.

Did this behavior change at some point? Or was it always like this, and I was just confused?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I confirm the unexpected link-order behaviour that you observe with gcc 5.1 and also that I have the traditional behaviour with gcc 4.9.2. I would infer that this novelty comes in with gcc 5.x, and that your toolchain is gcc 5.x. Possibly it is a distro-specific anomaly of the toolchain build. My toolchain is as per ubuntu 14.04.

The novel behaviour only affects dynamic libraries. I can see what is causing it if I link in verbose mode (-v) with gcc 4.9.2 and also with gcc 5.1, placing -lm before it is needed, and examine the differences in the verbose output.

From gcc 4.9.2 I have (with artifical line-wrapping):

/usr/lib/gcc/x86_64-linux-gnu/4.9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/4.9/liblto_plugin.so 
-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccsHNLNB.res 
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc 
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --sysroot=/ --build-id 
--eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker 
/lib64/ld-linux-x86-64.so.2 -z relro -o mathtest 
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crt1.o 
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crti.o 
/usr/lib/gcc/x86_64-linux-gnu/4.9/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.9 
-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu
-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../../lib -L/lib/x86_64-linux-gnu 
-L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib 
-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../.. -lm mathtest.o -lgcc --as-needed 
-lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed 
/usr/lib/gcc/x86_64-linux-gnu/4.9/crtend.o 
/usr/lib/gcc/x86_64-linux-gnu/4.9/../../../x86_64-linux-gnu/crtn.o

And from gcc 5.1 I have:

/usr/lib/gcc/x86_64-linux-gnu/5/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/5/liblto_plugin.so 
-plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper -plugin-opt=-fresolution=/tmp/cc5hI8vd.res 
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc 
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --sysroot=/ --build-id 
--eh-frame-hdr -m elf_x86_64 --hash-style=gnu -dynamic-linker 
/lib64/ld-linux-x86-64.so.2 -z relro -o mathtest 
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o 
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crti.o 
/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/5 
-L/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu 
-L/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib -L/lib/x86_64-linux-gnu 
-L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib 
-L/usr/lib/gcc/x86_64-linux-gnu/5/../../.. -lm mathtest.o -lgcc --as-needed 
-lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed 
/usr/lib/gcc/x86_64-linux-gnu/5/crtend.o 
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crtn.o

The relevant difference is that the gcc 4.9.2 linkage passes the option --as-needed in 4 places whereas the gcc 5.1 linkage passes it in only 3. gcc 4.9.2 passes --as-needed for the first time at the the 5th quoted "line":

--eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker

gcc 5.1 does not pass it there. Thereafter, both linkages pass this option at the same 3 places, starting as the 13th "line":

-L/usr/lib/gcc/x86_64-linux-gnu/4.9/../../.. -lm mathtest.o -lgcc --as-needed

This means that for gcc 4.9.2, the library option -lm on "line" 13 falls within the scope of the first --as-needed. For gcc 5.1 it does not. The effect of this option is to inform the linker that the dynamic library libm (or any dynamic library that is encountered in the option's scope) shall be linked only if it is encountered at a point in the linkage at which it can satisfy some unresolved symbols. In the absence of this option, at a given point in the linkage, a dynamic library is by default deemed to be needed for the linkage regardless of whether there are yet any unresolved symbols that it can satisfy. See the documentation of --as-needed

Thus the gcc 4.9.2 linkage will not link libm, although it appears on the commandline, because at the point where it appears - before mathtest.o - --as-needed is in force and there are as yet no unresolved references that libm satisfies. The gcc 5.1 linkage will link libm because it appears on the commandline at a point where --as-needed is not in force.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...