clang++编译C++生成.so需用-fPIC和-shared,必须用extern "C"导出函数防mangling,依赖STL时默认动态链接libstdc++.so,符号未定义或模板未实例化会导致运行时崩溃。

clang++ 编译 C++ 源码生成 .so 动态库
直接用 clang++ 加 -shared 就能生成 Linux 下的 .so 文件,但必须确保符号导出正确、无未定义引用,且不链接标准库静态部分。
-
clang++ -shared -fPIC -o libfoo.so foo.cpp是最简可行命令;-fPIC不可省——x86_64 上漏掉会报relocation R_X86_64_32 against symbol错误 - 如果源码依赖 STL(比如用了
std::string或std::vector),默认会动态链接libstdc++.so,无需额外加-lstdc++;强行静态链接(-static-libstdc++)反而会导致运行时报undefined symbol: _ZTVN10__cxxabiv120__function_type_infoE类错误 - 头文件里声明的函数,若没在源文件中定义,编译时不会报错,但链接动态库时会静默丢弃该符号——运行时调用就崩,建议加
-Wl,--no-undefined让链接器立刻报错
导出 C 风格接口避免 name mangling
C++ 默认对函数名做 mangling,其他语言(如 Python ctypes 或 C 程序)没法直接 dlsym 查找。必须显式用 extern "C" 包裹导出函数声明。
- 头文件中写:
extern "C" { void do_work(int x); const char* get_version(); } - 对应实现文件里也得保持
extern "C"块内定义,否则链接后符号仍是 mangled 形式(如_Z8do_worki) - 类成员函数不能直接导出,要么写成自由函数,要么用
static成员 +extern "C"包装一层
检查符号是否真正导出
生成 .so 后别急着用,先用工具确认目标函数在动态库中可见且未被优化掉。
-
nm -D libfoo.so | grep do_work—— 如果没输出,说明符号没导出(常见于忘了extern "C"或函数是static) -
objdump -T libfoo.so | grep do_work更可靠,只显示动态符号表里的条目 - 如果看到
U do_work(大写 U),代表该符号是 undefined,即本库依赖它但没提供——说明你误把实现放到了另一个没编进去的文件里
运行时找不到 .so 怎么办
Linux 下 dlopen 或直接执行依赖该库的程序时,系统默认只查 /lib、/usr/lib 和 LD_LIBRARY_PATH 中路径。本地开发的 .so 很容易“看不见”。
- 临时生效:
LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH ./myapp(注意.表示当前目录) - 永久方案不是改全局
/etc/ld.so.conf,而是用-rpath编译进库:clang++ -shared -fPIC -Wl,-rpath,'$ORIGIN' -o libfoo.so foo.cpp,这样运行时会自动从libfoo.so所在目录查找依赖 -
ldd ./myapp会列出所有依赖,如果某.so显示not found,说明路径没对上,别猜,先跑ldd
实际项目里最容易忽略的是:C++ 模板函数不会自动实例化进动态库,哪怕你写了 extern "C" 声明也没用——它根本没生成符号。这类必须显式实例化,或者改用非模板接口。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











