环境介绍 :
目标机上安装了两个版本gcc:gcc 3.36,gcc 4.41。makefile 使用gcc 3.36编译的。
Makefile链接部分:
FLAGS_LIB_PATH=-L../lib
FLAGS_LIB=-ldl -lxml++-2.6 -lcurl -lstdc++ ../lib/libstdc++.so.6
...
$(DIR_OUT)/$(FILE_OUT):$(OBJS_CPP) $(OBJS_CC)
$(LINK.cc) $(FLAGS_LINK) -o $@ $(addprefix $(DIR_OBJ)/,$(notdir $^)) $(FLAGS_LIB_PATH) $(FLAGS_LIB)
$(INSTALL_COMMAND)
问题:
项目依赖的libxml++2.6.so 依赖的GCC4.2.0 libstdc++.so.6, 这个库事先已经放在../lib 目录下了,但是/usr/lib目录下也有一个libstdc++.so.6库,这个是gcc 4.41安装的。
编译时出现:
linux-83nz:/home/projects/study/TestCURL # make
/opt/gcc-3.3.6/bin/g++ -o /home/projects/study/TestCURL/bin/testcurl /home/projects/study/TestCURL/bin/main.o /home/projects/study/TestCURL/bin/mycurl.o /home/projects/study/TestCURL/bin/myparser.o -L../lib -ldl -lxml++-2.6 -lcurl -lstdc++
/usr/bin/ld: warning: libstdc++.so.6, needed by ../lib/libxml++-2.6.so, may conflict with libstdc++.so.5
/usr/bin/ld: warning: libstdc++.so.6, needed by ../lib/libxml++-2.6.so, may conflict with libstdc++.so.5
/usr/lib/libstdc++.so.6: undefined reference to `_Unwind_GetIPInfo@GCC_4.2.0'
collect2: ld returned 1 exit status
make: *** [/home/projects/study/TestCURL/bin/testcurl] 错误 1
原因分析:
libxml++2.6.so依赖的库libstdc++.so.6会自动按照共享库搜索方式,搜索到该gcc 4.41下的,因此会提示链接错误。
解决方案:
1.使用LD_LIBRARY_PATH解决:
将搜索路径明确指定到../lib下,编译通过,如下:
linux-83nz:/home/projects/study/TestCURL # export LD_LIBRARY_PATH=../lib
linux-83nz:/home/projects/study/TestCURL # make
/opt/gcc-3.3.6/bin/g++ -o /home/projects/study/TestCURL/bin/testcurl /home/projects/study/TestCURL/bin/main.o /home/projects/study/TestCURL/bin/mycurl.o /home/projects/study/TestCURL/bin/myparser.o -L../lib -ldl -lxml++-2.6 -lcurl -lstdc++
/usr/bin/ld: warning: libstdc++.so.6, needed by ../lib/libxml++-2.6.so, may conflict with libstdc++.so.5
/usr/bin/ld: warning: libstdc++.so.6, needed by ../lib/libxml++-2.6.so, may conflict with libstdc++.so.5
2.修改Makefile解决:
修改Makefile链接选项FLAGS_LIB ,明确加上../lib/libstdc++.so.6,使之在指定目录下查找,编译通过。
FLAGS_LIB=-ldl -lxml++-2.6 -lcurl -lstdc++ ../lib/libstdc++.so.6
结论:
GCC -l 没有指定的库是通过执行时搜索路径来找的
附录:
1. 查询当前共享库版本:
objdump -p /usr/lib/libstdc++.so.6 | grep SONAME
2. Shared libraries
Shared library 会在程序执行起始时才被自动加载。因为链接库与执行档是分离的,所以维护弹性较好。有两点要注意, shared library 是在程序起始时就要被加载,而不是执行中用到才加载,而且在连结阶段需要有该链接库才能进行连结。
首先有一些名词要弄懂, soname 、 real name 与 linker name 。
soname 用来表示是一个特定 library 的名称,像是 libmylib.so.1 。前面以 `lib' 开头,接着是该 library 的名称,然后是 `.so' ,接着
是版号,用来表名他的界面;如果接口改变时,就会增加版号来维护兼容度。
real name 是实际放有 library 程序的文件名,后面会再加上 minor 版号与
release 版号,像是 libmylib.so.1.0.0 。
一般来说,版号的改变规则是 ( 印象中在 APress-Difinitive Guide to GCC 中有提到,但目前手边没这本书 ) ,最后缀的 release 版号用于程序内容的修正,接口完全没有改变。中间的 minor 用于有新增加接口,但相旧接口没改变,所以与旧版本兼容。最前面的 version 版号用于原接口有移除或改变,与旧版不兼容时。
linker name 是用于连结时的名称,是不含版号的 soname ,如 : libmylib.so 。
通常 linker name 与 real name 是用 ln 指到对应的 real name ,用来提供弹性与维护性。