参考了不少资料,其中最靠谱是这个:http://www.mingw.org/wiki/librarypathhowto
和http://www.kaizou.org/2015/01/linux-libraries/
经过线上实际验证,GCC编译、链接、运行时库查找顺序如下,这个顺序真实可信,网上很多说法有些地方都是有些问题的,
导致遇到问题时总是不确定到底是哪里出了问题,花了不少时间,绝知此事要躬行。
略微让人头疼的是,没有找到官方文档清晰说明什么情况下该如何查找依赖库目录,链接时查找直接依赖库和间接依赖库的方式
差别挺大。。。
一、概括GCC链接时搜索直接依赖库的先后顺序:
1、LDFLAGS选项 -L 参数指定的路径。
2、系统环境变量 LIBRARY_PATH(某些系统或编译器下可能无效)。
3、gcc安装时自身配置的搜索路径,gcc --print-search-dir | grep libraries 可查看,
一般会包含该版本gcc必需的库而不一定包含当前系统库路径,链接时会以-L参数形式传递给ld。
4、ld安装时自身配置的搜索路径,ld -verbose | grep SEARCH_DIR 可查看,
gcc通过调用collect2工具调用ld。
To summarize, when linking an executable against a static library, you need to specify explicitly all dependencies towards shared libraries introduced by the static library on the link command.
二、概括GCC链接时搜索间接依赖库(直接依赖库的依赖库)的先后顺序:(即secondary dependencies)
特别说明:搜索直接依赖库的链接查找顺序同样适用于编译生成动态的( shared)、可重定位(relocatable)目标的情形。
-rpath-link=dir
When using ELF or SunOS, one shared library may require another. This happens when an "ld -shared" link includes a shared library as one of the input files.
When the linker encounters such a dependency when doing a non-shared, non-relocatable link, it will automatically try to locate the required shared library and include it in the link, if it is not included explicitly. In such a case, the -rpath-link option specifies the first set of directories to search. The -rpath-link option may specify a sequence of directory names either by specifying a list of names separated by colons, or by appearing multiple times.
This option should be used with caution as it overrides the search path that may have been hard compiled into a shared library. In such a case it is possible to use unintentionally a different search path than the runtime linker would do.
The linker uses the following search paths to locate required shared libraries:
(1) Any directories specified by -rpath-link options.(2) Any directories specified by -rpath options. The difference between -rpath and -rpath-link is that directories specified by -rpath options are included in the executable and used at runtime, whereas the -rpath-link option is only effective at link time. Searching -rpath in this way is only supported by native linkers and cross linkers which have been configured with the --with-sysroot option.
(3) On an ELF system, for native linkers, if the -rpath and -rpath-link options were not used, search the contents of the environment variable "LD_RUN_PATH".
(4) On SunOS, if the -rpath option was not used, search any directories specified using -L options.
(5) For a native linker, the search the contents of the environment variable "LD_LIBRARY_PATH".
(6) For a native ELF linker, the directories in "DT_RUNPATH" or "DT_RPATH" of a shared library are searched for shared libraries needed by it. The "DT_RPATH" entries are ignored if "DT_RUNPATH"entries exist.
(7) The default directories, normally /lib and /usr/lib.(这里应该是指 ld -verbose | grep SEARCH_DIR显示的搜索目录)
(8) For a native linker on an ELF system, if the file /etc/ld.so.conf exists, the list of directories found in that file.
If the required shared library is not found, the linker will issue a warning and continue with the link.
“Ok, this is not crystal-clear, but what it actually means is that when specifying the path for a secondary dependency, you should not use -L but -rpath-link
To summarize, when linking an executable against:
a static library, you need to specify all dependencies towards other shared libraries this static library depends on explicitly on the link command.
a shared library, you don’t need to specify dependencies towards other shared libraries this shared library depends on, but you may need to specify the path to these libraries on the link command using the
-rpath/-rpath-linkoptions.
Note however that expressing, discovering and adding implicit libraries dependencies is typically a feature of your build system (autotools, cmake), as demonstrated in my samples.”
1、程序自身的RPATH(Library rpath), readelf -d bin可查看,在链接时通过-rpath参数写入程序ELF结构信息中,
2、编译时LDFLAGS选项 -L 参数指定的路径。
3、系统环境变量LD_LIBRARY_PATH。
4、在 /etc/ld.so.conf.d/ 目录下的配置文件指定的动态库绝对路径(通过ldconfig生效,一般是非root用户时使用)。
5、gcc安装时自身配置的搜索路径,gcc --print-search-dir | grep libraries 可查看,一般会包含该版本gcc必需的库
1、在链接和运行查找库的过程中,只要找到同名的库则不管该库是否兼容均停止查找,
2、安装高版本gcc时一般是直接解压已经编译好的gcc,然后直接复制一份至新的路径下,
3、如果系统自带的是低版本gcc,而需要使用高版本gcc编译程序,如果该程序依赖了非系统库(低版本gcc编译),
- You can pass the
-voption togccso that it shows you how it invokes the linker. In fact, it normally does not invokelddirectly, but indirectly via a tool calledcollect2(which lives in one of its internal directories), which in turn invokesld. That will show you what-Loptions are being used.
- You can add
-Wl,--verboseto thegccoptions to make it pass--verbosethrough to the linker, to see the linker script as described above.
四、库版本号
如果 major version number不一致,说明库的ABI接口是不兼容的,不同major version 库之间不能相互引用或依赖,相同major version一般是可以相互引用和依赖的,但工作时具体行为是否正确需要进一步验证。
Linux上的shared library有三个名字,分别是:
共享库本身的文件名(real name)
其通常包含完整的版本号,比如:libmath.so.1.1.1234 。lib是Linux库的约定前缀,math是共享库名字,so是共享库的后缀名,1.1.1234的是共享库的版本号,由
主版本号+小版本号+build号组成。主版本号,代表当前动态库的版本,如果共享库的接口发生变化,那么这个版本号就要加1;后面的两个版本号(小版本号和build号)是用来指示库的更新迭代号,表示在接口没有改变的情况下,由于需求发生变化等因素,开发的新代码。共享库的soname(Short for shared object name)
用来告诉应用程序,在加载共享库的时候,应该使用的文件名。其格式为
lib + math + .so + (major version number)其只包含主版本号,换句话说,也就是只要共享库的接口没有变,soname就能与real name保持一致,因为主版本号一样。所以在库的real name的小版本号和build号发生改变时,应用程序仍然可以通过soname得知,要使用的是哪个real name。共享库的链接名(link name)
是专门为应用程序在编译时的链接阶段而用的名字。这个名字就是lib + math +.so ,比如libmath.so。其是不带任何版本信息的。在共享库的编译过程中,编译器将生成一个共享库及real name,同时将共享库的soname写在共享库文件里的文件头里面。可以用命令
readelf -d sharelibrary | grep soname查看。 在应用程序引用共享库时,链接选项里面用的是共享库的link name。通过link名字找到对应的real name动态库,并且把其中的soname提取出来,写在应用程序自己的文件头的共享库字段里面。当应用程序运行时,就会通过soname,结合动态链接程序(ld.so),在给定的路径下加载real name的共享库。
以上。
本文详细介绍了GCC在编译、链接及运行时查找库的顺序,包括直接依赖库和间接依赖库的搜索路径。内容涵盖-L选项、LIBRARY_PATH环境变量、gcc和ld的配置路径、-rpath-link等。还提到了库版本号的重要性,以及如何通过各种选项和工具来查看链接过程。
567

被折叠的 条评论
为什么被折叠?



