必须显式列出所有.cpp文件或用file(glob)收集源码,禁用aux_source_directory;导出符号需加-fvisibility=hidden及__attribute__((visibility("default")));链接时用target_link_libraries并配置运行时库路径。

直接用 add_library 指定 SHARED 类型,并把所有 cpp 文件列进去,就能打包成动态库。关键不是“能不能”,而是“怎么列、怎么导出、怎么链接时不踩坑”。
如何在 CMakeLists.txt 中声明多个源文件的动态库
必须显式列出所有参与编译的 .cpp 文件(或用 aux_source_directory 收集),不能只写目录名。CMake 不会自动递归扫描子目录。
-
add_library(mylib SHARED a.cpp b.cpp c.cpp)—— 最稳妥,推荐用于小项目 -
file(GLOB SOURCES "src/*.cpp")+add_library(mylib SHARED ${SOURCES})—— 注意:GLOB 不支持增量构建,改了文件但没改CMakeLists.txt时可能漏编译 - 不要用
aux_source_directory(src DIR_SRCS)配合add_library(mylib SHARED ${DIR_SRCS})—— 它不处理子目录,且容易混入非源文件(比如测试文件)
为什么编译出来的 .so 里找不到函数?导出符号是关键
Linux 下默认不导出符号(不像 Windows 的 __declspec(dllexport)),所以即使编译成功,链接时也可能报 undefined reference,或者运行时报 dlsym: symbol not found。
CMake 4.3.2 Windows x86_64 历史版本安装包,适合旧项目兼容、构建环境回退、CMakeLists.txt 迁移验证、Visual Studio/Ninja/Makefile 生成器测试和 C/C++ 项目维护。
- 加编译选项
-fvisibility=hidden(推荐)+ 在头文件中用__attribute__((visibility("default")))标记要导出的函数或类 - 或者简单粗暴:编译时加
-fPIC -shared并确保没加-fvisibility=hidden(但会导出所有符号,增大体积、有命名冲突风险) - 检查是否导出成功:
nm -D libmylib.so | grep my_function—— 如果没输出,说明没导出
链接动态库时,-L 和 -l 顺序和路径必须匹配
CMake 里用 target_link_libraries 是安全的,但要注意作用域和依赖顺序。手动用 gcc 链接时最容易错。
-
target_link_libraries(myapp PRIVATE mylib)—— 前提是mylib是同一个CMakeLists.txt或add_subdirectory引入的目标;否则要先find_library或find_package - 如果库不在标准路径(如
/usr/lib),要用link_directories(/path/to/so),但更推荐用target_link_directories(myapp PRIVATE /path/to/so)(CMake 3.13+) - 运行时报
error while loading shared libraries: libmylib.so: cannot open shared object file,说明LD_LIBRARY_PATH没包含库路径,或没运行sudo ldconfig刷新缓存
最常被忽略的是符号可见性控制和运行时库路径 —— 编译通过不代表函数真能被调用,得用 nm -D 和 ldd 实锤验证。










