clang生成动态库需用-shared(Linux)或-dynamiclib(macOS),必须加-fPIC和-o指定输出名,macOS误用-shared会静默生成可执行文件;推荐-fvisibility=hidden配合__attribute__((visibility("default")))控制导出符号。

clang 编译动态库的基本命令格式
用 clang 生成动态库,核心是加 -shared 参数,且必须显式指定输出文件名(-o libxxx.so 或 -o libxxx.dylib)。不加 -shared 默认生成可执行文件,加了但没写 -o 会报错或生成无意义的 a.out。
Linux 下典型命令:
clang -shared -fPIC -o libmath.so math.c
macOS 下需用 .dylib 后缀,并注意链接器行为差异:
clang -shared -fPIC -o libmath.dylib math.c
-
-fPIC必须加上,否则链接时会报relocation R_X86_64_32 against ... can not be used when making a shared object - 多个源文件直接列在命令末尾:
clang -shared -fPIC -o libutil.so util.c log.c - 如果依赖其他库,用
-L和-l,但这些只影响编译期符号解析,不嵌入到动态库中
为什么 macOS 上 clang -shared 有时不生效
macOS 的 clang 实际调用的是 ld 的 Darwin 版本,它不认 -shared——这个参数会被忽略,真正起作用的是 -dynamiclib。用错参数会导致静默生成可执行文件,而不是动态库。
正确写法(macOS):
Clang 22.1.3 Windows 64 位历史版本安装包,适合旧项目兼容、LLVM/Clang 工具链回退、编译行为对比、链接问题复现和 C/C++ 构建环境维护。
clang -dynamiclib -fPIC -o libmath.dylib math.c
- 用
-shared在 macOS 上不会报错,但生成的是普通可执行文件(file libmath.dylib会显示executable),运行时加载失败 -
-dynamiclib是 macOS 唯一可靠的动态库生成开关 - 不需要额外加
-undefined dynamic_lookup,除非你明确要延迟绑定未定义符号
头文件和符号导出控制
Clang 默认导出所有非 static 全局符号,不依赖 __attribute__((visibility)) 也能工作,但容易导出内部辅助函数,增加 ABI 风险。
- 推荐加
-fvisibility=hidden,再对需要导出的函数加__attribute__((visibility("default"))) - 头文件里声明函数时,可以配合宏统一控制:
#ifdef BUILDING_MYLIB
#define MYLIB_API __attribute__((visibility("default")))
#else
#define MYLIB_API
#endif
MYLIB_API int add(int a, int b);
- 编译时定义
-DBUILDING_MYLIB:clang -dynamiclib -fPIC -fvisibility=hidden -DBUILDING_MYLIB -o libmylib.dylib mylib.c - 不加
-fvisibility=hidden也能跑,但后期维护、版本兼容、dlopen 符号冲突都更难处理
验证动态库是否生成成功
光看文件名和大小没用,得确认 ELF/Mach-O 类型和导出符号。Linux 下用 file 和 nm -D;macOS 用 file 和 nm -DY(或 otool -Iv)。
- Linux:
file libmath.so应输出ELF 64-bit LSB shared object;nm -D libmath.so显示你期望的函数名 - macOS:
file libmath.dylib应含Mach-O 64-bit dynamically linked shared library;nm -DY libmath.dylib查看动态符号表 - 如果
nm输出为空或全是U(undefined),说明函数被优化掉或没加extern/default可见性
跨平台项目里最容易漏掉的是 macOS 的 -dynamiclib 替换和 .dylib 后缀硬编码,这两处一错,后续所有 dlopen 都会失败,而且错误信息非常模糊。










