ldd用于检查.so文件自身依赖是否可解析,若输出含“not found”则表明缺失本质依赖(如libgcc_s.so.1),而非路径问题;配合objdump -p和nm -D可验证依赖声明与符号导出,dlopen实测则能暴露运行时加载真实问题。

用 ldd 检查动态库自身是否可解析依赖
动态库(.so)本身也可能依赖其他库,比如 libc.so.6 或 libm.so.6。如果它连自己的依赖都加载不了,就别提被程序用了。
直接对 .so 文件运行 ldd:
ldd libmyutil.so
关键看输出里有没有 not found。如果有,说明编译时没链接上对应库,或者系统里根本没装——不是路径问题,是缺失本质依赖。
常见错误现象:
-
libmyutil.so => not found:这个其实不表示库本身坏,而是ldd找不到它(因为没加搜索路径),但更危险的是下面这种 -
libgcc_s.so.1 => not found:你用 Clang 编译却依赖 GCC 的运行时,而目标环境没装libgcc,运行时必炸
用 objdump -p 确认导出符号是否符合预期
生成的 .so 有没有把你想暴露的函数真正导出来?光有源码声明不够,得看 ELF 动态段里写了什么。
执行:
objdump -p libmyutil.so | grep NEEDED
这行只看它依赖谁;再补一句查导出符号:
Clang 22.1.3 Windows 64 位历史版本安装包,适合旧项目兼容、LLVM/Clang 工具链回退、编译行为对比、链接问题复现和 C/C++ 构建环境维护。
nm -D libmyutil.so | grep ' T '
T 表示全局定义的函数符号(大写 T),t 是局部的。如果你写了 int add(int a, int b) 却没在输出里看到 add,大概率是:
- 忘了加
__attribute__((visibility("default"))),且编译时用了-fvisibility=hidden - 函数名被 C++ mangling 改了(C++ 源码没套
extern "C") - 函数是
static的,或放在了匿名命名空间里
用 dlopen + dlsym 在最小环境中实测加载
这是最贴近真实使用场景的验证方式:不编译主程序,只写几行 C 代码,模拟运行时加载行为。
新建 test_load.c:
#include <stdio.h><br>#include <dlfcn.h><br><br>int main() {<br> void *h = dlopen("./libmyutil.so", RTLD_LAZY);<br> if (!h) {<br> fprintf(stderr, "dlopen failed: %s\n", dlerror());<br> return 1;<br> }<br> void *sym = dlsym(h, "add");<br> if (!sym) {<br> fprintf(stderr, "dlsym(add) failed: %s\n", dlerror());<br> dlclose(h);<br> return 1;<br> }<br> dlclose(h);<br> printf("OK: loaded and found 'add'\n");<br> return 0;<br>}
编译并运行:
clang test_load.c -ldl -o test_load<br>./test_load
这个测试绕过了链接器阶段,直接走运行时动态加载链路,能暴露:
-
libmyutil.so是否有权限问题(如 noexec mount) - 是否因 ABI 不匹配(比如结构体对齐、
long大小)导致dlopen静默失败(某些旧 glibc 版本会) -
RTLD_GLOBAL/RTLD_LOCAL作用域引发的后续符号冲突(虽此处没用,但值得记着)
注意 Clang 编译动态库时的隐含陷阱
Clang 默认行为和 GCC 有细微差别,容易让 .so 在非开发机上跑不起来:
- Clang 14+ 默认启用
-fPIE,但生成.so必须用-fPIC;如果误用-fPIE,链接会成功,但ldd可能报cannot dynamically load position-independent executable - Clang 不自动链接
libgcc或libunwind,若你的库用了异常或 RTTI,得显式加-lgcc或-lunwind - 未指定
-target时,Clang 可能生成带 macOS 特有 flag 的.so(比如误用dylib格式),尤其在跨平台 CI 中要核对file libmyutil.so输出是否为ELF 64-bit LSB shared object
真正麻烦的不是“能不能生成”,而是“生成的东西看起来能过 ldd,但一进真实环境就挂”。验证必须在目标环境或容器里做,不能只信开发机结果。

















