undefined

1. 找不到动态库的解决方法

Linux 动态库的默认搜索路径是 /lib/usr/lib ,可使用以下方法来指定搜索路径

  1. 添加环境变量或移动动态库文件
1
2
3
4
5
6
7
// 添加当前用户当前终端的环境变量(临时)
export LD_LIBRARY_PATH=xxx
// 永久生效
添加到 ~/.bashrc 或者 /etc/profile 文件
source /etc/profile

// 将 so 库移动到 /usr/lib 目录
  1. 添加 ldconfig 寻找路径
1
2
3
4
vim /etc/ld.so.conf  直接添加路径

如果 /etc/ld.so.conf 中有 include /etc/ld.so.conf.d/*.conf 。可以进入 /etc/ld.so.conf.d 目录中创建 libxxx.conf 文件,并添加路径
执行 ldconfig 生效
  1. 编译目标代码时指定程序的动态库搜索路径
1
gcc xxx.c -Lxxx -lxxx -Wl,-rpath=xxx -o main 

使用 -Wl,-rpath=<link_path> 参数,<link_path> 就是链接库的路径

2. 动态库查找顺序

  1. 编译目标代码时指定的动态库搜索路径; //-L、-rpath和-rpath-link
  2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径;
  3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径;
  4. 默认的动态库搜索路径/lib;
  5. 默认的动态库搜索路径/usr/lib。

在上述1、2、3指定动态库搜索路径时,都可指定多个动态库搜索路径,其搜索的先后顺序是按指定路径的先后顺序搜索的。

3. 动态库路径(链接时和运行时)

现代链接器在处理动态库时将链接时路径(Link-time path) 和运行时路径(Run-time path) 分开。用户可以

  • 通过 -L 指定编译链接时库的路径
  • 通过 -R-rpath 指定程序运行时库的路径

链接器 ld 的选项有 -L-rpath-rpath-link 。区别如下

  • -L :链接时去找的目录,也就是所有的 -lxxx 选项里的库,都会先从 -L 指定的目录去找,然后是其他默认地方。-L 只是指定了程序编译链接时库的路径,并不影响程序运行时库的路径
  • -rpath-rpath-link 都可以在链接时指定库的路径。但是运行可执行文件时,-rpath-link 指定的路径就不再有效(链接器没有将库的路径包含到可执行文件中)-rpath 指定的路径有效(因为链接器已经将库的路径包含在可执行文件中了)

LIBRARY_PATHLD_LIBRARY_PATH 环境变量的区别:

  • LIBRARY_PATH 环境变量用在程序编译期间查找动态链接库时指定查找库的路径
  • LD_LIBRARY_PATH 环境变量用于在程序加载期间查找动态链接库时指定除了系统默认路径之外的其他路径

4. 其他命令

  • 查看程序依赖的 so 库
1
2
3
4
// 使用 ldd 查看可执行程序需要用到哪些动态库以及是否能找到
ldd <可执行文件>
// 查看可执行程序需要哪些动态库
readelf -d <可执行文件>
  • 查看 so 库的信息
1
2
3
4
5
// 查看 so 库的信息
file libxxx.so

// 查看 so 库中的字符串信息(比如查看版本号)
strings libxxx.so | grep Version

5. 链接动/静态库

1
2
3
4
5
6
7
# 第一种方式
gcc main.c -Lxxx -lxxx -o main
使用 -l 参数时,前缀 lib 和 后缀 .a / .so 是需要省略的

# 第二种方式
gcc main.c -Lxxx -l:libxx.a -o main
如果使用 -l:filename 格式指定一个文件名,链接程序直接去找这个文件名了

当一个库文件既有 .a 又有 .so 时,gcc 会优先链接 .so 文件。如果强制链接 .a 库文件,如下即可

1
gcc -Lxxx -l:libxxx.a -o main

6. 静态库说明

创建静态库:将代码文件编译成目标文件(.o),然后通过 ar 工具将目标文件打包成 .a 静态库文件

1
2
gcc -c xxx.c -o xxx.o 
ar -crv libxxx.a xxx.o

7. nm 命令

nm 命令可以打印出库中的涉及到的所有符号。库既可以是静态的,也可以是动态的。nm 列出的符号有很多,常见的有三种

  • 一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用 U 表示
  • 一种是库中定义的函数,用 T 表示,比较常见
  • 一种的所谓的弱态符号,他们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用 W 表示