Cmake中find_package命令的搜索模式之配置模式(C
前面有介绍过find_package
的两种搜索模式之一模块模式(请参考Cmake命令之find_package介绍和模块模式),本文将介绍另外一种模式:配置模式。
一、配置模式下的.cmake
文件
该模式下,CMake
会搜索<lowercasePackageName>-config.cmake
文件或<PackageName>Config.cmake
文件。如果find_package
命令中指定了具体的版本,也会搜索<lowercasePackageName>-config-version.cmake
或<PackageName>ConfigVersion.cmake
文件,因此配置模式下通常会提供配置文件和版本文件(注意形式上要保持一致),并且作为包的一部分一起提供给使用者。
同样的,当find_package
调用返回时,一系列跟包相关的变量也会提供给调用者。例如<PackageName>_FOUND
标识包是否找到、<PackageName>_DIR
变量用于指示包配置文件所在的位置。实际上,返回的变量并没有特别的限制,但是还是建议遵循模块模式
的标准变量名称的命名规则。
二、配置模式的配置文件生成
一个配置文件方式提供的包由包配置文件
(必须包含,名为<lowercasePackageName>-config.cmake
文件或<PackageName>Config.cmake
)和包版本文件
(可选,名为<lowercasePackageName>-config-version.cmake
或<PackageName>ConfigVersion.cmake
)组成。配置文件和版本文件的命名要配对出现,也就是:
<lowercasePackageName>-config.cmake
<lowercasePackageName>-config-version.cmake
或者是:
<lowercasePackageName>Config.cmake
<lowercasePackageName>ConfigVersion.cmake
仍然是以我们自己编写的mymath
库为例,假设mymath
库提供了如下的文件:
/XXX/mymath/CMakeLists.txt
# 生成libmymath.a的cmake
配置
/XXX/mymath/mymath.h
/XXX/mymath/libmymath.a
/XXX/mymath/mymath/mymath/mymathConfig.cmake
/XXX/mymath/mymath/mymath/mymathConfigVersion.cmake
2.1 配置文件mymathConfig.cmake
mymathConfig.cmake
文件有两种方式可以生成:
- 在
CMake
中include(CMakePackageConfigHelpers)
,用CMakePackageConfigHelpers
提供的configure_package_config_file()来生成。 - 直接通过
set
设置对应的变量,本文采用这种方式提供,如下:
# mymath/mymath/mymathConfig.cmake
set(mymath_INCLUDE_DIR "/XXX/mymath")
set(mymath_LIBRARY "/XXX/mymath/libmymath.a")
可以参考Cmake命令之find_package介绍的4.1
章节查看.cmake
文件的搜索路径,我们的例子将在find_package
中通过PATHS
来指定。
2.2 版本文件mymathConfigVersion.cmake
find_package
找到一个配置文件后,会尝试去查找版本文件。版本文件的主要作用是用来验证包的版本是否与find_package
命令中指定的版本信息匹配。如果匹配的话,就会使用配置文件中的内容,否则会忽略配置文件中的内容。
和配置文件一样,版本文件也有两种方式生成:
- 在
CMake
中include(CMakePackageConfigHelpers)
,用CMakePackageConfigHelpers
提供的write_basic_package_version_file()来生成。我们的例子采用自动生成的方式,在mymath库生成的CMakeLists.txt
中添加:
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/mymath/mymathConfigVersion.cmake"
VERSION ${Inner_VERSION}
COMPATIBILITY AnyNewerVersion
)
- 自己手动写版本文件的校验规则。
当find_package
命令在加载版本文件时,首先会通过从find_package
中得到的版本信息设置如下变量,用于版本文件中版本对比:
-
PACKAGE_FIND_NAME
:包名 -
PACKAGE_FIND_VERSION
:全版本字符串 -
PACKAGE_FIND_VERSION_MAJOR
:主版本,默认值为0 -
PACKAGE_FIND_VERSION_MINOR
:次版本,默认为0 -
PACKAGE_FIND_VERSION_PATCH
:补丁版本,默认为0 -
PACKAGE_FIND_VERSION_TWEAK
:小版本,默认为0
在版本文件中可以使用上述变量来检查版本的兼容性、版本是否匹配,并设置如下变量作为返回结果:
-
PACKAGE_VERSION
:全版本字符串 -
PACKAGE_VERSION_EXACT
:版本是否精确匹配,True
表示精确匹配 -
PACKAGE_VERSION_COMPATIBLE
:版本是否兼容,True
表示兼容 -
PACKAGE_VERSION_UNSUITABLE
:版本是否合适,True
表示不合适
find_package
会检查上述变量,如果版本匹配成功,那么find_package
会返回如下变量给调用者:
-
<PackageName>_VERSION
:包的全版本字符串 -
<PackageName>_VERSION_MAJOR
:主版本 -
<PackageName>_VERSION_MINOR
:此版本 -
<PackageName>_VERSION_PATCH
:补丁版本 -
<PackageName>_VERSION_TWEAK
:小版本 -
<PackageName>_VERSION_COUNT
:点分版本组成的数量,范围0~4
2.3 生成自己的库
mymath
库的CMakeLists.txt
内容如下:
# /XXX/mymath/CMakeLists.txt
cmake_minimum_required (VERSION 3.18)
project (mymath)
set(Inner_VERSION 1.2.3.4)
add_library (mymath mymath.cpp)
set_property(TARGET mymath PROPERTY VERSION ${Inner_VERSION})
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/mymath/mymathConfigVersion.cmake"
VERSION ${Inner_VERSION}
COMPATIBILITY AnyNewerVersion
)
// /XXX/mymath/mymath.cpp
#include "mymath.h"
#include <iostream>
namespace mymath {
int add(int a, int b)
{
std::cout << "Add " << a << " and " << b << " is " << a + b << std::endl;
return a + b;
}
};
// /XXX/mymath/mymath.h
namespace mymath {
int add(int a, int b);
};
在命令行中执行cmake .
和make
生成libmymath.a
库。
三、完整的例子
mymath
库及其提供的.cmake
配置文件见本文的第二章节。下面来编写测试文件:
// /XXX/test.cpp
#include "mymath.h"
int main(int argc, char** argv)
{
mymath::add(1, 2);
return 0;
}
# 顶层的CMakeLists.txt:/XXX/CMakeLists.txt
cmake_minimum_required(VERSION 3.10.2)
project(find_package_test)
find_package(mymath 1.2.3.2...1.2.4.0
CONFIG
PATHS ./mymath/mymath
)
if(mymath_FOUND)
message("Find mymath: ${mymath_INCLUDE_DIR}; ${mymath_LIBRARY}")
add_executable(test test.cpp)
include_directories(${mymath_INCLUDE_DIR})
target_link_libraries(test ${mymath_LIBRARY})
endif()
在命令行中执行cmake .
和make
生成test
可执行文件并执行./test
,对应的输出结果如下(摘取重要部分呈现):
# 命令行中执行 cmake .的打印
Find mymath: /XXX/mymath; /XXX/mymath/libmymath.a;
#命令行中执行make,得到可执行文件test,并执行test
./test
Add 1 and 2 is 3