cmake随笔
cmake
cmake命令使用
##配置project
cmake [<options>] <path-to-source>`
常用选项:
-S <path-to-source>:指定源文件根目录
-B <path-to-build>:指定构建文件目录
-G <generator-name>:指定生成器。具体支持哪些生成器可用
-DCMAKE_BUILD_TYPE=Debug :配置debug版
-DCMAKE_BUILD_TYPE=Release :配置release版
#如果使用默认生成器,则-G这部分可以省略,具体支持哪些生成器可以用cmake --help查看,设置环境变量**CMAKE_GENERATOR**可以指定默认生成器,简化cmake命令的执行
##构建project
cmake --build <dir> [<options>] [-- <build-tool-options>]
<dir>为上述生成了构建文件的目录。生成器对应的构建工具来构建项目
-j [<jobs>], --parallel [<jobs>]:指定构建时的线程数,可以开启多线程构建提升速度
-t <tgt>..., --target <tgt>...:指定构建目标。
--clean-first:构建前先clean
#eg:
cmake --build .#通用
cmake . -DUSE_MYMATH=OFF #指定特定的变量值
# 指定构建目标为install
cmake --build . --target install
## 安装project
cmake --install <dir> [<options>]
dir为项目构建目录
options安装选项
--config <cfg> 对于多配置的项目,用于指定需要安装的配置
--prefix <prefix> 指定安装目录
eg:
cmake --install . --prefix "/path/to/your/installdir"
## 运行脚本
cmake -P <cmake-script-file>
项目
添加cmake最低版本要求
cmake_minimum_required
用于指定所需cmake最低版本
用法与示例:
# 用法
cmake_minimum_required(VERSION <版本号>)
# 示例
cmake_minimum_required(VERSION 3.10)
如果当前使用的cmake版本低于所指定的版本,则会报错并且终止执行。
添加项目名和版本号
project
- project
定义项目名和版本号
project(<项目名> VERSION <版本号>)
添加子目录
-
add_subdirectory
为当前项目添加子目录。子目录当中必须包含一个CMakeLists.txt文件,其中可以不写cmake_minimum_required与project。
用法与示例:
# 用法 add_subdirectory(<source_dir>) # 示例 add_subdirectory(MathFunctions)
生成库
-
add_library
用指定的源文件生成库文件。
用法与示例:
# 用法 add_library(<name> [<source>...]) # 示例 add_library(MathFunctions mysqrt.cxx MathFunctions.h) #生成动态库 add_library(MathFunctions SHARED mysqrt.cxx ${CMAKE_CURRENT_BINARY_DIR}/Table.h )
使用
add_library(<libname> INTERFACE)
可以创建个Interface库,这样的库并不是真实存在的,是一个虚拟的库,通常用来传递一些选项。用法和正常的库一样,可通过target_link_libraries
链接到目标,可以向指定的目标传递一些指定的参数选项。# TODO 1: 将下面的代码替换为: # * 创建一个interface库tutorial_compiler_flags # Hint: use add_library() with the INTERFACE signature # * 添加编译特性cxx_std_11到tutorial_compiler_flags # Hint: Use target_compile_features() add_library(tutorial_compiler_flags INTERFACE) target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_14)
生成可执行文件
add_executable
利用指定的源文件在项目中添加可执行文件
用法与示例:
# 用法 源文件可以有多个,用空格隔开
add_executable(<可执行文件名> <源文件列表>)
# 示例 可执行文件名为Tutorial,用到的源文件为tutorial.cxx
add_executable(Tutorial tutorial.cxx)
添加自定义命令
add_custom_command
执行自定义指令。
简版用法
add_custom_command(OUTPUT output1
COMMAND command1
DEPENDS depends)
OUTPUT
指定输出文件名COMMAND
指定要执行的指令DEPENDS
执行指令需要依赖的内容。如果是由add_executable
或add_library
添加的目标名,写这一条可以保证对应目标的生成。
添加cmake文件和模块
include
用于导入其他CMake文件或模块。
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
[NO_POLICY_SCOPE])
eg:
include(CheckCXXSourceCompiles)
include(InstallRequiredSystemLibraries)
添加c++标准
1.set
用于给变量设置值
用法与示例:
# 用法
set(<变量名> <变量值>)
# 示例
set(CMAKE_CXX_STANDARD 26)
set(SRC_DIR /home/src)
2.CMAKE_CXX_STANDARD
变量,用于指定C++标准
用法与示例:
# 用法 截止2023/6 std_num∈{98,11,14,17,20,23,26}
set(CMAKE_CXX_STANDARD <std_num>)
# 示例
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
在C++中可以通过输出__cplusplus查看当前编译器所用的标准
__cplusplus的值 对应的C++标准 199711 C++98 201103 C++11 201402 C++14 201703 C++17 202002 C++20 202100 C++23
3.CMAKE_CXX_STANDARD_REQUIRED
变量,如果设置为True,则通过CMAKE_CXX_STANDARD设置的C++标准是必需的,如果编译器不支持该标准则会输出错误提示信息。如果不设置或者设置为False,则CMAKE_CXX_STANDARD设置的C++标准不是必需的,如果编译器不支持对应的标准,则会使用上一个版本的标准进行编译。
用法与示例:
set(CMAKE_CXX_STANDARD_REQUIRED True)
添加测试
- enable_testing()
开启当前目录及子目录的测试支持。
- add_test
添加一条测试
简版用法:
add_test(NAME <name> COMMAND <command> [<arg>...])
name
为本条测试名称command
测试用的命令arg
传递测试命令的参数
- set_tests_properties
设置测试的属性。
语法
set_tests_properties(test1 [test2...] PROPERTIES prop1 value1 prop2 value2)
test1...
为用add_test添加的测试名prop1
为需要设置的属性名,本节中只学PASS_REGULAR_EXPRESSION
,表示测试程序的输出结果需要能匹配value
所表示的正则表达式才能通过,如果匹配不了则不通过。value
要设置的属性值
示例
set_tests_properties(Usage
PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
)
表示运行Usage
这个测试时测试程序的输出结果要能正则匹配到"Usage:.*number"。
- function()与endfunction()
用于在定义函数,分别表示函数开始与函数结束
语法
function(<name> [<arg1> ...])
<commands>
endfunction()
- 括号里第一个参数为函数名,后面是参数列表,可以有多个,多个参数用空格隔开
示例:
# 定义
function(do_test target arg result)
add_test(NAME Comp${arg} COMMAND ${target} ${arg})
set_tests_properties(Comp${arg}
PROPERTIES PASS_REGULAR_EXPRESSION ${result}
)
endfunction()
# 调用
do_test(Tutorial 4 "4 is 1")
- 测试调用
-
查看测试
ctest -N .
-
调用测试
ctest -VV
添加cmakelist与cpp文件数据共通的头文件
- configure_file
输入文件默认路径为CMakeLists.txt所在的路径,输出文件的路径默认为cmake生成文件所在的路径。
用法与示例:
# 用法
configure_file(<inputfile> <outputfile>)
# 示例
configure_file(TutorialConfig.h.in TutorialConfig.h)
在输入文件中,用宏定义的方式对变量进行定义
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR ${Tutorial_VERSION_MINOR}
// 因为CMakeLists.txt中定义的字符串都是裸的,所以如果一个变量的值为字符串,需要用双引号包起来
#define STR_VAR "@STR_VAR@"
上述定义中@Tutorial_VERSION_MAJOR@、${Tutorial_VERSION_MINOR}、@STR_VAR@在输出文件中会被替换为CMakeLists.txt中定义的对应变量值。
添加系统特性检测
check_cxx_source_compiles
检查给定的C++代码能不能编译及链接成可执行文件。通常用来检查当前环境中是否具有某些特性。
用法
check_cxx_source_compiles(<code> <resultVar> [FAIL_REGEX <regex1> [<regex2>...]])
code
为需要检查的代码,需要包含main
函数resultVar
为检查结果,如果成功返回布尔真,否则返回布尔假FAIL_REGEX
如果提供,则返回为假的结果需要能匹配上对应的正则表达式
如何打包
发布程序可以有多种形式,比如安装包、压缩包、源文件等。CMake也提供了打包程序cpack
可将程序打包成多种形式。
只需要在顶层CMakelists.txt中添加以下代码
include(InstallRequiredSystemLibraries)
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)
在项目构建完成之后,可以直接执行
cpack
在Windows上默认情况会打包成.exe文件,所以需要先安装一个exe打包程序NSIS(Null Soft Installer)
NSIS下载地址:https://sourceforge.net/projects/nsis/
也可以指定生成器打包成对应的格式
cpack -G ZIP # 打包成ZIP
具体生成器各类可以通过cpack --help
查看
对于多配置项目,可以指定打包配置
cpack -C Debug # 打包Debug版本
也可以打包源代码
cpack --config CPackSourceConfig.cmake
如何导出一个用CMake管理的库
第一步 将目标安装添加导出,EXPORT
可以生成一个MathFunctionsTargets.cmake
的文件,里面描述了此处安装的这些目标的一些导出配置。
MathFunctions/CMakeLists.txt
install(TARGETS ${installable_libs}
EXPORT MathFunctionsTargets
DESTINATION lib)
第二步 要让导出文件配置的路径对其他项目也可用,而不是绑定当前项目路径,需要修改头文件搜索路径,构建时和安装后为不同值
MathFunctions/CMakeLists.txt
target_include_directories(MathFunctions
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>
)
第三步 安装生成的MathFunctionsTargets.cmake
MathFunctions/CMakeLists.txt
install(EXPORT MathFunctionsTargets
FILE MathFunctionsTargets.cmake
DESTINATION lib/cmake/MathFunctions
)
第四步 准备MathFunctionsConfig.cmake
文件模板与生成
用CMake管理的库需要用find_package
进行导入,为了让find_package
能正确找到对应的库,需要再准备一个MathFunctionsConfig.cmake
文件,通常由模板生成,模板格式固定,内容如下
MathFunctions/Config.cmake.in
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )
由configure_package_config_file
根据模板生成MathFunctionsConfig.cmake
文件。
MathFunctions/CMakeLists.txt
include(CMakePackageConfigHelpers)
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
INSTALL_DESTINATION "lib/cmake/example"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
第五步 生成版本文件(非必需)
MathFunctions/CMakeLists.txt
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
COMPATIBILITY AnyNewerVersion
)
第六步 安装生成文件
MathFunctions/CMakeLists.txt
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
DESTINATION lib/cmake/MathFunctions
)
目标
添加头文件搜索路径
- target_include_directories
添加头文件目录,给指定的目标添加头文件搜索路径
# 用法
target_include_directories(<target> <INTERFACE|PUBLIC|PRIVATE> <dir1 dir2 ...>)
# 示例
target_include_directories(Tutorial PUBLIC ${PROJECT_BINARY_DIR})
有些时候需要让源代码能访问CMakeLIsts.txt当中的数据,比如说在CMakeLists.txt中定义版本号之后,希望能在源程序中对版本号进行输出。本节内容为如何让源代码中能访问CMakeLists.txt中的变量数据。
CMakeLists.txt
# TODO 1: 设置CMake最低版本要求为 3.10
cmake_minimum_required(VERSION 3.10)
# TODO 2: 创建一个名为Tutorial的项目
project(Tutorial VERSION 11.25)
# TODO 7: 用上面project命令将项目版本设为 1.0
# TODO 6: 设置变量 CMAKE_CXX_STANDARD 为 11
# CMAKE_CXX_STANDARD_REQUIRED 为 True
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# set(STR_TEST "Hello World")
# TODO 8: 用 configure_file 复制 TutorialConfig.h.in 生成
# TutorialConfig.h
configure_file(TutorialConfig.h.in TutorialConfig.h)
# TODO 3: 为项目添加一个叫做 Tutorial 的可执行文件
# Hint: 一定要指定源文件 tutorial.cxx
add_executable(Tutorial tutorial.cxx)
# TODO 9: 用 target_include_directories 添加头文件搜索目录 ${PROJECT_BINARY_DIR}
# PUBLIC PRIVATE INTERFACE
target_include_directories(Tutorial PUBLIC ${PROJECT_BINARY_DIR})
TutorialConfig.h.in
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
-
PUBLIC | INTERFACE | PRIVATE
在使用
target_include_directories
和target_link_libraries
添加搜索目录时,有三个修饰符PUBLIC | INTERFACE | PRIVATE
,其含义如下:PUBLIC:当前目标和以当前目标为依赖的目标都能能使用添加的目录,都能在对应的目录中进行搜索
PRIVATE:只有当前目标能使用添加的目录,以当前目标为依赖的目标不能使用
INTERFACE:以当前目标为依赖的目标需要使用添加的目录,但当前目标不需要用这种方式添加对应搜索目录时用INTERFACE。
添加指定库
-
target_link_libraries
指定需要链接的库(libXXX.a libXXX.dll直接写成XXX的形式即可)
用法与示例:
# 用法 target_link_libraries(<target> ... <item>... ...) # 示例 target_link_libraries(Tutorial PUBLIC MathFunctions)
-
target_link_directories
设置库文件搜索位置
eg:
target_link_libraries(Tutorial PRIVATE MathFunctions)
cmake引入第三方库的方法
- 正常使用库的方法
cmake_minimum_required(VERSION 3.10)
project(Tutorial)
add_executable(Tutorial tutorial.cxx)
set(mathlib_DIR C:/Users/YAN/Desktop/cmake/mathlib)
# cmake中使用第三方库的一般步骤
# 1. 设置头文件位置
target_include_directories(Tutorial PRIVATE "${mathlib_DIR}/include")
# 2. 设置库文件搜索位置
target_link_directories(Tutorial PRIVATE "${mathlib_DIR}/lib")
# 3. 指定需要链接的库(libXXX.a libXXX.dll直接写成XXX的形式即可)
target_link_libraries(Tutorial PRIVATE MathFunctions)
cmake使用cmake管理的库
cmake_minimum_required(VERSION 3.10)
project(Tutorial)
add_executable(Tutorial tutorial.cxx)
# 如果库是安装在环境变量里有的位置,这行可以不用写
# set(MathFunctions_DIR C:/Users/YAN/Desktop/cmake/mathlib/lib/cmake/MathFunctions)
find_package(MathFunctions REQUIRED)
target_link_libraries(Tutorial PRIVATE MathFunctions)
添加编译特性
- target_compile_features
target_compile_features
是 CMake 用来指定编译器特性的命令。它可以用来指定编译器需要支持的 C++ 标准或者其他编译器特性。具体支持的特性取决于编译器版本和 CMake 版本。
语法与示例
target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
# 示例
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
以下是一些常见的特性:
cxx_std_11
:指定 C++11 标准。cxx_std_14
:指定 C++14 标准。cxx_std_17
:指定 C++17 标准。cxx_std_20
:指定 C++20 标准。cxx_constexpr
:启用 C++11 constexpr 函数。cxx_nullptr
:启用 C++11 nullptr 关键字。cxx_auto_type
:启用 C++11 auto 关键字。cxx_lambdas
:启用 C++11 lambda 表达式。cxx_range_for
:启用 C++11 range-based for 循环。cxx_override
:启用 C++11 override 关键字。cxx_final
:启用 C++11 final 关键字。
添加编译选项
- target_compile_options
给指定的目标添加编译选项。
语法及示例:
target_compile_options(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
# 示例
target_compile_options(Tutorial PUBLIC -std=c++11 -Wunused)
添加编译器宏定义
- target_compile_definitions
为指定可执行文件及库文件这类目标添加编译器定义,用来控制代码中的条件编译。有点类似于#cmakedefine
与configure_file
的作用,但这两个操作的结果会生成一个文件再进行引用,而target_compile_definitions
不会生成文件。
用法
target_compile_definitions(<target>
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
示例
target_compile_definitions(MathFunctions PRIVATE "HAVE_LOG" "HAVE_EXP")
添加安装规则
install
用于定义安装规则。
语法与示例(简洁版)
# 安装生成的目标文件
install(TARGETS <目标名列表> DESTINATION <安装位置>)
# 安装其他文件
install(FILES <文件列表> DESTINATION <安装位置>)
安装多个文件时,用空格隔开。安装位置是相对于CMAKE_INSTALL_PREFIX
的,CMAKE_INSTALL_PREFIX
是安装时的默认路径,可以自行用set
设置。