find_package 找不到库主因是路径未设对或缺少Config/Find文件;需正确设置CMAKE_PREFIX_PATH/CMAKE_MODULE_PATH,优先用CONFIG模式和IMPORTED target,且所有find_package应放在顶层。
绝大多数问题出在 CMAKE_MODULE_PATH 或 CMAKE_PREFIX_PATH 没设对,或者库本身没提供合格的 *Config.cmake 或 Find*.cmake 文件。CMake 默认只查系统路径(如 /usr/lib/cmake、/opt/homebrew/lib/cmake),不会自动扫描你 git clone 下来的源码目录或自建的 build/ 输出路径。
find_package(XXX REQUIRED) 前,先确认该库是否已安装且带 CMake 支持(比如 apt install libboost-all-dev 而非仅 libboost-dev)make install 到 /opt/mylib),必须在 find_package 前加:set(CMAKE_PREFIX_PATH "/opt/mylib" ${CMAKE_PREFIX_PATH})
FindXXX.cmake 文件(比如放在项目 cmake/ 目录下),需提前设置:set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})find_package 默认优先走 CONFIG 模式(找 XXXConfig.cmake 或 xxx-config.cmake),失败才回落到 MODULE 模式(找 FindXXX.cmake)。现代库(如 Qt6、OpenCV 4+、Boost 1.70+)基本都提供 Config 模式支持,应优先依赖它——更可靠、支持版本语义(find_package(Boost 1.75 REQUIRED COMPONENTS system filesystem))、能正确传递 INTERFACE 属性。
find_package(XXX CONFIG REQUIRED);加 CONFIG 后,CMAKE_MODULE_PATH 就不起作用了find_package(XXX MODULE REQUIRED);适合老库或临时补丁(比如你写了自定义 FindMyLib.cmake)找到包后,CMake 会导出一个或多个 IMPORTED target(如 Boost::system、Threads::Threads),这才是现代用法的核心。别再用 ${Boost_INCLUDE_DIRS} 或 ${OpenCV_LIBS} 这类变量——它们是旧式 MODULE 模式遗留,不保证接口一致性,也无法跨平台正确处理链接顺序或编译定义。
target_link_libraries(myapp PRIVATE Boost::system Threads::Threads)
if(TARGET Boost::system),而不是 if(Boost_FOUND)
Find*.cmake 只设变量),说明它不满足“现代 CMake”要求,应避免使用,或自行封装一层 add_library(Boost::system IMPORTED)
find_package 的结果(包括导入的 target 和缓存变量)默认是全局可见的,但有个关键例外:如果你在 add_subdirectory() 引入的子项目中调用 find_package,而主项目没提前声明依赖,CMake 可能因作用域隔离导致 target 名称冲突或未传播。
find_package 应统一放在 CMakeLists.txt 顶层(project() 之后、add_subdirectory() 之前)find_package 仅在极少数场景合理:比如子项目是完全独立可构建的第三方模块,且明确不依赖主项目的任何 find 结果find_package 后,通过 target_link_libraries(... PRIVATE ...) 显式透传,而非让它自己再找一遍find_package 的解析是静态的、一次性的,一旦缓存生成(CMakeCache.txt),后续修改 CMAKE_PREFIX_PATH 或新增库路径都不会自动重触发查找——必须删掉 build/ 目录或手动 cmake -U 清缓存。这是最容易被忽略、却导致“明明装了就是找不到”的根本原因。