linux环境变量LIBRARY_PATH和LD_LIBRARY_PATH
文章目录1.LIBRARY_PATH和LD_LIBRARY_PATH区别1.1.两个环境变量的不同1.2.使用场景2.配合CMake实验测试2.0.文件结构2.1.测试1:LIBRARY_PATH包含库目录,LD_LIBRARY_PATH不包含2.2.测试2:LIBRARY_PATH不包含库目录,LD_LIBRARY_PATH包含库目录2.3.测试3:LIBRARY_PATH包含库目录,LD_LI
文章目录
- 1.LIBRARY_PATH和LD_LIBRARY_PATH区别
- 2.配合CMake实验测试
- 3.总结
- 4.问题
1.LIBRARY_PATH和LD_LIBRARY_PATH区别
参考:
LIBRARY_PATH和LD_LIBRARY_PATH的区别
LINUX中PATH,LIBRARY_PATH,LD_LIBRARY_PATH等环境变量的含义
LD_LIBRARY_PATH vs LIBRARY_PATH
1.1.两个环境变量的不同
gcc在编译链接时链接的动态库跟LIBRARY_PATH
有关而跟LD_LIBRARY_PATH
没关系!
LIBRARY_PATH
和LD_LIBRARY_PATH
是Linux下的两个环境变量,二者的含义和作用分别如下:
LIBRARY_PATH
环境变量用于在程序编译期间查找动态链接库时指定查找共享库的路径,例如,指定gcc编译需要用到的动态链接库的目录。设置方法如下(其中,LIBDIR1
和LIBDIR2
为两个库目录):
export LIBRARY_PATH=LIBDIR1:LIBDIR2:$LIBRARY_PATH
LD_LIBRARY_PATH
环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径。注意,LD_LIBRARY_PATH中
指定的路径会在系统默认路径之前进行查找。设置方法如下(其中,LIBDIR1
和LIBDIR2
为两个库目录):
export LD_LIBRARY_PATH=LIBDIR1:LIBDIR2:$LD_LIBRARY_PATH
1.2.使用场景
举个例子,我们开发一个程序,经常会需要使用某个或某些动态链接库,为了保证程序的可移植性,可以先将这些编译好的动态链接库放在自己指定的目录下,然后按照上述方式将这些目录加入到LD_LIBRARY_PATH
环境变量中,这样自己的程序就可以动态链接后加载库文件运行了。
区别与使用:
-
开发时(编译程序的时候):设置
LIBRARY_PATH
,以便gcc能够找到编译时需要的动态链接库,这样可以顺利通过编译链接生成可执行文件。但是注意:如果这个时候这个库不在LD_LIBRARY_PATH
目录里,或者不在系统默认的动态库链接目录里,那么程序仍然是不能运行的,因为它运行到时候找不到链接的库,就无法链接这个库。 -
发布时(程序编译完成,需要运行):设置
LD_LIBRARY_PATH
,以便程序加载运行时能够自动找到需要的动态链接库。
2.配合CMake实验测试
2.0.文件结构
在文件夹~/test
下的目录结构:
2.1.测试1:LIBRARY_PATH包含库目录,LD_LIBRARY_PATH不包含
- 首先在
~/.zshrc
中加入环境变量:export LIBRARY_PATH=~/test/Lib:$LIBRARY_PATH
。然后重新打开一个窗口,输入printenv | grep LIBRARY
查看一下是否加入了环境变量 - 编写
CMakeLists.txt
文件如下
cmake_minimum_required(VERSION 3.0)
project(main)
add_executable(main main.cpp)
target_link_libraries(main libmyLog.so )
- cmake … , make测试结果:可以正常编译链接得到可执行文件,但是运行时报错
error while loading shared libraries: libmyLog.so: cannot open shared object file: No such file or directory
。
以上测试说明,LIBRARY_PATH
包含库目录但LD_LIBRARY_PATH
不包含的情况,可以正常编译链接到库,但是运行的时候链接不到库。
2.2.测试2:LIBRARY_PATH不包含库目录,LD_LIBRARY_PATH包含库目录
测试步骤仍然同上,注意编译之前重开窗口,然后printenv | grep LIBRARY
查看一下是否真正满足 “LIBRARY_PATH
不包含库目录但LD_LIBRARY_PATH
包含库目录” 的要求。
测试结果是编译链接的时候就失败,报错/usr/bin/ld: 找不到 -lmyLog
,也就是编译的时候就找不到库目录。
2.3.测试3:LIBRARY_PATH包含库目录,LD_LIBRARY_PATH包含库目录
测试步骤仍然同上,注意编译之前重开窗口,然后printenv | grep LIBRARY
查看一下是否真正满足 “LIBRARY_PATH
包含库目录且LD_LIBRARY_PATH
也包含库目录” 的要求。
测试结果是编译链接通过,程序也可以正常运行。
2.4.测试4:和LD_LIBRARY_PATH同等作用的/etc/ld.so.conf
2.4.1./etc/ld.so.conf详解
/etc/ld.so.conf
和LD_LIBRARY_PATH
具有同等的作用,都是负责存储程序运行时链接的动态库目录,而不是程序编译时链接的动态库目录。他们不同的地方在于前者是系统目录下的,属于默认路径(超级用户也可以更改);而后者是环境变量,用户可以在其中增加路径。因此程序运行时链接库的时候,优先链接后者,即环境变量LD_LIBRARY_PATH
目录下的库。如果不能满足一些共享库相关性要求,则转回到 /etc/ld.so.conf
中指定的库。
首先查看/etc/ld.so*
相关的文件如下图所示。
-
ld.so.conf
文件和ld.so.conf.d
文件夹下的文件是用户使用的。ld.so.conf
是文件,它里面默认只有一句话是include /etc/ld.so.conf.d/*.conf
。即ld.so.conf.d
是一个文件夹,它里面还有很多.conf
文件,真正的库包含目录就在这些文件中。然后顶层的ld.so.conf
文件包含ld.so.conf.d
下的所有文件,也就是统计了这些文件中的库目录。 -
ld.so.cache
是真正和链接器打交道的。这个文件中的内容是系统生成的缓存文件,链接器到这个文件中读取链接的库。这个文件需要调用ldconfig
命令来生成,或者刷新缓存。
因此,添加把库文件的路径加入到 /etc/ld.so.conf
的方法很简单,有两种方法:
- 将库文件的绝对路径直接写进
/etc/ld.so.conf
,一行一个,例如:
include /etc/ld.so.conf.d/*.conf # 系统默认路径
/home/cc/test/Lib # 用户新增库路劲
- 在
/etc/ld.so.conf .d
文件夹下新建一个自己的.conf
文件,在里面写库目录,也是一行一个,例如/etc/ld.so.conf .d/mylib.conf
文件内容:
/home/cc/test/Lib # 用户新增库路劲
如下图可以看到,除了mylib.conf
是我们自己新建的,其他都是安装软件的时候或者系统默认就有的。其中有x86_64-linux-gnu.conf
,这个就是系统默认库包含目录中有/usr/lib/x86_64_linux-gnu
文件夹下的库的根本所在!
库增加结束,调用sudo ldconfig
命令更新缓存,当 ldconfig
操作结束时,会有一个最新的 /etc/ld.so.cache
文件,它反映对 /etc/ld.so.conf
所做的更改。从这一刻起,动态装入器在寻找共享库时会查看在 /etc/ld.so.conf
中指定的所有新目录。
最后查看我们增加的库, 要查看 ldconfig
可以“看到”的所有共享库,请输入ldconfig -p | less
。这里用管道查找特定的路,输入ldconfig -p | grep libmyLog
。
2.4.2./etc/ld.so.conf测试
在ld.so.conf
添加自己的库,LIBRARY_PATH
中没有库目录,此时编译链接不通过,报错同2.2。
在ld.so.conf
不添加自己的库,LIBRARY_PATH
中有库目录,此时编译链接通过,但运行链接错误,报错同2.1。
在ld.so.conf
添加自己的库,LIBRARY_PATH
中有库目录,此时编译链接通过,运行链接也无错误。
2.5.测试5:删除环境变量包含目录,使用cmake的find_library命令
CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 3.0)
project(main)
find_library(MYLOG libmyLog.so "~/test/Lib")
if( MYLOG)
message(STATUS "MYLOG library DIR = ${MYLOG} ")
else()
message(FATAL_ERROR "MYLOG library not found")
endif()
add_executable(main main.cpp)
target_link_libraries(main $[MYLOG} ) # 一定注意LOG是变量,所以要用${}引用!
测试步骤仍然同上,注意编译之前重开窗口,然后printenv | grep LIBRARY
查看一下是否真正满足 “LIBRARY_PATH
不包含库目录且LD_LIBRARY_PATH
也不包含库目录” 的要求。
测试结果是编译链接通过,程序也可以正常运行。
2.6.测试6:删除环境变量包含目录,使用cmake的link_directories命令
CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 3.0)
project(main)
link_directories("~/test/Lib")
add_executable(main main.cpp)
target_link_libraries(main libmyLog.so )
测试步骤仍然同上,注意编译之前重开窗口,然后printenv | grep LIBRARY
查看一下是否真正满足 “LIBRARY_PATH
不包含库目录且LD_LIBRARY_PATH
也不包含库目录” 的要求。
测试结果是编译链接通过,程序也可以正常运行。
问题:之前一个工程遇到了使用link_directories
加入库目录,但是编译链接的时候就是通过不了。最后在target_link_libraries
中指定这个库的绝对路径才能编译链接上。很奇怪!
3.总结
如果链接到一个非系统默认或环境变量中的库,该如何写?
使用find_library
,这样会编译时链接库的目录和运行时链接库的目录。否则就需要在LIBRARY_PATH
和LD_LIBRARY_PATH
都加入库目录,这样才能保证编译链接成功、运行链接成功。
关于link_directories
命令,之前使用遇到奇怪的问题,另外CMake官方也建议不要使用link_directories
,而应该使用find_library
。
4.问题
-
既然
ld.so.conf
里的库等效于LD_LIBRARY_PATH
,也就是程序运行时链接的库。那么程序编译时默认链接的库,即等效于LIBRARY_PATH
的库路径是在哪里定义的呢?并没有找到! -
关于
link_directories
命令,之前使用遇到奇怪的问题,另外CMake官方也建议不要使用link_directories
,而应该使用find_library
。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)