今天碰到一个gcc链接数学库函数找不到的问题。解决办法 -lm放在最后 。
GCC在链接过程中,对参数中的库的顺序是有要求的,参数右侧的库会先于左侧的库加载,也就是说参数的解析是从右往左的。
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和我现在用的一个板子的编译器都可以不用严格按照顺序。
但是同时发现了另一个问题,就是我们自己的操作系统提供的库文件有两个:和。
链接的时候要加上 -lcs -lgcc ,如果这两个顺序搞乱了,就会报错。
xscale-elf-ld -L../../lib -o main \
-lgcc \
-lcs
xscale-elf-ld: warning: cannot find entry symbol _start; defaulting to 00008000
../../lib/(_uprint.o): In function `outnum':
_uprint.o(.text+0x1ac): undefined reference to `__modsi3'
_uprint.o(.text+0x1c8): undefined reference to `__divsi3'
../../lib/(_uprint.o): In function `outnum_u':
_uprint.o(.text+0x2e0): undefined reference to `__umodsi3'
_uprint.o(.text+0x2f4): undefined reference to `__udivsi3'
../../lib/(): In function `__sfvwrite':
(.text+0x270): undefined reference to `__udivsi3'
: *** [main] Error 1
为什么编译器在搜索目标文件的时候可以不看顺序,搜索库文件的时候却会报错呢?
下面是hh的解答:
不依命令行的顺序的话就得重复扫描目标文件,我猜可能是重复扫描库文件的开销比较大所以必须在命令行指定正确的顺序。有空也可读读此书:
今天在编译的时候遇到一个gcc编译链接库顺序的问题,描述如下:
$ gcc -o par -L/usr/lib -lparsifal
编译通过,但是如下编译时出错
/tmp/: In function `main':
:(.text+0xcb): undefined reference to `XMLParser_Create'
:(.text+0x143): undefined reference to `XMLParser_Parse'
:(.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, -lz searches library z
after file but before . If 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 -Xlinker "-(" la lb -Xlinker "-)" -lrt
上面的方法是解决了,库之间相互依赖的问题,但是没有解决我一开始发现的问题,
只能暂时总结为:
gcc 链接时优先选择从后面给出的库中找符号。
所以编译时应将链接库的指定放在后面。
1.6 对链接顺序导致问题的解决方案
1.6.1 在项目开发过层中尽量让lib是垂直关系,避免循环依赖;越是底层的库,越是往后面写!
例如:
g++ ... obj($?) -l(上层逻辑lib) -l(中间封装lib) -l(基础lib) -l(系统lib) -o $@
这样写可以避免很多问题,这个是在搭建项目的构建环境的过程中需要考虑 清楚地,在编译和链接上浪费太多的生命不值得!