当前位置:   article > 正文

【Linux之·工程构建·Cmake】

【Linux之·工程构建·Cmake】

系列文章目录



前言

CMake是一个用于构建、测试和打包软件的跨平台构建工具。 它通过生成平台特定的构建文件(如Makefile、Visual Studio项目文件等),来协助开发者管理项目的构建过程。

CMake的作用和重要性:

1. 跨平台性: CMake可以在不同的操作系统和编译器之间进行无缝切换。它支持多种平台,如Windows、Mac、Linux等,而且可以使用不同的构建系统,比如Make、Ninja、Visual Studio等。
 
2. 自动化构建流程: CMake可以自动化处理构建过程的繁琐任务。通过定义CMakeLists.txt文件,开发者可以指定源代码文件的位置、依赖库的链接方式、编译选项等,从而简化了项目的构建和管理。
 
3. 灵活性和可定制性: CMake提供了丰富的命令和选项,使得开发者可以根据项目的需求进行灵活的配置和定制。开发者可以定义自己的构建选项、生成不同类型的目标文件(如可执行文件、库文件、模块等),以及设置自己的编译规则等。
 
4. 多工程管理: CMake可以用于管理复杂的多工程项目。通过使用CMake的模块化机制,开发者可以将项目分为多个模块,并定义它们之间的依赖关系。这样可以提高代码的可维护性和复用性。
 
5. 良好的社区支持: CMake是一个开源项目,有着庞大的用户社区。这意味着开发者可以轻松地找到相关的文档、教程、示例代码和解决方案。此外,CMake还有许多第三方的扩展库和工具,可以进一步增强其功能和易用性。

学习CMake对于以下场景是必要的:

1. 跨平台开发: 在开发跨平台应用或库时,不同操作系统和编译器的构建方式存在差异。学习CMake可以帮助开发者编写通用的构建脚本,使代码可以在不同平台上进行编译和运行。
 
2. 多工程项目: 在开发大型项目时,通常会划分为多个模块或库。使用CMake可以管理这些模块之间的依赖关系,并确保它们以正确的顺序进行构建和链接。
 
3. 第三方库的使用: 许多软件项目需要使用第三方库。学习CMake可以帮助开发者正确地配置和链接这些库,以便项目能够使用它们的功能。
 
4. 编译选项的管理: 不同的编译器和操作系统有不同的编译选项和标志。学习CMake可以帮助开发者定义和管理这些选项,以确保代码在不同环境下能够正确地编译和运行。
 
5. 自动化构建流程: 手动进行构建和编译往往是繁琐的。学习CMake可以帮助开发者定义构建流程,并自动处理构建相关的任务,如编译、链接、测试和打包等。
 
6. 项目的可维护性: 使用CMake可以将项目的构建过程与代码分离,使构建逻辑更加清晰和可维护。这样,开发者可以更方便地修改、扩展和维护项目。


一、概述

  CMake是一个开源、跨平台的编译、测试和打包工具,它使用比较简单的语言描述编译、安装的过程,输出Makefile或者project文件,再去执行构建。大多数IDE都集成CMake,相比于makefile,CMake不需要依赖当前编译的平台,并且工作量相对较少,依赖关系更少出错。

CMake过程如下所示,其先生成Makefile文件再生成目标文件:
在这里插入图片描述

二、CMake的基本概念

2.1 CMake的工作原理和基本组成部分

工作原理:

CMake通过读取项目中的CMakeLists.txt文件来配置和生成构建脚本。这个脚本可以根据不同的平台、编译器和构建选项来生成所需的构建系统文件,如Makefile、Visual Studio解决方案、Xcode项目等。然后,可以使用生成的构建系统文件来编译、链接和打包项目。

基本组成部分如下:

CMakeLists.txt文件:

CMakeLists.txt文件是CMake的配置文件,用于描述项目的构建过程。它可以包含一系列的指令和命令,用于设置项目的编译参数、依赖关系、源文件列表等信息。

CMake命令

CMake提供了一系列的命令和变量,用于在CMakeLists.txt文件中配置项目的构建过程。这些命令可以用于设置项目的名称、版本号、编译选项、链接库、查找依赖等。

模块和宏:

CMake还提供了一些预定义的模块和宏,用于简化项目的配置过程。这些模块和宏可以用于查找特定的库、设置环境变量、定义函数等。

构建系统文件:

CMake根据CMakeLists.txt文件生成的构建系统文件用于实际的编译、链接和打包操作。这些文件可根据不同的平台和编译器生成,如Makefile、Visual Studio解决方案、Xcode项目等。

2.2 CMakeLists.txt文件的结构和语法

CMakeLists.txt文件是CMake的配置文件,用于描述项目的构建过程。它具有以下的结构和语法:

  1. 最小结构:
    一个最小的CMakeLists.txt文件包含以下两个部分:

    cmake_minimum_required(VERSION <version>)
    project(<project_name>)
    
    • 1
    • 2
  2. cmake_minimum_required命令:
    这个命令用于指定需要的CMake的最低版本,语法为:

    cmake_minimum_required(VERSION <version>)
    
    • 1
  3. project命令:
    这个命令用于定义项目的名称,语法为:

    project(<project_name>)
    
    • 1
  4. 设置变量:
    可以使用set命令来设置变量,语法为:

    set(<variable_name> <value>)
    
    • 1
  5. 添加子目录:
    如果项目包含子目录,可以使用add_subdirectory命令来添加子目录,语法为:

    add_subdirectory(<subdirectory>)
    
    • 1
  6. 设置编译类型和选项:
    可以使用set命令设置编译类型和选项,如:

    set(CMAKE_BUILD_TYPE <build_type>)
    set(CMAKE_CXX_FLAGS <flags>)
    
    • 1
    • 2
  7. 添加源文件:
    可以使用add_executable或add_library命令来添加源文件,语法为:

    add_executable(<executable_name> <source_files>)
    add_library(<library_name> <source_files>)
    
    • 1
    • 2
  8. 链接库:
    可以使用target_link_libraries命令来链接库,语法为:

    target_link_libraries(<target_name> <library_name>)
    
    • 1
  9. 定义函数和变量:
    可以使用function和set命令来定义函数和变量,语法为:

    function(<function_name> [ARG1 [ARG2 ...]])
       ...c
    endfunction()
    
    set(<variable_name> <value>)
    
    • 1
    • 2
    • 3
    • 4
    • 5
  10. 条件语句:
    可以使用if和else命令来进行条件判断,语法为:

    if(<condition>)
       ...
    elseif(<condition>)
       ...
    else()
       ...
    endif()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  11. 循环语句:
    可以使用foreach和while命令来进行循环操作,语法为:

    foreach(<variable> [IN [LISTS] [ITEMS] ...])
       ...
    endforeach()
    
    while(<condition>)
       ...
    endwhile()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  12. 指定c++使用标准:
    设置全局变量CMAKE_CXX_STANDARD:

    #增加-std=c++11
    set(CMAKE_CXX_STANDARD 11)
    #增加-std=c++14
    set(CMAKE_CXX_STANDARD 14)
    #增加-std=c++17
    set(CMAKE_CXX_STANDARD 17)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    执行CMake时使用-DCMAKE_CXX_STANDARD=xx选项

    #增加-std=c++11
    cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=11
    #增加-std=c++14
    cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=14
    #增加-std=c++17
    cmake CMakeLists.txt文件路径 -DCMAKE_CXX_STANDARD=17
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  13. 搜索文件:
    使用aux_source_directory 命令可以查找某个路径下的所有源文(.c 或 .cpp):

    #aux_source_directory(搜索路径 存储变量名)
    aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src SRC_LIST)
    #CMAKE_CURRENT_SOURCE_DIR 全局变量表示CMakeLists.txt所在路径
    
    • 1
    • 2
    • 3

    使用file搜索指定文件

    #file(GLOB/GLOB_RECURSE 存储变量名 搜索路径及文件类型)
    #GLOB: 仅在指定目录下搜索
    #GLOB_RECURSE:递归搜索
    file(GLOB SRC ${PROJECT_SOURCE_DIR}/src/*.cpp)
    # PROJECT_SOURCE_DIR 是 cmake命令后跟的路径
    
    • 1
    • 2
    • 3
    • 4
    • 5
  14. 制作库文件:

    add_library(库名称 STATIC/SHARED 源文件 [源文件2] ...)
    # STATIC:静态库 SHARED:动态库  
    
    • 1
    • 2

    指定库输出路径

    set(LIBRARY_OUTPUT_PATH 输出路径)
    
    • 1
  15. 链接库文件:

链接静态库
指定自定义链接文件所在的路径
link_directories(库路径)
# 注意是路径而不是库名
  • 1
  • 2
链接静态库
link_libraries(库名1 库名2)
# 系统静态库不需要指定路径 自定义静态库需要
  • 1
  • 2
链接动态库
 
target_link_libraries(目标文件 访问权限 库名1 访问权限 库名2)
# 系统静态库不需要指定路径 自定义静态库需要 同上
# 访问权限
# PUBLIC:库具有传递性,由目标文件链接得到的目标文件仍可以使用库文件
# PRIVATE:不具有传递性,目标文件可以使用库,但其传递的目标文件不能使用该库文件
# INTERFACE:非传递性,并且目标文件仅有库文件函数名(即只知道接口但无法得到具体内容)
# target_link_libraries要在目标文件生成命令之后使用
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 包含头文件:
    include_directories(头文件路径)
    
    • 1

2.2.1 变量操作

# 1.set
set(目标变量名 ${变量名1} ${变量名2} ...)

# 2.list添加到末尾
list(APPEND 待操作变量 ${变量名}/"字符串" ...)

# 3.移除某个元素
list(REMOVE_ITEM 待操作变量 ${变量名}/"字符串" ...)

# 4.获取子串个数
list(LENGTH 待操作变量 输出变量)

# 5.获取指定索引的元素
list(GET 待操作变量 索引1 索引2 ... 输出变量)
#索引从0开始编号,也可以是负数,-1表示列表的最后一个元素 
#索引超过列表的长度会报错

# 6.用指定连接符将列表中的元素连接起来组成一个字符串
list (JOIN 待操作变量 连接符 输出变量)
<list>:当前操作的列表
<glue>:指定的连接符(字符串)
<output variable>:新创建的变量,存储返回的字符串

# 7.查找列表是否存在指定的元素,若果未找到,返回-1
list(FIND 待操作变量 搜索元素 输出变量)

# 8.在指定的位置插入若干元素
list(INSERT 待操作变量 索引 元素1 元素2 ...)

# 9.将元素插入到列表的0索引位置
list (PREPEND 待操作变量 元素 ...)

# 10.将列表中最后元素移除
list (POP_BACK 待操作变量 输出变量 ...)

# 11.将列表中第一个元素移除
list (POP_FRONT 待操作变量 输出变量 ...)

# 12.将指定索引的元素从列表中移除
list (REMOVE_AT 待操作变量 索引1 索引2 ...)

# 13.移除列表中的重复元素
list (REMOVE_DUPLICATES 待操作变量)

# 14.列表翻转
list(REVERSE 待操作变量)

# 15.列表排序
list (SORT 待操作变量 [COMPARE <compare>] [CASE <case>] [ORDER <order>])
#[[COMPARE:指定排序方法。有如下几种值可选:
    STRING:按照字母顺序进行排序,默认
    FILE_BASENAME:如果是一系列路径名,会使用basename进行排序
    NATURAL:使用自然数顺序排序
CASE:指明是否大小写敏感。
    SENSITIVE:默认
    INSENSITIVE:按照大小写不敏感方式进行排序
ORDER:指定升降序。是升序
    ASCENDING:默认
    DESCENDING:降序
]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

2.2.2 注释

使用#进行单行注释,#[[ ]]进行多行注释
  • 1
#这是一个CMake单行注释

#[[
这是一个
多行注释
]]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.2.3 日志

message(消息等级 "消息内容" ...)
#[[
() :重要消息
STATUS :非重要消息
WARNING:警告, 会继续执行
AUTHOR_WARNING:警告 (dev), 会继续执行
SEND_ERROR:错误, 会继续执行,跳过生成的步骤
FATAL_ERROR:错误, 终止
]]
########################################################
string(ASCII 27 Esc)

set(R "${Esc}[31;1m")
set(E "${Esc}[0m")

message("${R}红色内容${E} 默认颜色")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2.2.4 宏定义

在CMake中,可以使用add_definitions命令来定义宏。该命令将在所有目标中添加编译选项,以定义宏。

下面是一个示例,展示如何在CMake中定义宏:

# 定义一个宏
add_definitions(-DDEBUG)

# 定义一个带有数值的宏
add_definitions(-DVERSION=1)

# 定义一个带有字符串值的宏
add_definitions(-DMESSAGE="Hello, World!")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在上面的示例中,add_definitions命令用于定义不同的宏。通过在命令中使用-D选项,可以指定要定义的宏的名称、数值或字符串值。这些宏在编译时将被替换为相应的值。

为了在代码中使用这些宏,可以在源文件中使用#ifdef语句来判断宏是否被定义,以及使用宏的值:

#ifdef DEBUG
  // 宏已定义,执行相应的代码
#endif

#ifdef VERSION
  // 使用宏的值
  int version = VERSION;
#endif

#ifdef MESSAGE
  // 使用宏的值
  std::cout << MESSAGE << std::endl;
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在上面的示例中,#ifdef语句用于检查宏是否被定义。如果宏已定义,则执行相应的代码块。

2.3 CMakeLists.txt文件的作用

CMakeLists.txt文件是CMake工具的配置文件,它的主要作用是描述项目的构建过程和依赖关系,并生成适合不同平台和编译器的构建系统。

具体来说,CMakeLists.txt文件的作用包括:

1. 定义项目的名称和版本号: 通过project命令,可以指定项目的名称和版本号,方便项目的标识和管理。

2. 设置编译选项和参数: 通过set命令,可以设置编译器的选项和参数,例如编译类型、编译器标志等。

3. 添加源代码目录和文件: 通过add_subdirectory和add_executable命令,可以将子目录和源代码文件添加到项目中,告诉CMake如何构建项目。

4. 链接库和依赖项: 通过target_link_libraries命令,可以指定项目所需的链接库和依赖项,确保项目能够正确编译和运行。

5. 定义宏和函数: 通过define_property和function命令,可以定义宏和函数,方便在CMakeLists.txt文件中重复使用代码逻辑。

6. 条件判断和循环控制: 通过if、elseif、else和foreach命令,可以在CMakeLists.txt文件中进行条件判断和循环控制,使构建过程更加灵活和可定制。

三、CMake的常用命令和变量

3.1 常用的CMake命令和变量

常用命令:

命令描述
cmake_minimum_required(VERSION)指定CMake的最低版本要求。
project(name)指定项目的名称。
add_executable(name source_files)添加一个可执行文件,并指定源文件。
add_library(name source_files)添加一个库文件,并指定源文件。
target_link_libraries(target libraries)指定目标文件需要链接的库文件。
include_directories(directory)指定头文件的搜索路径。
link_directories(directory)指定库文件的搜索路径。
set(variable value)设置变量的值。
find_package(package)查找指定的第三方库。
aux_source_directory(directory variable)查找某个路径下的所有源文(.c 或 .cpp)
include(sources.cmake)为了保持CMakeLists.txt文件的清晰和可维护性,我们可以将源文件列表放在一个单独的文件中,然后在CMakeLists.txt文件中包含它。

常用变量:

变量描述
CMAKE_SOURCE_DIR项目根目录的路径。
CMAKE_BINARY_DIR工程编译时存放二进制文件的目录。
CMAKE_CXX_COMPILERC++编译器的路径。
CMAKE_C_COMPILERC语言编译器的路径。
CMAKE_CURRENT_SOURCE_DIR当前源文件所在的目录。
CMAKE_CURRENT_BINARY_DIR当前编译文件所在的目录。
CMAKE_INCLUDE_PATH头文件搜索路径。
CMAKE_LIBRARY_PATH库文件搜索路径。
CMAKE_INSTALL_PREFIX安装目录的路径。
CMAKE_CURRENT_SOURCE_DIR全局变量表示CMakeLists.txt所在路径。
EXECUTABLE_OUTPUT_PATH生成的可执行文件的输出路径
LIBRARY_OUTPUT_PATH指定生成库输出路径
CMAKE_CXX_STANDARD指定c++使用标准
CMAKE_CXX_FLAGS用于设置C++编译器的编译选项。
CMAKE_INCLUDE_DIRECTORIES_BEFORE将添加的头文件搜索路径放在已有路径的前面。
CMAKE_INCLUDE_DIRECTORIES_ AFTER将添加的头文件搜索路径放在已有路径的后面。
CMAKE_MODULE_PATH定义自己的 cmake模块所在的路径
BUILD_SHARED_LIBS控制库的默认编译方式
­DCMAKE_BUILD_TYPE置构建类型,类型选项有Debug/Release。当使用GDB调试工程时要使用Debug选项。该变量可以通过命令行:cmake ­DCMAKE_BUILD_TYPE=Release或指令SET(CMAKE_BUILD_TYPE [type])设置。

3.1.1 字符串处理指令string

在CMake中,string 指令提供了一系列的操作来处理字符串。这些操作包括但不限于比较、替换、连接、长度计算等等。

  • 转换
    • 数字/字符互转
      • 将ASCii码转为对应的字符,如65转为A,66转为B
        string(ASCII <number> [<number> ...] <output_variable>)
        
        • 1
      • 将转换为对应的16进制ASii码,如A转为61(61为A十六进制ascii)
        string(HEX <string> <output_variable>)
        
        • 1

3.1.2 向终端输出信息指令message

message([<mode>] "message text" ...)函数的<mode>参数可以是以下之一:
  • 1
  • (none): 等同于STATUS,但不推荐使用。
  • STATUS: 输出的信息会被发送到CMake的状态消息流,这是message()函数的默认模式。在命令行上,这些消息通常会被显示出来,但在图形界面中,它们可能会被重定向到其他地方。
  • WARNING: 输出的信息会被发送到CMake的警告消息流。这些消息会被显示出来,并且会标记为警告。
  • AUTHOR_WARNING: 这是WARNING模式的一种变体,只有在CMAKE_SUPPRESS_DEVELOPER_WARNINGS变量为FALSE时才会产生警告。
  • SEND_ERROR: 输出的信息会被发送到CMake的错误消息流,但不会立即停止CMake的处理过程。
  • FATAL_ERROR: 输出的信息会被发送到CMake的错误消息流,并立即停止CMake的处理过程。
参数使用场景底层原理优点缺点
(none)当你想输出一条普通的状态消息,但不希望给它指定任何特殊的模式时输出的信息会被发送到CMake的状态消息流。简单易用,不需要指定模式。不推荐使用,因为它的行为可能会在未来的CMake版本中改变。
STATUS当你想输出一条状态消息,例如进度信息或配置信息时。输出的信息会被发送到CMake的状态消息流。明确表示这是一条状态消息,易于理解。在图形界面中,这些消息可能会被重定向到其他地方,不一定能被用户看到。
WARNING当你想输出一条警告消息,例如某个选项已被弃用或某个操作可能会失败时。输出的信息会被发送到CMake的警告消息流。明确表示这是一条警告消息,可以引起用户的注意。过多的警告消息可能会让用户感到困扰,忽视真正重要的警告。
AUTHOR_WARNING当你是项目的开发者,并且你想输出一条只有在开发模式下才会显示的警告消息时。输出的信息会被发送到CMake的
警告消息流,但只有CMAKE_SUPPRESS_
DEVELOPER_WARNINGS变量为FALSE时才会产生警告。
可以避免在用户模式下显示不必要的警告。如果CMAKE_
SUPPRESS_
DEVELOPER_
WARNINGS变量
被设置为TRUE,
这些警告会被忽略。
SEND_ERROR当你遇到一个错误,但你希望CMake继续处理剩下的命令时。输出的信息会被发送到CMake的错误消息流,但不会立即停止CMake的处理过程。可以在发生错误时继续执行CMake的处理过程。由于CMake的处理过程没有立即停止,可能会导致更多的错误。
FATAL_ERROR当你遇到一个严重的错误,你希望立即停止CMake的处理过程时。输出的信息会被发送到CMake的错误消息流,并立即停止CMake的处理过程。可以在发生严重错误时立即停止CMake的处理过程,防止错误的扩散。一旦使用,CMake的处理过程会立即停止,无法执行任何后续的命令。

3.2 命令和变量的作用和用法常见用法示例

cmake_minimum_required(VERSION 3.10)
project(MyProject)

add_subdirectory(utils)
add_executable(MyApp main.cpp helper.cpp)
target_link_libraries(MyApp MyLibrary)

include_directories(include)
add_library(MyLibrary utils.cpp helper.cpp)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这个示例告诉CMake最低需要版本3.10,并且定义了一个名为MyProject的项目。然后,它添加了一个名为utils的子目录,然后在子目录中可能有另一个独立的CMakeLists.txt来构建utils子项目。接下来,它创建一个可执行文件MyApp,编译main.cpp和helper.cpp这两个源文件,并将库MyLibrary链接到它上面。最后,它将include目录添加到包含路径,并创建一个名为MyLibrary的库,编译utils.cpp和helper.cpp这两个源文件。

3.3 CMake中的变量和函数的使用方法

在CMake中,有两种类型的变量:全局变量和局部变量。全局变量可以在整个项目中使用,而局部变量仅在特定的范围内有效,例如在一个函数内部。

  • 设置变量的值:

    • 使用set命令可以设置变量的值。语法为set(<variable> <value>)。例如,set(SRC_FILES main.cpp helper.cpp)将变量SRC_FILES设置为main.cpphelper.cpp
    • 使用list命令可以将多个值放入一个变量中。语法为list(APPEND <list_variable> <value1> <value2> ...)。例如,list(APPEND SRC_FILES main.cpp helper.cpp)main.cpphelper.cpp添加到SRC_FILES变量中。
  • 访问变量的值:

    • 使用${<variable>}语法可以访问变量的值。例如,${SRC_FILES}表示变量SRC_FILES的值。
    • 使用set(<variable>)命令可以通过将变量传递给set命令来获取变量的值。例如,set(SRC_FILES)中的SRC_FILES将获得SRC_FILES变量的值。
  • 函数的使用:

    • CMake提供了许多有用的内置函数,可以在CMakeLists.txt文件中使用。例如,add_executableadd_library就是内置函数。
    • 可以使用function命令创建自定义函数。函数可以接受参数并执行一些操作。语法为function(<function_name> [arg1 [arg2 ...]])。例如,function(print_message MESSAGE)定义了一个名为print_message的函数,它接受一个参数MESSAGE
    • 使用${<variable>}语法可以访问函数参数的值。

以一个示例说明变量和函数的使用方法:

set(MY_NAME "Alice")
set(SRC_FILES main.cpp helper.cpp)

function(print_message MESSAGE)
  message("Hello, ${MESSAGE}!")
endfunction()

message("My name is ${MY_NAME}")
message("Source files: ${SRC_FILES}")

print_message("Bob")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这个例子中,首先设置了两个变量MY_NAMESRC_FILES。然后定义了一个名为print_message的函数,它接受一个参数MESSAGE并打印出一个消息。最后,使用message命令打印出变量MY_NAMESRC_FILES的值,并调用print_message函数打印出一个消息。

运行以上示例的CMakeLists.txt,将会输出以下内容:

My name is Alice
Source files: main.cpp;helper.cpp
Hello, Bob!
  • 1
  • 2
  • 3

三、构建和安装

3.1 CMake的构建流程和常用选项

CMake的构建流程通常如下:

  1. 创建一个构建目录,该目录用于存储生成的构建系统文件和构建产物,与源代码目录分开。
     
  2. 在构建目录中运行cmake命令,指定源代码目录的路径。例如:cmake /path/to/source
     
  3. CMake会解析源代码目录中的CMakeLists.txt文件,并根据其中的指令和变量进行配置。
     
  4. CMake生成目标构建系统文件,如Makefiles、IDE项目文件等,根据所选的生成器确定。
     
  5. 使用生成的构建系统文件进行构建,如使用Make工具运行make命令或使用IDE进行构建。
选项描述
-H用于指定CMakeLists.txt文件所在的目录。
-D用于定义一个CMake变量。它允许您在命令行中传递变量值给CMake,而无需修改CMakeLists.txt文件。
-G用于指定生成器的名称。生成器用于生成适合特定平台或开发环境的构建系统文件(如Makefiles、IDE项目文件等)。例如,cmake -G "Ninja" ..将使用Ninja生成器来生成构建系统文件。
-C用于指定一个预定义的CMake缓存文件。缓存文件中可以包含预先定义的变量和选项。例如,cmake -C mycache.cmake ..将使用mycache.cmake中定义的变量进行配置。
-B用于指定生成构建系统文件的目录。该目录通常是一个单独的构建目录,与源代码目录分开。例如,cmake -B build ..将在build目录中生成构建系统文件。
-S用于指定源代码目录。这是源代码存储的目录,其中包含CMakeLists.txt文件。例如,cmake -S myproject ..将在myproject目录中搜索CMakeLists.txt文件。

-D是CMake的一个选项,用于定义一个CMake变量。它允许您在命令行中传递变量值给CMake,而无需修改CMakeLists.txt文件。

使用-D选项的一般语法是:-D<variable>=<value>。其中,<variable>是你要定义的变量名,<value>是你要为该变量设置的值。

例如,假设有一个名为DEBUG_MODE的变量,您可以使用-D选项来定义它的值,如下所示:

cmake -DDEBUG_MODE=ON ..
  • 1

在CMakeLists.txt文件中,您可以使用${DEBUG_MODE}来引用该变量。例如,您可以在CMakeLists.txt文件中使用if语句来根据DEBUG_MODE变量的值执行不同的操作:

if(DEBUG_MODE)
    message("Debug mode is enabled.")
else()
    message("Debug mode is disabled.")
endif()
  • 1
  • 2
  • 3
  • 4
  • 5

通过使用-D选项,您可以通过命令行轻松地传递变量值给CMake,以便进行自定义配置,而无需手动编辑CMakeLists.txt文件。

3.2 如何使用CMake进行构建和安装项目

使用CMake进行构建和安装项目的一般流程如下:

  1. 创建一个构建目录,用于存储生成的构建系统文件和构建产物。最好将构建目录与源代码目录分开。

  2. 进入构建目录,并运行cmake命令来配置项目。可以使用以下命令:

    cmake /path/to/source
    
    • 1

    或者,如果想指定生成器和其他选项:

    cmake -G "GeneratorName" -DCMAKE_INSTALL_PREFIX=/path/to/install /path/to/source
    
    • 1

    上述命令中:

    • /path/to/source 是源代码目录的路径。
    • -G "GeneratorName" 是指定生成器的选项,例如使用Make生成器可以使用-G "Unix Makefiles",使用Ninja生成器可以使用-G "Ninja"
    • -DCMAKE_INSTALL_PREFIX=/path/to/install 是指定安装目录的选项,即项目构建完成后要安装到的目标路径。
  3. 运行makecmake --build命令来进行构建。例如:

    make
    
    • 1

    如果使用的是Ninja生成器,可以运行:

    cmake --build .
    
    • 1

    或者,如果希望使用多线程编译,可以使用-j选项。例如:

    make -j4
    
    • 1

    构建命令将根据生成的构建系统文件编译项目,并生成构建产物。

  4. 运行make install命令来安装项目到指定的安装目录。例如:

    make install
    
    • 1

    安装命令将把构建产物复制到指定的安装目录,以便在其他地方使用该项目。

完成上述步骤后,项目的构建和安装就完成了。可以根据具体的项目需要进行自定义配置和调整。

四、CMake的常用功能

4.1 编译源代码

4.1.1 指定源文件和头文件的位置

在CMake中指定源文件和头文件的位置有多种方法。以下是几种常用的方法:

  1. 使用add_executableadd_library命令:
add_executable(my_executable main.cpp other.cpp)
  • 1

这样做将会将main.cppother.cpp作为源文件添加到可执行文件my_executable中。

  1. 使用file命令:
file(GLOB SOURCES src/*.cpp)
file(GLOB HEADERS include/*.h)

add_executable(my_executable ${SOURCES} ${HEADERS})
  • 1
  • 2
  • 3
  • 4

这样做将会使用GLOB模式匹配指定文件夹下的所有.cpp文件和.h文件,并将它们添加到可执行文件my_executable中。

  1. 使用target_sources命令:
target_sources(my_executable PRIVATE main.cpp other.cpp)
  • 1

这样做将会将main.cppother.cpp作为源文件添加到可执行文件my_executable中。

对于头文件的指定,通常会使用include_directories命令或target_include_directories命令,以指定头文件搜索路径。例如:

include_directories(include)
  • 1

或者

target_include_directories(my_executable PRIVATE include)
  • 1

4.1.2 设置编译选项和链接库

在CMake中设置编译选项和链接库有多种方法。以下是几种常用的方法:

  1. 使用set命令设置编译选项:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
  • 1

这样做将会将编译选项-Wall-Wextra添加到默认的C++编译选项中。

  1. 使用target_compile_options命令设置目标的编译选项:
target_compile_options(my_executable PRIVATE -Wall -Wextra)
  • 1

这样做将会将编译选项-Wall-Wextra添加到目标my_executable的编译选项中。

  1. 使用target_link_libraries命令链接库:
target_link_libraries(my_executable PRIVATE my_library)
  • 1

这样做将会将库my_library链接到目标my_executable中。

对于编译选项和链接库的设置,可以在全局范围使用set命令,也可以在目标级别使用target_compile_optionstarget_link_libraries命令。根据具体的项目需求,你可以选择适合的方法来设置编译选项和链接库。


CMAKE_CXX_FLAGS 是一个CMake变量,用于设置C++编译器的编译选项。

CMake生成的Makefile或其他构建系统文件会在使用C++编译器编译源代码时使用CMAKE_CXX_FLAGS变量的值作为编译选项。

通过设置CMAKE_CXX_FLAGS变量,可以向编译器传递一些参数和选项,例如优化级别、警告选项等。

以下是一些常用的C++编译选项示例:

  • -Wall: 开启所有警告选项。
  • -Werror: 将所有警告视为错误。
  • -O2: 开启优化级别2。
  • -std=c++11: 指定使用C++11标准进行编译。

你可以通过在CMakeLists.txt文件中设置CMAKE_CXX_FLAGS变量的值来自定义编译选项,例如:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -O2")
  • 1

这将会将-Wall -Werror -O2这些选项添加到默认的C++编译选项中。

注意,CMAKE_CXX_FLAGS是一个全局变量,会影响整个项目中使用C++编译器的地方。如果你只想为特定的目标设置编译选项,你可以使用target_compile_options命令。

4.2 构建可执行文件、库文件和模块

在CMake中,可以使用add_executableadd_libraryadd_subdirectory来构建可执行文件、库文件和模块。

  1. 构建可执行文件:
    使用add_executable命令指定可执行文件的名称和源文件,如下所示:

    add_executable(my_exe main.cpp)
    
    • 1

    这将生成名为my_exe的可执行文件,该文件由main.cpp源文件构建而成。

  2. 构建库文件:
    使用add_library命令指定库文件的名称、库类型和源文件,如下所示:

    add_library(my_lib STATIC my_lib.cpp)
    
    • 1

    这将生成名为my_lib的静态库文件,该文件由my_lib.cpp源文件构建而成。你也可以使用SHARED关键字来构建共享库。

  3. 构建模块:
    使用add_subdirectory命令将一个子目录添加到构建中,该子目录包含一个CMakeLists.txt文件。这个子目录可以是一个模块,可以包含库、可执行文件等构建规则。

    add_subdirectory(my_module)
    
    • 1

    这将添加名为my_module的子目录,并在该目录的CMakeLists.txt文件中执行构建规则。

4.3 安装生成的文件到指定目录

在CMake中,可以使用install命令将生成的文件安装到指定的目录。

  1. 安装可执行文件:
    使用install命令指定要安装的可执行文件,以及安装目标的路径,如下所示:

    install(TARGETS my_exe DESTINATION bin)
    
    • 1

    这将把名为my_exe的可执行文件安装到bin目录下。

  2. 安装库文件:
    使用install命令指定要安装的库文件,以及安装目标的路径,如下所示:

    install(TARGETS my_lib DESTINATION lib)
    
    • 1

    这将把名为my_lib的库文件安装到lib目录下。

  3. 安装头文件:
    使用install命令指定要安装的头文件,以及安装目标的路径,如下所示:

    install(FILES my_header.h DESTINATION include)
    
    • 1

    这将把名为my_header.h的头文件安装到include目录下。

4.4 构建测试和运行测试

在CMake中,可以使用CTest来构建和运行测试。

  1. 创建测试:
    使用add_test命令添加测试。例如:

    add_executable(my_test my_test.cpp)
    add_test(NAME MyTest COMMAND my_test)
    
    • 1
    • 2

    这将创建一个名为MyTest的测试,并执行名为my_test的可执行文件。

  2. 运行测试:
    使用ctest命令运行测试。例如:

    ctest
    
    • 1

    这将运行所有配置好的测试。你也可以通过指定测试名称或者使用正则表达式来运行特定的测试。例如:

    ctest -R MyTest
    
    • 1

    此外,你还可以使用add_test命令的COMMAND选项来指定测试运行的具体命令,而不是使用可执行文件。这样可以更灵活地设置测试环境和参数。

注意: 在使用CTest之前,确保在你的项目中包含了如下语句:

include(CTest)
  • 1

这将使CTest相关的命令和变量可用。

有了这些设置,你就可以使用CMake和CTest方便地构建和运行测试了。

五、CMake的高级功能

5.1 CMake的高级功能,例如条件编译、依赖管理等

CMake提供了一些高级功能,帮助你更灵活地管理项目的条件编译和依赖管理。下面介绍一些常用的高级功能:

  1. 条件编译:
    使用if语句可以针对不同的条件选择编译选项。例如:

    if(CONDITION)
        # do something
    else()
        # do something else
    endif()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以使用DEFINEDNOTANDOR等条件运算符来组合条件。

  2. 依赖管理:
    使用find_package命令可以查找外部库的位置和版本,并将其添加到项目中。例如:

    find_package(OpenCV REQUIRED)
    target_link_libraries(my_project ${OpenCV_LIBS})
    
    • 1
    • 2

    这将查找OpenCV库,并将其链接到my_project可执行文件或库文件中。

  3. 外部项目管理:
    使用ExternalProject_Add命令可以在构建过程中下载和构建外部项目。例如:

    ExternalProject_Add(MyLibrary
        PREFIX ${CMAKE_CURRENT_BINARY_DIR}/external/MyLibrary
        GIT_REPOSITORY https://github.com/user/MyLibrary.git
        CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这将下载并构建名为MyLibrary的外部项目,并将其安装到指定的目录。

  4. 自定义编译选项:
    可以使用option命令创建自定义的编译选项。例如:

    option(ENABLE_FEATURE "Enable feature" ON)
    if(ENABLE_FEATURE)
        add_definitions(-DENABLE_FEATURE)
    endif()
    
    • 1
    • 2
    • 3
    • 4

    这将创建一个名为ENABLE_FEATURE的选项,用户可以通过设置-DENABLE_FEATURE=ON-DENABLE_FEATURE=OFF来决定是否启用某个特性。

这些只是CMake的一些高级功能的简介,CMake还提供了许多其他功能,如自定义函数和宏、生成器表达式、包装器等,可以帮助你更好地管理和构建项目。可以通过查阅CMake官方文档或参考各种CMake的教程来深入了解这些功能的使用方法。

5.2 示例和用法说明

下面是一些示例和用法说明,演示了CMake的高级功能:

  1. 条件编译示例:

    if(USE_CUDA)
        add_definitions(-DUSE_CUDA)
        find_package(CUDA REQUIRED)
        include_directories(${CUDA_INCLUDE_DIRS})
        target_link_libraries(my_project ${CUDA_LIBRARIES})
    else()
        find_package(OpenCV REQUIRED)
        target_link_libraries(my_project ${OpenCV_LIBS})
    endif()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这个示例根据USE_CUDA变量的值选择编译选项。如果USE_CUDA为真,将添加一个定义USE_CUDA,然后查找并链接CUDA库。否则,查找并链接OpenCV库。

  2. 依赖管理示例:

    find_package(Boost REQUIRED COMPONENTS filesystem)
    include_directories(${Boost_INCLUDE_DIRS})
    target_link_libraries(my_project ${Boost_LIBRARIES})
    
    • 1
    • 2
    • 3

    这个示例使用find_package命令查找并链接Boost库的filesystem组件。Boost_INCLUDE_DIRS变量保存了Boost库的头文件路径,Boost_LIBRARIES变量保存了链接Boost库所需的库文件。

  3. 外部项目管理示例:

    ExternalProject_Add(MyLibrary
        PREFIX ${CMAKE_CURRENT_BINARY_DIR}/external/MyLibrary
        GIT_REPOSITORY https://github.com/user/MyLibrary.git
        CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这个示例使用ExternalProject_Add命令下载并构建名为MyLibrary的外部项目。PREFIX选项指定了项目的构建目录,GIT_REPOSITORY选项指定了项目的Git仓库地址,CMAKE_ARGS选项指定了传递给外部项目的CMake参数。

  4. 自定义编译选项示例:

    option(ENABLE_FEATURE "Enable feature" ON)
    if(ENABLE_FEATURE)
        add_definitions(-DENABLE_FEATURE)
    endif()
    
    • 1
    • 2
    • 3
    • 4

    这个示例创建了一个名为ENABLE_FEATURE的选项。如果用户在构建过程中设置了-DENABLE_FEATURE=ON,则会添加一个定义ENABLE_FEATURE

5.3 引入外部依赖库

引入外部依赖库有几种常见的方式。下面是两个示例:

  1. 使用find_package命令:

    find_package(OpenCV REQUIRED)
    include_directories(${OpenCV_INCLUDE_DIRS})
    target_link_libraries(my_project ${OpenCV_LIBS})
    
    • 1
    • 2
    • 3

    这个示例使用find_package命令查找OpenCV库,并通过include_directories命令将OpenCV的头文件路径添加到项目中。然后使用target_link_libraries命令将OpenCV库链接到项目中。

  2. 使用add_subdirectory命令和add_library命令:

    add_subdirectory(external/MyLibrary)
    include_directories(external/MyLibrary/include)
    target_link_libraries(my_project MyLibrary)
    
    • 1
    • 2
    • 3

    这个示例假设外部依赖库的源代码位于项目根目录下的external/MyLibrary目录中。通过add_subdirectory命令将该目录中的源代码添加到项目中。然后使用include_directories命令将该库的头文件路径添加到项目中。最后使用target_link_libraries命令将该库链接到项目中。

5.4 自定义构建选项和功能

在CMake中,可以使用option命令来定义自定义构建选项。下面是一个示例:

option(ENABLE_FEATURE_A "Enable Feature A" ON)
option(ENABLE_FEATURE_B "Enable Feature B" OFF)
  • 1
  • 2

这个示例定义了两个自定义构建选项:ENABLE_FEATURE_AENABLE_FEATURE_BONOFF分别表示选项的默认值为打开和关闭。

然后,你可以在CMakeLists.txt文件中根据这些选项进行条件编译和添加功能。示例如下:

if(ENABLE_FEATURE_A)
    message("Feature A is enabled")
    add_definitions(-DENABLE_FEATURE_A)
endif()

if(ENABLE_FEATURE_B)
    message("Feature B is enabled")
    add_definitions(-DENABLE_FEATURE_B)
endif()

# 添加功能代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在这个示例中,如果ENABLE_FEATURE_A选项被打开,将会在编译过程中添加-DENABLE_FEATURE_A宏定义,并打印一条相关信息。同样,如果ENABLE_FEATURE_B选项被打开,将会添加-DENABLE_FEATURE_B宏定义并打印一条相关信息。然后,你可以根据这些宏定义来添加相应的功能代码。

通过定义自定义构建选项,你可以根据需求来开启或关闭特定的功能,并且在构建过程中根据这些选项进行条件编译。如果你需要更多的自定义选项,可以继续使用option命令来定义。

5.5 使用CMake进行跨平台开发

CMake是一个跨平台的构建工具,可以方便地在不同的操作系统上进行开发。下面是使用CMake进行跨平台开发的一些常见方法和示例:

  1. 检测操作系统类型:

可以使用CMake的变量CMAKE_SYSTEM_NAME来获取当前的操作系统名称。根据不同的操作系统类型,可以进行不同的设置和配置。例如,可以使用以下代码在Windows系统上设置特定的编译选项:

if(WIN32)
    # Windows-specific settings
endif()
  • 1
  • 2
  • 3
  1. 检测编译器类型:

可以使用CMake的变量CMAKE_C_COMPILERCMAKE_CXX_COMPILER来获取当前使用的C和C++编译器路径。根据不同的编译器类型,可以进行不同的设置和配置。

  1. 处理平台特定的库和头文件路径:

在不同的操作系统上,可能会有不同的标准库和头文件路径。通过使用CMake的变量CMAKE_INCLUDE_PATHCMAKE_LIBRARY_PATH,可以设置特定的路径,以确保在不同的平台上能够正确地找到所需的库和头文件。

if(UNIX)
    set(CMAKE_INCLUDE_PATH "/usr/local/include")
    set(CMAKE_LIBRARY_PATH "/usr/local/lib")
elseif(WIN32)
    set(CMAKE_INCLUDE_PATH "C:/Program Files/SomeLibrary/include")
    set(CMAKE_LIBRARY_PATH "C:/Program Files/SomeLibrary/lib")
endif()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 处理平台特定的编译选项:

不同的操作系统和编译器可能需要不同的编译选项。可以使用CMake的变量CMAKE_C_FLAGSCMAKE_CXX_FLAGS来设置特定的编译选项。例如,可以使用以下代码设置在Linux上使用特定的编译选项:

if(UNIX)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
  • 1
  • 2
  • 3
  • 4
  1. 使用Find模块查找库:

CMake提供了一系列的Find模块,用于自动查找各种常见的第三方库。你可以使用find_package命令来调用相应的Find模块,并根据结果进行配置。例如,使用以下代码在项目中查找和使用OpenCV库:

find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(MyApp ${OpenCV_LIBS})
  • 1
  • 2
  • 3

通过以上方法,你可以使用CMake方便地进行跨平台开发,确保你的项目可以在不同的操作系统上正确编译和运行。

六、在不同平台上使用CMake

6.1 如何在不同操作系统和开发环境上使用CMake

当在不同的操作系统和开发环境上使用CMake时,可以按照以下步骤进行:

  1. 安装CMake:
    首先,在你的目标操作系统上安装CMake。你可以从CMake的官方网站(https://cmake.org)上下载适合你操作系统的安装程序,并按照提示进行安装。

  2. 创建CMakeLists.txt文件:
    在你的项目根目录下创建一个名为CMakeLists.txt的文本文件。这个文件将包含构建你项目所需的CMake配置和构建指令。

  3. 写入CMake配置和构建指令:
    编辑CMakeLists.txt文件,并根据你的项目需求编写CMake配置和构建指令。这些指令包括设置项目名称、指定源文件、定义目标(可执行文件、库等)、链接库和设置编译选项等。

  4. 在命令行中使用CMake:
    打开终端或命令提示符,并导航到你的项目根目录。在命令行中输入以下命令来运行CMake配置和生成构建系统所需的Makefile或项目文件:

    cmake .
    
    • 1

    注意,这里的"."表示当前目录,你也可以指定其他目录作为参数来进行配置和生成。

  5. 构建项目:
    在运行CMake之后,根据你的操作系统和开发环境,使用相应的构建工具(如make、Ninja、Visual Studio等)来构建你的项目。使用以下命令进行构建:

    make         # 在Linux或macOS上使用make进行构建
    ninja        # 在任何平台上使用ninja进行构建
    msbuild      # 在Windows上使用Visual Studio进行构建
    
    • 1
    • 2
    • 3
  6. 运行和调试:
    构建成功后,你可以在生成的可执行文件或库的目录中找到生成的输出文件。你可以在适合你的操作系统和开发环境中运行、调试和测试你的项目。

6.1 不同平台的特殊注意事项和使用技巧

当在不同的平台上使用CMake时,可能会面临一些特殊的注意事项和使用技巧。以下是针对不同平台的一些常见问题和解决方案:

  1. Linux上的注意事项和技巧:

    • 在Linux上,通常需要安装一些依赖库和开发工具,以便CMake可以找到并链接它们。确保在CMakeLists.txt文件中正确设置了依赖库的路径和名称。
    • Linux上的默认构建系统是make,可以使用make命令来构建项目。你也可以使用其他构建工具,如Ninja。
    • 在Linux上进行调试时,可以使用GNU调试器(GDB)来调试生成的可执行文件。你可以使用以下命令进行调试:
    gdb <executable>  # 用你的可执行文件的名称替换<executable>
    
    • 1
  2. Windows上的注意事项和技巧:

    • 在Windows上,可以使用Visual Studio来构建和调试CMake项目。在运行CMake配置时,可以通过指定生成器来生成一个适合Visual Studio的项目文件。例如,使用以下命令:
    cmake -G "Visual Studio 16" .  # 生成Visual Studio 2019的项目文件
    
    • 1
    • 在Visual Studio中打开生成的项目文件后,可以使用IDE中提供的编辑、构建和调试工具。
    • 注意,在Windows上链接库时,需要指定库文件的完整路径或设置库文件的搜索路径。在CMakeLists.txt文件中使用绝对路径或设置CMake变量来指定库的位置。
  3. macOS上的注意事项和技巧:

    • 在macOS上,可以使用Xcode或者命令行工具进行构建和调试。CMake可以生成适用于Xcode的项目文件,或者你可以使用命令行工具来构建。
    • 使用Xcode进行构建时,可以通过指定生成器生成Xcode项目文件。例如,使用以下命令:
    cmake -G "Xcode" .  # 生成Xcode项目文件
    
    • 1
    • 在命令行中构建时,可以使用make或者ninja等工具。在macOS上,默认的构建系统是make。
    • 在macOS上,链接库时也需要指定库文件的完整路径或设置库文件的搜索路径。在CMakeLists.txt文件中使用绝对路径或设置CMake变量来指定库的位置。

6.1 不同平台(Windows、Mac、Linux等)上CMake的安装方法

在不同平台上安装CMake的具体方法如下:

  1. Windows上安装CMake:

    • 在CMake的官方网站(https://cmake.org/download/)上下载最新的Windows安装程序。
    • 运行下载的安装程序,并按照安装向导进行安装。
    • 添加CMake的安装路径到系统的环境变量中(将CMake的bin目录添加到PATH变量中),这样就可以在命令行中直接使用cmake命令。
  2. macOS上安装CMake:

    • 通过Homebrew安装(推荐):

      • 打开终端,并运行以下命令来安装Homebrew:

        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
        
        • 1
      • 安装Homebrew后,运行以下命令来安装CMake:

        brew install cmake
        
        • 1
    • 通过安装程序安装:

      • 在CMake的官方网站(https://cmake.org/download/)上下载最新的macOS安装程序。
      • 运行下载的安装程序,并按照安装向导进行安装。安装过程中会提示你将CMake添加到系统的PATH中,选择是即可。
  3. Linux上安装CMake:

    • 通过包管理器安装(根据不同的Linux发行版可能会有所不同):

      • 在终端中运行以下命令来安装CMake:
        • Debian/Ubuntu:
          sudo apt-get install cmake
          
          • 1
        • Fedora/RHEL:
          sudo dnf install cmake
          
          • 1
        • Arch Linux/Manjaro:
          sudo pacman -S cmake
          
          • 1
      • 根据你的发行版和包管理器,可能需要使用不同的命令来安装CMake,请查看相关文档以获取准确的命令。
    • 通过源代码安装:

      • 在CMake的官方网站(https://cmake.org/download/)上下载最新的源代码包。

      • 解压下载的源代码包,并进入解压后的目录。

      • 在终端中运行以下命令来编译和安装CMake:

        ./bootstrap
        make
        sudo make install
        
        • 1
        • 2
        • 3

6.1 CMake的配置选项和环境变量的设置方式

CMake提供了一些配置选项和环境变量,可以用来自定义构建过程和设置一些参数。下面是一些常用的配置选项和环境变量的设置方式:

  1. 配置选项:

    • -D:使用-D选项可以设置CMake变量的值,例如:
      cmake -DCMAKE_BUILD_TYPE=Release ..
      
      • 1
      这将设置CMake变量CMAKE_BUILD_TYPE的值为Release。常用的一些配置选项有:
      • CMAKE_BUILD_TYPE:指定构建类型,例如Release、Debug等。
      • CMAKE_INSTALL_PREFIX:指定安装目录。
      • CMAKE_CXX_FLAGS:设置C++编译器的额外编译选项。
      • CMAKE_C_FLAGS:设置C编译器的额外编译选项。
      • 其他自定义的CMake变量。
  2. 环境变量:

    • CMAKE_PREFIX_PATH:设置CMake查找依赖库的路径。可以通过设置此环境变量告诉CMake在指定路径下搜索依赖库的头文件和库文件。
    • CMAKE_MODULE_PATH:设置CMake查找自定义模块文件的路径。CMake模块文件通常用于扩展CMake的功能,通过设置此环境变量告诉CMake在指定路径下搜索自定义模块文件。
    • CXXFLAGS和CFLAGS:设置C++和C编译器的额外编译选项。可以通过设置这些环境变量来传递额外的编译选项给CMake。

这些配置选项和环境变量可以在CMakeLists.txt文件中使用,或者通过命令行传递给CMake。例如,在CMakeLists.txt中可以使用set()命令来设置变量的默认值,或者使用if()语句根据不同的变量值进行条件判断。在命令行中,可以使用cmake -D选项来设置变量的值。

七、常见问题和解决方法

7.1 常见的CMake问题和解决方案

在使用CMake时,可能会遇到一些常见的问题。以下是几个常见问题及其解决方案:

  1. CMake找不到依赖库:

    • 确保依赖库已经正确安装在系统中,并且路径正确。
    • 可以使用find_library()find_package()命令来告诉CMake查找依赖库的路径。
    • 可以设置CMAKE_PREFIX_PATH环境变量来指定依赖库的安装路径。
  2. CMake生成的Makefile或项目文件无法编译通过:

    • 检查CMakeLists.txt文件中的语法错误或逻辑错误。
    • 确保文件路径和文件名正确,特别是在使用add_executable()add_library()命令时。
    • 可以在命令行中运行CMake并查看生成的Makefile或项目文件的输出,从中找到错误提示。
  3. 无法生成所需的构建目标或输出文件:

    • 检查CMakeLists.txt文件中的构建规则是否正确,并且目标文件名和路径是否正确设置。
    • 检查构建选项和环境变量是否正确设置,例如构建类型和安装目录。
  4. CMake生成的项目文件不能正确地与IDE集成:

    • 确保使用支持CMake的IDE,并且已经正确安装了相应的插件或扩展。
    • 在IDE中导入或打开CMakeLists.txt文件,而不是直接打开生成的项目文件。
  5. CMake缓存问题:

    • CMake在运行时会生成一个缓存文件(CMakeCache.txt),其中存储了变量的值。如果更改了CMakeLists.txt文件或配置选项,可能需要删除缓存文件并重新生成项目。

7.2 调试技巧和常用命令

在使用CMake时,以下是一些常用的调试技巧和命令:

  1. 使用message()命令输出调试信息:将需要跟踪的变量或信息输出到终端,以便调试和排除问题。
message("Variable X has value: ${X}")
  • 1
  1. 在CMakeLists.txt中启用调试模式:使用set(CMAKE_VERBOSE_MAKEFILE ON)命令启用详细的Makefile输出,以查看生成的构建规则和命令。

  2. 使用--trace选项运行CMake:在命令行中使用cmake --trace命令,可以打印出CMake在解析和处理CMakeLists.txt文件时的详细信息,有助于排查问题。

  3. 使用--build选项编译项目:在命令行中使用cmake --build <build_dir>命令,可以手动触发构建过程,并查看编译器输出的详细信息和错误提示。

  4. 使用--debug-output选项调试生成过程:在命令行中使用cmake --debug-output命令,可以获得更详细的CMake生成过程信息,包括搜索和配置文件的路径。

  5. 使用ctest命令运行测试:CMake集成了CTest框架,可以使用ctest命令执行项目中的测试,并查看测试结果和详细输出。

  6. 使用外部工具调试:可以使用其他调试工具(如GDB或LLDB)来调试生成的可执行文件。在CMakeLists.txt中设置CMAKE_BUILD_TYPEDebug,并使用适当的编译选项来生成可调试的二进制文件。

八、实例演示

  • 提供一个实际项目的CMakeLists.txt文件示例,并解释每个部分的作用和用法
  • 分析常见问题和解决方案
  • 详细讲解CMakeLists.txt文件的内容和配置

示例1:

hello.cpp
  • 1
#include <iostream>
using namespace std;

int main()
{
    cout << "hello world!" << endl;

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
CMakeLists.txt	
  • 1
cmake_minimum_required (VERSION 3.10)

project (learn_cmake)

add_executable (App hello.cpp)
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果
在这里插入图片描述

示例2:
在这里插入图片描述
在这里插入图片描述

test1.h
  • 1
#ifndef TEST1_H
#define TEST1_H

void test01(int num = 8);

#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
test1.cpp
  • 1
#include <iostream>
#include "test1.h"

using namespace std;

void test01(int num)
{
    cout << num << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
main.cpp
  • 1
#include <iostream>
#include "test1.h"

using namespace std;

int main()
{
    cout << "hello world!" << endl;
    test01();
    test01(66);

    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
CMakeLists.txt	
  • 1
cmake_minimum_required (VERSION 3.10)

project (learn_cmake)

include_directories(./include )
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/source SRC_DIR)

add_executable (App ${SRC_DIR})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

运行结果
在这里插入图片描述
示例3:

在CMakeLists.txt定义代码中使用的宏

在这里插入图片描述

main.c
  • 1
#include <stdio.h>

int main()
{
#if DEBUG
    printf("调试信息\n");
#endif
    return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
cmake_minimum_required(VERSION 3.10)

project(cmake03)

add_definitions(-DDEBUG)

aux_source_directory(./src SRC_LIST)

add_executable(main ${SRC_LIST})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

运行结果
在这里插入图片描述

定义CMakeLists.txt文件中使用的宏,通过命令行传入

在这里插入图片描述
CMakeLists.txt

if(DEBUG_MODE)
    message("ON------${DEBUG_MODE}")
else()
    message("OFF------${DEBUG_MODE}")
endif()
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果:
在这里插入图片描述

示例4:

message(消息等级 "消息内容" ...)
  • 1
string(ASCII 27 Esc)
set(R "${Esc}[32;1m")
set(E "${Esc}[0m")

message(FATAL_ERROR "${R}this is test${E}")
  • 1
  • 2
  • 3
  • 4
  • 5
(无) :重要消息
  • 1
message("${R}this is test${E}")
  • 1

运行结果
在这里插入图片描述

STATUS :非重要消息
  • 1
message(STATUS "${R}this is test${E}")
  • 1

运行结果
在这里插入图片描述

WARNING:警告, 会继续执行
  • 1
message(WARNING "${R}this is test${E}")
  • 1

运行结果
在这里插入图片描述

AUTHOR_WARNING:警告 (dev), 会继续执行
  • 1
message(AUTHOR_WARNING "${R}this is test${E}")
  • 1

运行结果
在这里插入图片描述

SEND_ERROR:错误, 会继续执行,跳过生成的步骤
  • 1
message(SEND_ERROR "${R}this is test${E}")
  • 1

运行结果
在这里插入图片描述

FATAL_ERROR:错误, 终止
  • 1
message(FATAL_ERROR "${R}this is test${E}")
  • 1

运行结果
在这里插入图片描述

示例5:


  • 1

运行结果


总结

CMake是一种流行的构建系统工具,用于自动化软件的构建过程。它有以下几个优势:

  1. 跨平台: CMake可以在多个操作系统上运行,包括Windows、Linux和macOS。这使得开发人员可以在不同平台之间共享和重用构建配置。

  2. 简单易用: CMake使用简洁的语法,易于理解和学习。开发人员可以通过编写简单的CMakeLists.txt文件来描述项目的构建过程。

  3. 可扩展性: CMake提供了丰富的功能和模块,可以满足各种项目的需求。使用CMake,开发人员可以自定义构建过程,并集成其他工具和库。

  4. 并行构建: CMake支持并行构建,可以加快项目的构建速度。开发人员可以指定同时构建多个目标,提高构建效率。

  5. 支持多种构建系统: CMake可以生成多种构建系统的配置文件,包括Makefile、Ninja和Visual Studio等。这使得开发人员可以根据自己的需求选择合适的构建系统。

CMake的不足之处包括:

  1. 学习曲线较陡峭: 尽管CMake的语法相对简洁,但对于新手来说,学习和理解CMake的概念和工作原理可能需要一定的时间和经验。CMake使用一种基于脚本的语法,对于初学者来说,学习和理解CMake的语法可能需要一些时间。

  2. 缺乏良好的文档: 虽然CMake有一些文档和教程可供参考,但相对不够全面和详细。这可能导致开发人员在遇到问题时难以找到合适的解决方案。

  3. 速度较慢: CMake的速度相对较慢,特别是在处理大型项目时。这可能影响项目的构建效率。

  4. 缺乏直观性: CMake的语法相对复杂,有时候很难直观地理解脚本的含义。

  5. 生成的构建脚本可能不够优化: 由于CMake的生成脚本是自动生成的,有时候可能会存在一些不够优化的问题,需要手动对生成的脚本进行优化。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/952679
推荐阅读
相关标签
  

闽ICP备14008679号