目录
其他命令
Linux 动态库的默认搜索路径是 /lib 和 /usr/lib,除了默认的搜索路径外,还可以通过以下几种方法来指定。
原文:https://www.it610.com/article/1295147005911310336.htm
方法一:添加环境变量
添加环境变量三种方式
1. 添加当前用户当前终端的环境变量(临时)
export LD_LIBRARY_PATH=/home/czd/... #.so file path
2. 添加当前用户的环境变量
修改~/.bashrc文件,在其末尾,添加环境变量
vim ~/.bashrc
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/czd/... #.so file path
使其生效,
source ~/.bashrc
如不能生效,请重启
3. 添加所有用户的环境变量
修改profile文件,在其末尾添加环境变量
vim /etc/profile
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/czd/... #.so file path
使其生效
source /etc/profile
如不能生效,请重启
方法二:复制so文件到lib路径
linux系统的so库一般存储与“/usr/lib/”路径中,可将动态库复制到该路径中。
sudo cp liblibtest.so /usr/lib/
即时生效
方法三:(推荐)添加ldconfig寻找路径
步骤1. 编辑链接配置文件
vim /etc/ld.so.conf
,确认内容是否为如下,不是则修改为如下:
include /etc/ld.so.conf.d/*.conf
步骤2. 进入/etc/ld.so.conf.d
目录内,创建*.conf文件,文件名随意,扩展名必须为.conf
cd /etc/ld.so.conf/
vim libmy.conf
步骤4. 在文件内部,添加so的路径,保存并退出
/home/czd/eclipse-workspacee/calllib/Debug
步骤5. 执行命令时期生效
sudo ldconfig
程序在运行时寻找so库就会到添加的目录中寻找。
方法四:在编译目标代码时指定该程序的动态库搜索路径
解决办法有两种,第一程序链接时指定链接库的位置,就是使用-wl,-rpath=<link_path>参数,<link_path>就是链接库的路径。如:
gcc -o foo foo.c -L. -lfoo -Wl,-rpath=/usr/mylib
上面就是指定了链接的位置在/usr/mylib,执行./foo时,foo会去/usr/mylib找libfoo.so库。
不过一般情况我们使用如下格式
gcc -o foo foo.c -L$(prefix)/lib -lfoo -Wl,-rpath=$(prefix)/lib
其他命令
查看程序依赖的.so库
查看可以执行程序需要哪些动态库,以及是否能找到
ldd /usr/bin/mount
[root@rdma64 lcx]# ldd ./ceph_perf_msgr_server_normal
linux-vdso.so.1 => (0x00007ffc24dec000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f6f9a6ee000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f6f9a4ea000)
libmymalloc.so => not found
libjemalloc.so.1 => not found
libsnappy.so.1 => /lib64/libsnappy.so.1 (0x00007f6f9a0e2000)
libceph-common.so.0 => ./bak/libceph-common.so.0 (0x00007f6f912d5000)
查看可以执行程序需要哪些动态库,使用命令:
readelf -d [可执行程序]
查看动态库连接过程
查keep
ldconfig -v | grep keep
ldconfig -p | grep keep
查看一个so链接库的版本
如果要准确的版本,看看这个库文件链接到那个具体文件:
/lib# file libhandle.so
libhandle.so: symbolic link to `libhandle.so.1'
lib# file libhandle.so.1
libhandle.so.1: symbolic link to `libhandle.so.1.0.3'
可以看到经过两次链接,最终文件名中1.0.3是版本号,其它方法只能得出主版本号
查看So 的版本、GCC版本、GLIB版本
strings libc.so | grep Version
1. 查看GLIB版本信息
动态库查找顺序strings xxx | grep GLIB
~$ strings libGL.so | grep GLIB
GLIBC_2.2.5
GLIBC_2.3.2
GLIBC_2.3
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.14
GLIBC_2.17
2. 查看GCC版本信息strings xxx | grep GCC
~$ strings libGL.so | grep GCC
GCC_3.0
GCC: (Debian 6.4.0-22) 6.4.0 20180924
综合以上结果可知,动态库的搜索路径搜索的先后顺序是:
1.编译目标代码时指定的动态库搜索路径; //-L、-rpath和-rpath-link
2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
3.配置文件/etc/ld.so.conf中指定的动态库搜索路径;
4.默认的动态库搜索路径/lib;
5.默认的动态库搜索路径/usr/lib。
在上述1、2、3指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。
动态库[链接时]路径和[运行时]路径( -L、-rpath和-rpath-link的区别)
现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开。用户可以
- 通过-L 指定编译连接时库的路径
- 通过-R(或-rpath)指定程序运行时库的路径,
大大提高了库应用的灵活性。
比如我们在编译环境 gcc -o target -L /work/lib/zlib/ -llibz-1.2.3 (work/lib/zlib下是编译环境的动态库目录),将target编译好后我们只要把zlib下的库文件拷贝到运行环境的系统默认路径下即可。或者通过-rpath(或-R )、LD_LIBRARY_PATH指定查找路径。
链接器ld的选项有 -L,-rpath 和 -rpath-link,大致是这个意思:
-L: “链接”的时候,去找的目录,也就是所有的 -lxxx 选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径。
-rpath和-rpath-link都可以在链接时指定库的路径;但是运行可执行文件时,-rpath-link指定的路径就不再有效(链接器没有将库的路径包含进可执行文件中),
而-rpath指定的路径还有效(因为链接器已经将库的路径包含在可执行文件中了。)
修改efl文件(程序、库文件)的库依赖路径工具:patchelf
(RHEL 已经自带了chrpath工具,直接使用即可. ( yum install chrpath)不过chrpath 有个缺陷,如果当前系统为x86_64,则修改i386 elf会报错,patchelf则无此问题!)
rpath全称是run-time search path。Linux下所有elf格式的文件都包含它,特别是可执行文件。它规定了可执行文件在寻找.so文件时的第一优先位置。用patchelf修改它的信息。
查看demo依赖的库:
$ readelf -d demo
路径修改
更改程序或库运行时搜索依赖库的路径(多个路径用冒号隔开)
$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program
去掉冗余的依赖库路径(Shrink the RPATH of executables and libraries:)
$ patchelf --shrink-rpath my-program
去掉冗余的依赖库路径,但保留/usr/lib:/foo/lib前缀的路径
$ patchelf --shrink-rpath --allowed-rpath-prefixes /usr/lib:/foo/lib my-program
依赖修改
删除依赖(删除my-program对libfoo.so.1的依赖)
$ patchelf --remove-needed libfoo.so.1 my-program
增加依赖(给my-program增加对libfoo.so.1的依赖)
$ patchelf --add-needed libfoo.so.1 my-program更换依赖。原本是依赖 liboriginal.so.1,改为依赖 libreplacement.so.1
$ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program
更改动态库的短名(SONAME) :
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3 Change the dynamic loader ("ELF interpreter") of executables
$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
官网使用说明:
README.md
PatchELF is a simple utility for modifying existing ELF executables and libraries. In particular, it can do the following:
Change the dynamic loader ("ELF interpreter") of executables:
$ patchelf --set-interpreter /lib/my-ld-linux.so.2 my-program
Change the RPATH of executables and libraries:
$ patchelf --set-rpath /opt/my-libs/lib:/other-libs my-program
Shrink the RPATH of executables and libraries:
$ patchelf --shrink-rpath my-program
This removes from the RPATH all directories that do not contain a library referenced by DT_NEEDED fields of the executable or library. For instance, if an executable references one library libfoo.so, has an RPATH /lib:/usr/lib:/foo/lib, and libfoo.so can only be found in /foo/lib, then the new RPATH will be /foo/lib.
In addition, the --allowed-rpath-prefixes option can be used for further rpath tuning. For instance, if an executable has an RPATH /tmp/build-foo/.libs:/foo/lib, it is probably desirable to keep the /foo/lib reference instead of the /tmp entry. To accomplish that, use:
$ patchelf --shrink-rpath --allowed-rpath-prefixes /usr/lib:/foo/lib my-program
Remove declared dependencies on dynamic libraries (DT_NEEDED entries):
$ patchelf --remove-needed libfoo.so.1 my-program
This option can be given multiple times.
Add a declared dependency on a dynamic library (DT_NEEDED):
$ patchelf --add-needed libfoo.so.1 my-program
This option can be give multiple times.
Replace a declared dependency on a dynamic library with another one (DT_NEEDED):
$ patchelf --replace-needed liboriginal.so.1 libreplacement.so.1 my-program
This option can be give multiple times.
Change SONAME of a dynamic library:
$ patchelf --set-soname libnewname.so.3.4.5 path/to/libmylibrary.so.1.2.3
链接静态库/动态库
链接静态库
链接静态库libadd_minus.a
方式一
gcc -o main2 main.o -L./ -ladd_minus
说明1:-L./表明库文件位置在当前文件夹
说明2: -ladd_minus 表示链接 libadd_minus.a 文件,使用“-l”参数时,前缀“lib”和后缀“.a”是需要省略的。
方式二、
-L/your/library/path -l:libmylib.a
如果-l:filename
格式指定一个文件名,连接程序直接去找这个文件名了,不会再像使用-lname
时将name扩展成lib<name>.a
格式的文件名.
当然如果库的位置不在gcc默认搜索路径中,要用-L
参数另外指定搜索库的路径
在gcc编译链接时强制使用lib.a
当一个库文件既有.a又有.so时,如果这么写,gcc会优先链接.so文件:
gcc -L/path/to/library/ -ljemalloc -o run
有一种写法可以强制链接.a库文件:
gcc -L/path/to/library/ -l:libjemalloc.a -o run
这种写法也能解决当依赖库不是以libxxx.a或者libxxx.so规范命名时,可以通过指定库文件全名来解决。
链接动态库
gcc -o main4 main.o -L./ -ladd_minus -lmulti_div
说明1:-L./表明库文件位置在当前文件夹
说明2: -ladd_minus 表示链接 libadd_minus.so 文件,使用“-l”参数时,前缀“lib”和后缀“.so”是需要省略的。