PackageName_DIR优先级最高,CMake仅在其指定目录下查找Config文件;CMAKE_PREFIX_PATH用于批量设置多个库的搜索根目录;NO_DEFAULT_PATH会禁用所有默认路径;Module模式需提前设置CMAKE_MODULE_PATH。

find_package 优先级最高的路径是 PackageName_DIR
直接在命令行传入 PackageName_DIR 是最可靠、最优先的指定方式,CMake 会跳过所有其他路径,只在这个目录下找 PackageNameConfig.cmake 或 PackageName-config.cmake。
常见错误是把路径设成库的安装根目录(如 /opt/opencv),但实际应指向包含 Config 文件的子目录(通常是 lib/cmake/opencv 或 share/opencv/cmake)。
- 正确示例:
cmake -DOpenCV_DIR=/usr/local/lib/cmake/opencv4 .. - 错误示例:
cmake -DOpenCV_DIR=/usr/local ..(CMake 找不到 Config 文件) - 如果路径中含空格或特殊字符,必须用引号包裹:
-DBoost_DIR="/path/with spaces/boost" -
PackageName_DIR只影响本次find_package()调用,不污染全局环境
用 CMAKE_PREFIX_PATH 批量设置多个库的搜索根目录
当你同时集成多个自编译库(比如 Eigen、glog、protobuf 都装在 ~/deps 下),CMAKE_PREFIX_PATH 比逐个设 _DIR 更干净。
CMake 会依次在 ${CMAKE_PREFIX_PATH}/lib/cmake/<name></name>、${CMAKE_PREFIX_PATH}/share/<name>/cmake</name> 等位置查找 Config 文件。
- 命令行写法:
cmake -DCMAKE_PREFIX_PATH=$HOME/deps .. - 注意:路径末尾不要加
/lib/cmake—— CMake 自己拼接子路径 - 多个路径用分号分隔(Linux/macOS 用
:,Windows 用;),例如:-DCMAKE_PREFIX_PATH="/a;/b" - 它不影响
find_path()或find_library()的行为,只作用于find_package()的 Config 模式
禁用默认路径时小心 NO_DEFAULT_PATH 的副作用
加上 NO_DEFAULT_PATH 后,CMake 不再查 /usr、/usr/local、CMAKE_INSTALL_PREFIX 等系统路径 —— 这能避免误匹配系统旧版本,但也容易“什么也找不到”。
它常和 HINTS 或 PATHS 配合使用,但顺序很重要:CMake 先查 HINTS,再查 PATHS,且都只在你显式列出的路径里搜。
- 安全写法:
find_package(Protobuf REQUIRED HINTS ${PROTOBUF_ROOT} NO_DEFAULT_PATH) - 危险写法:
find_package(Protobuf REQUIRED PATHS /wrong/path NO_DEFAULT_PATH)(查不到就直接失败) -
NO_DEFAULT_PATH会同时禁用CMAKE_PREFIX_PATH和PackageName_DIR—— 它真的“啥都不认”,只信你给的HINTS/PATHS - 调试技巧:加
MESSAGE(STATUS "CMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")确认变量是否生效
模块模式下 CMAKE_MODULE_PATH 必须提前设置
当库没提供 XXXConfig.cmake(比如老版本 Boost 或某些自制库),CMake 会退回到 Module 模式,去查 FindXXX.cmake。此时 CMAKE_MODULE_PATH 决定它去哪找。
这个变量必须在任何 find_package() 调用前设置,否则无效 —— 放在 project() 之后、find_package() 之前是最稳妥的位置。
- 正确顺序:
project(MyProj)→set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules" ${CMAKE_MODULE_PATH})→find_package(MyLib) -
CMAKE_MODULE_PATH是 list 类型,追加时用${CMAKE_MODULE_PATH}保留原有路径 - 自定义
FindXXX.cmake文件里不能依赖PackageName_DIR—— Module 模式根本不读这个变量 - 别指望
find_package(MyLib MODULE)能绕过 Config 模式:它只是强制走 Module 模式,仍要你提供FindMyLib.cmake
XXX_FOUND),但它们的底层逻辑完全隔离。一个库是否真正“被正确找到”,取决于它走的是哪种模式、以及对应模式下的文件是否存在且无语法错误 —— 而不是你写了 find_package(XXX REQUIRED) 就万事大吉。


















