C++动态链接库总结
编译时查找动态链接库的顺序
编译时会在以下路径查找:
通过编译选项-L 指定的目录
通过链接选项–rpath=指定的目录
通过环境变量LIBRARY_PATH
指定的目录(:
分割)
通过环境变量LD_LIBRARY_PATH
指定的目录(:
分割)
/lib
/usr/lib
/etc/ld.so.cache
中缓存的路径,通过/etc/ld.so.conf
指定,通过ldconfig
命令更新缓存。
至于查找的顺序其实不重要,因为只要找到符号通过链接就可以了,而运行时又会按照运行时查找的顺序进行查找,甚至运行时都不在相同环境,链接到的动态库也可能和编译时不是同一个。
指定编译时的动态链接库路径
通过gcc/g++
的-L
编译选项
通过-Wl,--rpath=
传递链接选项
设置LIBRARY_PATH
或LD_LIBRARY_PATH
环境变量
在CMakeLists.txt
中使用link_directories(${LIB_DIRS})
来指定,LIB_DIRS是用一个或多个空白字符分割的多个路径
在CMakeLists.txt
中使用指定rpath,方式如下
1 | target_link_libraries(${PROJECT_NAME} |
其中'$ORIGIN'
是一个特殊的路径,实际上这里是在提前指定运行时的查找路径,'$ORIGIN'
表示可执行文件所在目录,另外要注意的是如果指定多个rpath这里不能通过:
分割,而是使用多次-rpath选项.
BTW: 我并不清楚为什么要使用'$ORIGIN'
而不是.
,因为我测试下来效果是一样的。
运行时查找动态链接库的顺序
通过rpath连接选项指定的目录
通过环境变量LD_RUN_PATH
指定的目录(:
分割)
通过环境变量LD_LIBRARY_PATH
指定的目录(:
分割)
编译时实际的链接路径(不是查找过的路径,而是找到了这个so的路径)
/lib
/usr/lib
另外可以通过ldd <可执行程序>
来查看运行将使用链接库,也可以看到缺少的库。
还可以通过chrpath -l <可执行程序>
查看程序被设置的rpath。
指定运行时的动态链接库路径
设置环境变量LD_RUN_PATH
(:
分割)
设置环境变量LD_LIBRARY_PATH
(:
分割)
还可以通过chrpath -r <库路径> <可执行程序>
修改程序的rpath,但实际上rpath被写在可执行文件中并没有为修改它预留空间,所以只能修改成相同长度或更短的路径,所以显然这不是一个常规操作。
另外rpath只影响这个可执行程序本身而不能传递给其加载的so,如果我从程序a加载了动态库b,而动态b需要加载动态库c,即使我把b、c放在相同路径,a通过rpath的方式找到了b,而b还是找不到c,因为b的rpath里并没有这个路径。
所以总得来说最靠谱的方式还是指定LD_LIBRARY_PATH
,在linux上可以通过下面的方式在启动程序同时设置环境变量
1 | LD_LIBRARY_PATH=<动态库目录>:$LD_LIBRARY_PATH <可执行文件> |
设置LD_LIBRARY_PATH同时保留了之前的值放在后面,这样设置的环境变量只影响可执行文件启动的程序,包括间接加载的动态链接库,