clang作编译器时cmake需显式指定,否则默认用gcc/msvc导致abi不一致;add_library(shared)自动加-fpic,无需手动添加。

Clang作为编译器时,CMake必须显式指定
默认 CMake 在 Linux/macOS 上会优先找 gcc,Windows 上找 MSVC;即使你系统装了 Clang,cmake .. 也不会自动用它。不指定的话,哪怕你后续在代码里加了 -fPIC,链接阶段仍可能因 ABI 或符号导出规则不一致而失败。
正确做法是在配置阶段用 -DCMAKE_CXX_COMPILER=clang++(或 -DCMAKE_C_COMPILER=clang)强制指定:
cmake -S . -B build -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang
如果你用 Ninja 生成器(推荐),可一并加上:
cmake -S . -B build -G Ninja -DCMAKE_CXX_COMPILER=clang++
验证是否生效:构建后查看 build/CMakeCache.txt 中 CMAKE_CXX_COMPILER:FILEPATH=... 的值,或运行 cmake --build build --verbose | head -n 3 看实际调用的命令是不是 clang++。
add_library(SHARED) 必须配 -fPIC,但不用手写
Clang 和 GCC 都要求动态库目标代码位置无关,否则链接时报 relocation R_X86_64_32 against symbol 错误。但你**不需要**在 add_compile_options(-fPIC) 里手动加——CMake 对 SHARED 目标会自动注入 -fPIC(Clang 下也一样)。
只要确保:
-
add_library(mylib SHARED src/a.cpp src/b.cpp)中明确写了SHARED - 没在
target_compile_options(mylib PRIVATE -fPIE)这类错误选项干扰它 - 没把该 target 设为
STATIC后又试图 link 到可执行文件(会直接报错)
如果 CMake 版本 -fPIC,此时才需补:set_property(TARGET mylib PROPERTY POSITION_INDEPENDENT_CODE ON)。
Clang 22.1.3 Windows 64 位历史版本安装包,适合旧项目兼容、LLVM/Clang 工具链回退、编译行为对比、链接问题复现和 C/C++ 构建环境维护。
Clang 下 Windows DLL 导出要小心 __declspec 宏定义
Clang on Windows(比如通过 LLVM/MinGW 或 VS 的 ClangCL 工具链)对 __declspec(dllexport) 支持不如 MSVC 原生稳定。常见现象是:头文件里写了 EXPORT_API,但生成的 .dll 里符号为空,dumpbin /exports 看不到函数名。
解决方法分两步:
- 在 CMakeLists.txt 中统一启用 Clang 的 DLL 导出支持:
target_compile_definitions(mylib PRIVATE _CRT_SECURE_NO_WARNINGS)(可选),更重要的是加:target_compile_options(mylib PRIVATE $:-Xclang -fdeclspec>) - 头文件中避免依赖编译器内置宏判断,改用更健壮的写法:
#if defined(_WIN32) && !defined(__clang__)# define EXPORT_API __declspec(dllexport)#elif defined(_WIN32) && defined(__clang__)# define EXPORT_API __attribute__((dllexport))#else# define EXPORT_API#endif
Clang + CMake 生成的 .so 或 .dylib 要注意 rpath
Clang 默认生成的动态库不带 RPATH(Linux)或 @rpath(macOS),导致运行时找不到依赖库,报错 error while loading shared libraries: libmylib.so: cannot open shared object file。
必须显式设置运行时路径:
- Linux:
set_target_properties(mylib PROPERTIES INSTALL_RPATH "$ORIGIN/../lib") - macOS:
set_target_properties(mylib PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "@rpath") - 同时对可执行目标也要设:
set_target_properties(myapp PROPERTIES INSTALL_RPATH "$ORIGIN/../lib")
注意:$ORIGIN 是运行时解析的关键字,不能写成绝对路径或 ${CMAKE_BINARY_DIR}/lib —— 那只是构建时路径,对最终运行无效。
Clang 下动态库最容易被忽略的其实是跨平台宏定义一致性:同一份头文件,在 Clang 和 GCC 下对 __declspec、visibility、dllexport 的解释有细微差别,光靠 #ifdef __clang__ 不够,得结合 PLATFORM_ID 和实际编译器行为做 fallback。










