gcc 链接库的顺序问题

来源:互联网 发布:用户画像 数据挖掘 编辑:程序博客网 时间:2024/05/18 18:19


今天碰到一个gcc链接数学库函数找不到的问题。解决办法 -lm放在最后 。


 GCC在链接过程中,对参数中的库的顺序是有要求的,参数右侧的库会先于左侧的库加载,也就是说参数的解析是从右往左的。

    假设库B依赖与库A,则链接的时候要写为:
       gcc -o bin -lB -lA
   如果写为:
       gcc -o bin -lA -lB
   则在B中引用的A中的内容就会无法链接通过。

如果多个库中对某些符号的定义相同,链接时谁先谁后可能都可以链接通过,但是运行时会产生不同的效果,需要特别注意,消除这些相同的符号定义。


将多个.o文件链接成可执行文件的时候。如果链接的顺序不对,会产生错误。
《An introduction of gcc》里面有下面一段话:
On Unix-like systems, the traditional behavior of compilers and linkers
is to search for external functions from left to right in the object files
specified on the command line. This means that the object file which
contains the definition of a function should appear after any files which
call that function.

但是也说了:
Most current compilers and linkers will search all object files, regardless
of order, but since not all compilers do this it is best to follow the
convention of ordering object files from left to right.

链接库的时候,也存在这个问题。
今天写程序做了一下试验,发现gcc和我现在用的一个板子的编译器都可以不用严格按照顺序。
但是同时发现了另一个问题,就是我们自己的操作系统提供的库文件有两个:libgcc.a和libcs.a。
链接的时候要加上 -lcs -lgcc ,如果这两个顺序搞乱了,就会报错。

xscale-elf-ld -L../../lib -o main test1.o test2.o main.o \
-lgcc \
-lcs
xscale-elf-ld: warning: cannot find entry symbol _start; defaulting to 00008000
../../lib/libcs.a(_uprint.o): In function `outnum':
_uprint.o(.text+0x1ac): undefined reference to `__modsi3'
_uprint.o(.text+0x1c8): undefined reference to `__divsi3'
../../lib/libcs.a(_uprint.o): In function `outnum_u':
_uprint.o(.text+0x2e0): undefined reference to `__umodsi3'
_uprint.o(.text+0x2f4): undefined reference to `__udivsi3'
../../lib/libcs.a(fvwrite.o): In function `__sfvwrite':
fvwrite.o(.text+0x270): undefined reference to `__udivsi3'
make.exe: *** [main] Error 1

为什么编译器在搜索目标文件的时候可以不看顺序,搜索库文件的时候却会报错呢?

下面是hh的解答:

不依命令行的顺序的话就得重复扫描目标文件,我猜可能是重复扫描库文件的开销比较大所以必须在命令行指定正确的顺序。有空也可读读此书:


今天在编译的时候遇到一个gcc编译链接库顺序的问题,描述如下: 

$ gcc elements.c -o par -L/usr/lib -lparsifal

编译通过,但是如下编译时出错 

$ gcc -L/usr/lib -lparsifal elements.c -o par 
/tmp/ccO82iYg.o: In function `main': 
elements.c:(.text+0xcb): undefined reference to `XMLParser_Create' 
elements.c:(.text+0x143): undefined reference to `XMLParser_Parse' 
elements.c:(.text+0x187): undefined reference to `XMLParser_Free' 
collect2: ld 返回 1 


两者不同指出就是链接库指定的顺序不同。 

查了相关资料总结: 
gcc -l 解释如下: 
       -l library 
           Search the library named library when linking.  (The second alter- 
           native with the library as a separate argument is only for POSIX 
           compliance and is not recommended.) 

           It makes a difference where in the command you write this option; 
           the linker searches and processes libraries and object files in the 
           order they are specified.  Thus, foo.o -lz bar.o searches library z 
           after file foo.o but before bar.o.  If bar.o refers to functions in 
           z, those functions may not be loaded. 

看看gcc的帮助,有下面的选项 
-Xlinker option 
           Pass option as an option to the linker.   You can use this to supply 
           system-specific linker options which GCC does not know how to rec- 
           ognize. 

           If you want to pass an option that takes an argument, you must use 
           -Xlinker twice, once for the option and once for the argument.  For 
           example, to pass -assert definitions, you must write -Xlinker 
           -assert -Xlinker definitions.  It does not work to write -Xlinker 
           "-assert definitions", because this passes the entire string as a 
           single argument, which is not what the linker expects. 

也就是说,-Xlinker是将连接选项传给连接器的,赶快看看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  unde- 
           fined  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 sym- 
           bol referred to by an object in an archive that  appears  later  on 
           the command line, the linker would not be able to resolve that ref- 
           erence.  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 -o output.bin -Xlinker "-(" la  lb -Xlinker "-)" -lrt 

上面的方法是解决了,库之间相互依赖的问题,但是没有解决我一开始发现的问题,

只能暂时总结为:

gcc 链接时优先选择从后面给出的库中找符号。 

所以编译时应将链接库的指定放在后面。

1.6 对链接顺序导致问题的解决方案

1.6.1 在项目开发过层中尽量让lib是垂直关系,避免循环依赖;越是底层的库,越是往后面写!

例如:

g++ ...  obj($?) -l(上层逻辑lib) -l(中间封装lib) -l(基础lib) -l(系统lib)  -o $@

这样写可以避免很多问题,这个是在搭建项目的构建环境的过程中需要考虑 清楚地,在编译和链接上浪费太多的生命不值得!


原创粉丝点击