前言
- find_package是cmake用来管理第三方库的一个命令。
- 那这个命令有什么用呢?在实际项目开发中,我们肯定会使用到第三方库。那就需要在程序中,去指定库的位置和头文件位置,但库的安装位置,每个人都是不一样的,基本上所有项目都是很多人一起协同开发,我们不可能直接在项目中把路径写死。
- find_package就可以解决这个问题,他会自动去查找第三方库的位置。这样不管你的第三方库安装在哪个位置,都可以使用同一套项目代码。
语法
- 语法简介
-
find_package(<PackageName> [<version>] [REQUIRED] [COMPONENTS <components>...])
- PackageName: 包名
- version: 版本
- REQUIRED: 指定后如果找不到对应包,cmake就会停止执行。
- COMPONENTS: 指定要查找的组件
- 执行find_package命令后,会自动设置以下三个变量 :
PackageName_FOUND
:找到了就是TruePackageName_INCLUDE_DIR
或者PackageName_INCLUDES
:头文件目录PackageName_LIBRARY
或者PackageName_LIBRARIES
: 库文件位置
模式
- cmake有两种查找库的模式,分别为 Module mode 和 Config mode。默认情况下, cmake采用Module模式查找, 如果没有找到, 再采用Config模式查找.
Module mode
- 在Module模式中,cmake需要找到一个叫做
Find<PackageName>.cmake
的文件。这个文件负责找到库所在的路径,为我们的项目引入头文件路径和库文件路径。 - cmake搜索这个文件的路径有两个,一个是cmake安装目录下的
share/cmake-<version>/Modules
(Linux平台为/usr/share/cmake-<version>/modules
)目录,另一个是我们指定的CMAKE_MODULE_PATH
的所在目录。 - 这里简单演示下,我的电脑上安装了Qt4,通过find_package去查找下
- cmake文件内容
-
# 指定CMake最低版本 cmake_minimum_required(VERSION 3.16) # 构建项目的名称 project(findpackage) # 查找库 find_package(Qt4) if(Qt4_FOUND) Message("find Qt4 success") else() Message("find Qt4 failed") endif()
-
- 构建工程后,可以看到查找成功
- 那么cmake是如何找到Qt4库的,cmake首先会去安装目录下的
share/cmake-<version>/Modules
目录下查找一个Find<PackageName>.cmake
的文件,可以去这个目录下看看都有哪些文件。 - 可以看到有非常多的*.cmake文件,这是cmake安装时就会将一些常用的开源库的*.cmake文件放到这个目录下。
- 接下来把 FindQt4.cmake拷贝到D盘根目录下,再去构建工程。可以看到提示查找失败。
Config mode
- 在Config模式中,可以查找两种类型的文件。
- config:
<lowercasePackageName>-config.cmake
或者<PackageName>Config.cmake
- version:
<lowercasePackageName>-config-version.cmake
或者<PackageName>ConfigVersion.cmake
- config:
- 查找路径为
CMAKE_PREFIX_PATH
示例
-
生成*.cmake并调用
-
需要准备两个工程
-
工程一:生成动态库并导出*.cmake文件
- 目录结构
-
├── CMakeLists.txt ├── include │ └── dlib.h └── src └── dlib.cpp
- cmake文件内容
-
# 指定CMake最低版本 cmake_minimum_required(VERSION 3.16) # 构建项目的名称 project(create_package) # 包含头文件 include_directories(${PROJECT_SOURCE_DIR}/include) # 生成动态库 add_library(dlib SHARED ${PROJECT_SOURCE_DIR}/src/dlib.cpp) # 指定头文件 set_target_properties(dlib PROPERTIES PUBLIC_HEADER include/dlib.h) # 设置头文件路径 target_include_directories(dlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # install时为空, 只有编译时有值 $<INSTALL_INTERFACE:include> # 只有install时有值 ) # 安装目标项 install(TARGETS dlib EXPORT dlib # 标志导出Config.cmake文件 RUNTIME DESTINATION bin ARCHIVE DESTINATION bin PUBLIC_HEADER DESTINATION include # 导出头文件 ) install(EXPORT dlib FILE dlibConfig.cmake DESTINATION config # 指定生成的 Config.cmake 文件名和路径 )
- 命令
-
# 构建工程,并指定生成文件路径 cmake -DCMAKE_INSTALL_PREFIX=../out .. # 编译 cmake --build . --config Release # 安装 cmake --install . --config Release
- 安装完成后,可以看到指定目录下生成了对应的文件
- 下面通过工程二来调用生成的相关文件
-
工程二:通过*.cmake文件调用动态库
- 目录结构
-
├── CMakeLists.txt └── src └── main.cpp
- cmake文件内容
-
# 指定CMake最低版本 cmake_minimum_required(VERSION 3.16) # 构建项目的名称 project(findpackage) # 查找库 find_package(dlib) if(dlib_FOUND) Message("find dlib success") else() Message("find dlib failed") endif() # 包含头文件 include_directories(${PROJECT_SOURCE_DIR}/include) # 生成可执行程序 add_executable(findpackage ${PROJECT_SOURCE_DIR}/src/main.cpp) target_link_libraries(findpackage dlib)
- 命令
-
# 构建项目 # 工程一中生成的是Config类型的*.cmake文件,因此通过 CMAKE_PREFIX_PATH 来指定生成的*cmake文件路径。 cmake -DCMAKE_PREFIX_PATH=E:/setcmake_package/out/config .. # 编译 cmake --build . --config Release
- 可以看到,调用并执行成功
参考
- “轻松搞定CMake”系列之find_package用法详解