ldd进行排查mymath.h, mymath.c编译为共享库// mymath.h
#ifndef MYMATH_H
#define MYMATH_H
int add(int a, int b);
int multiply(int a, int b);
#endif
// mymath.c
#include "mymath.h"
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
#!/bin/bash
# 生成位置无关代码
gcc -c -fPIC mymath.c -o mymath.o
# 生成共享库,版本号设为 1.0.0
gcc -shared -Wl,-soname,libmymath.so.1 -o libmymath.so.1.0.0 mymath.o
# 创建符号链接(模拟标准库的版本管理)
ln -s libmymath.so.1.0.0 libmymath.so.1
ln -s libmymath.so.1 libmymath.so
// main.c
#include <stdio.h>
#include "mymath.h"
int main() {
int a = 10, b = 5;
printf("Testing custom math library:\n");
printf("%d + %d = %d\n", a, b, add(a, b));
printf("%d * %d = %d\n", a, b, multiply(a, b));
return 0;
}
gcc main.c -L -lmymath -o my_program
直接运行会报错:找不到库
error while loading shared libraries: libmymath.so.1: cannot open shared object file: No such file or directory
用ldd查看会发现libmymath.so.1 => not found,说明动态链接器找不到自定义库
临时解决方案
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
升级库,但故意移除一个函数,模拟API不兼容的情况
修改mymath.c,移除multiply
#include "mymath.h"
int add(int a, int b) {
return a + b;
}
编译新版本并更新符号链接
gcc -c -fPIC mymath.c -o mymath.o
gcc -shared -Wl, -soname,libmymath.so.1 -o libmymath.so.1.1.0 mymath.o
# 更新符号链接
ln -sf libmymath.so.1.1.0 libmymath.so.1
ln -sf libmymath.so.1 libmymath.so
运行程序,仍然用旧的main没有重新编译
$ export LD_LIBRARY_PATH=.:LD_LIBRARY_PATH
$ ./my_program
报错
./my_program: symbol lookup error: ./my_program: undefined symbol: multiply
用ldd -r 深入排查
$ LD_LIBRARY_PATH=. ldd -r ./my_program
linux-vdso.so.1 (0x00007286cb3c5000)
libmymath.so.1 => ./libmymath.so.1 (0x00007286cb3b3000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007286cb000000)
/lib64/ld-linux-x86-64.so.2 (0x00007286cb3c7000)
undefined symbol: multiply (./my_program)
最后一行明确指出,说明程序需要的函数在新版库中不存在
验证库中的符号
$ nm -D libmymath.so.1 | grep ' T '
00000000000010f9 T add
解决方案
RPATH指向它不想每次设置LD_LIBRARY_PATH,把库路径写入程序
# gcc main.c -L -lmymath -Wl, -rpath,[绝对路径] -o my_program_rpath
验证
$ unset LD_LIBRARY_PATH
$ ldd ./my_program_rpath
输出
linux-vdso.so.1 (0x00007f8e61fee000)
libmymath.so.1 => libmymath.so.1的绝对路径 (0x00007f8e61fdc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8e61c00000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8e61ff0000)
无需任何变量,直接运行即可
编译时故意多加一个不需要的库
gcc main.c -L. -lmymath -Wl,--no-as-needed -lm -o my_program_extra
--no-as-needed强制保留未使用的库,以免被链接器优化掉用ldd -u 检查
$ LD_LIBRARY_PATH=. ldd -u ./my_program_extra
Unused direct dependencies:
/lib/x86_64-linux-gnu/libm.so.6