优先用 find_package,找不到再手动导入预编译库;Android NDK 下必须用 add_library(... SHARED IMPORTED) 配合 set_target_properties,不能只靠 link_directories。

直接说结论:优先用 find_package,找不到再手动导入预编译库;Android NDK 下必须用 add_library(... SHARED IMPORTED) 配合 set_target_properties,不能只靠 link_directories。
find_package 找不到库?先确认它有没有提供 Config 文件
find_package 不是万能的——它依赖第三方库是否自带 XXXConfig.cmake 或 FindXXX.cmake。比如 OpenCV、Qt、fmt(>=9.0)通常自带;但很多轻量库(如 log4cplus、tinyxml2)默认不带,硬写 find_package(log4cplus REQUIRED) 会报错:Could not find a package configuration file。
- 查证方式:进你装好的库目录,搜
*Config.cmake或cmake/子目录下有没有配置文件 - 没找到就别强用
find_package,否则只能靠PATHS参数硬指定路径,例如:find_package(OpenCV REQUIRED PATHS /opt/opencv4/share/opencv4/cmake) - 更稳妥的做法是:用
pkg_check_modules(需启用PkgConfig模块),尤其对 Linux/macOS 上通过apt或brew安装的库
Android NDK 必须用 IMPORTED 方式引入 .so
在 Android 的 CMakeLists.txt 中,link_directories + target_link_libraries(mylib xxx) 这种写法大概率失败——NDK 构建时不会自动按 ABI 查找 .so,而且 link_directories 对 ANDROID_ABI 变量不敏感。
- 正确做法是显式声明导入库:
add_library(openssl SHARED IMPORTED) - 然后绑定具体路径:
set_target_properties(openssl PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libssl.so) - 路径中的
${ANDROID_ABI}会被自动替换为当前构建的 ABI(如arm64-v8a),否则你得自己写条件判断 - 头文件路径用
target_include_directories(native-lib PRIVATE src/main/cpp/include),别用全局include_directories
静态库(.a)和动态库(.so/.dll)链接写法不同
链接行为差异直接影响能否运行成功,尤其在 Android 上漏掉 .a 的完整路径或写错 INTERFACE 会导致 undefined reference 或 dlopen 失败。
- 静态库必须给全路径:
target_link_libraries(myapp PRIVATE ${CMAKE_SOURCE_DIR}/libs/libcurl.a),不能只写curl - 动态库可只写名字(如
curl),但前提是它已通过add_library(... IMPORTED)正确注册,或系统路径已包含(Android 系统库如log、android除外) - 用
PUBLIC/PRIVATE控制头文件暴露范围:target_include_directories(thirdparty PUBLIC include/)表示依赖它的目标也能用这些头文件;PRIVATE则仅限当前目标
最容易被忽略的是:CMake 的 IMPORTED 库必须在 target_link_libraries 里显式列出,且顺序不能颠倒——依赖项要放在被依赖项之后,否则链接器找不到符号。这点在多层第三方库嵌套时特别关键。


















