hallnakulaos

导航

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_executableadd_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)

添加测试

  1. enable_testing()

开启当前目录及子目录的测试支持。

  1. add_test

添加一条测试

简版用法:

add_test(NAME <name> COMMAND <command> [<arg>...])
  • name为本条测试名称
  • command测试用的命令
  • arg传递测试命令的参数
  1. 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"。

  1. 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")
  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_directoriestarget_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

为指定可执行文件及库文件这类目标添加编译器定义,用来控制代码中的条件编译。有点类似于#cmakedefineconfigure_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设置。

posted on 2023-08-16 23:45  想写文章的路人甲  阅读(26)  评论(0编辑  收藏  举报