CMake基础

1.CMake

CMake是一个开源的跨平台构建工具,用于管理软件项目的构建过程。它使用CMakeLists.txt文件来描述项目的构建配置,并能够根据不同的操作系统、编译器和构建工具生成适应性的构建文件(如Makefile、Visual Studio项目文件等)。

CMake的主要目标是简化跨平台软件项目的构建过程。使用CMake可以提供一个统一的构建系统,使得开发者可以更方便地在不同的平台上进行构建、测试和部署。通过使用CMake,开发者只需编写一次构建配置,并可以在多个平台上重复使用,大大简化了构建过程的维护和管理。

CMake支持多种编程语言和构建工具,如C、C++、Java、Python等,也可以与各种常用的构建系统集成,如Make、Ninja、Visual Studio、Xcode等。通过CMake,开发者可以指定项目的源文件、依赖库、编译选项以及安装目标等,还可以定义自定义的构建规则和脚本。

使用CMake需要编写CMakeLists.txt文件,该文件描述了项目的构建配置。CMakeLists.txt文件使用一种类似于脚本的语法,包括命令、变量、函数等各种元素,用于组织和配置项目的构建过程。

总之,CMake是一个强大的构建工具,能够帮助开发者简化跨平台项目的构建过程,提高项目的可维护性和可移植性。

2.示例1

当工程目录单一,文件相对较少

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (CMakeSample)

# 指定生成目标CMakeSample 源文件 sample1.cc sample2.cc 。。。
add_executable(CMakeSample sample1.cc sample2.cc)

# 也可以使用以下方式实现
# add_executable(CMakeSample)
# target_sources(CMakeSample sample1.cc sample2.cc)

3. 示例2

当项目工程设计多个目录时,项目文件较多或者变化较快时

./CMakeSample
    |
    +--- src/
          |
          +--- sample.cc
          |
          +--- smple.h
          |
          +--- common
          		|
          		+--- common.h
          		|
          		+--- common.cc

# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (CMakeSample)

# 也可以使用以下方式实现
add_executable(CMakeSample)
# 将当前目录添加到变量DIR_SRCS
aux_source_directory(. DIR_SRCS)
# 将common目录添加到变量DIR_SRCS
aux_source_directory(common DIR_SRCS)
target_sources(CMakeSample ${DIR_SRCS})

# aux_source_directory只会将当前目录的源文件添加到构建中
# 子目录的源文件和所有头文件都不会添加到构建中
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)

# 项目信息
project (CMakeSample)

# 也可以使用以下方式实现
add_executable(CMakeSample)

# 递归遍历指定目录,将匹配的文件添加到构建系统中
file(GLOB_RECURSE DIR_SRCS
    "*.hpp"
    "*.h"
    "*.cpp"
    "*.cc"
    "*.c"
)

target_sources(CMakeSample ${DIR_SRCS})

# GLOB_RECURSE会递归遍历指定的目录
# 当构建列表变更时无法自动感知到变更,需要重写构建

5. 常用命令

5.1 cmake_minimum_required

指定所需的最低 CMake 版本。命令的语法如下:

cmake_minimum_required(VERSION <min-version> [FATAL_ERROR])

其中 <min-version> 是指定的最低 CMake 版本。它可以是一个具体的版本号,也可以是一个版本范围。

示例用法如下:

cmake_minimum_required(VERSION 3.16)

在上述示例中,cmake_minimum_required 命令指定了所需的最低 CMake 版本为 3.16。

5.2 project

定义一个项目,并设置项目名称和版本信息。命令的语法如下:

project(<project-name> [VERSION <project-version>] [LANGUAGES <language1> <language2> ...])

其中 <project-name> 是指定的项目名称,<project-version> 是可选的项目版本号,<language1> <language2> ... 是可选的项目所使用的编程语言。

示例用法如下:

project(MyProject VERSION 1.0 LANGUAGES CXX)

在上述示例中,project 命令将项目名称设置为 “MyProject”,版本号设置为 “1.0”,并指定项目使用的编程语言为 C++ (CXX)。

通过使用 project 命令,可以为 CMake 构建定义一个项目,并指定项目的名称、版本以及所使用的编程语言。这对于构建和管理大型项目非常有用,尤其是当需要处理多个源文件、依赖项和构建选项时。

project 命令还会自动创建一些与项目相关的变量,如 <project-name>_SOURCE_DIR<project-name>_BINARY_DIR。这些变量可用于引用项目源代码目录和构建目录的路径,方便在 CMake 脚本中使用。

5.3 set

创建新的变量或修改现有变量的值。命令的语法如下:

set(<variable> <value> [CACHE <type> <docstring> [FORCE]])

其中 <variable> 是要设置的变量名,<value> 是要给变量赋予的值,<type> 是可选的缓存类型,<docstring> 是可选的参数描述,FORCE 是可选的强制标志。

示例用法如下:

set(SRC_FILES file1.cpp file2.cpp)
set(MY_FLAG ON CACHE BOOL "Enable feature X" FORCE)

在上述示例中:

  • 第一个 set 命令创建了一个名为 SRC_FILES 的变量,并将其设置为包含两个源文件的列表。
  • 第二个 set 命令创建了一个名为 MY_FLAG 的变量,并将其设置为逻辑值 ONCACHE BOOL 表示将该变量作为缓存变量,"Enable feature X" 是缓存变量的描述信息,FORCE 表示即使已经存在同名的缓存变量也强制设置。

通过使用 set 命令,可以在 CMake 脚本中定义和修改变量,这些变量可以在后续的配置和生成过程中使用。变量可以用于存储路径、编译选项、依赖项等信息,从而实现对构建过程的灵活控制和配置。

5.4 add_executable

创建一个可执行文件并指定其源代码文件。它是 CMake 构建系统中常用的一个命令之一。命令的语法如下:

add_executable(<target-name> [source1] [source2 ...])

其中 <target-name> 是要创建的可执行文件的目标名,[source1] [source2 ...] 是指定的源代码文件列表。

示例用法如下:

add_executable(MyApp main.cpp utils.cpp)

在上述示例中,add_executable 命令创建了一个名为 MyApp 的可执行文件,该文件由 main.cpputils.cpp 两个源文件构成。

通过使用 add_executable 命令,可以在 CMake 构建系统中创建可执行文件,并指定源代码文件。可执行文件可以包含多个源文件,也可以从其他库或对象文件中引用符号和函数。在构建过程中,CMake 将根据指定的源代码文件生成编译输出,并将其链接到最终的可执行文件中。

5.5 add_library

创建一个库文件并指定其源代码文件。它是 CMake 构建系统中常用的一个命令之一。命令的语法如下:

add_library(<target-name> [library-type] [source1] [source2 ...])

其中 <target-name> 是要创建的库文件的目标名,[library-type] 是可选的库类型参数,[source1] [source2 ...] 是指定的源代码文件列表。

示例用法如下:

add_library(MyLib STATIC utils.cpp)

在上述示例中,add_library 命令创建了一个名为 MyLib 的静态库文件,该文件由 utils.cpp 一个源文件构成。

通过使用 add_library 命令,可以在 CMake 构建系统中创建库文件,并指定源代码文件。库文件可以包含多个源文件,也可以从其他库或对象文件中引用符号和函数。根据 [library-type] 的值,可以创建静态库(STATIC)或共享库(SHARED)。

在构建过程中,CMake 将根据指定的源代码文件生成编译输出,并将其打包成库文件供其他项目使用。

5.6 aux_source_directory

将指定目录下的所有源文件自动添加到变量中。这个命令的语法如下:

aux_source_directory(<dir> <variable>)

其中,<dir> 是指定的目录名称,而 <variable> 则是一个将包含找到的源文件列表的变量名。

以下是一个示例,展示了如何使用 aux_source_directory 命令:

# 将指定目录下的源文件添加到变量中
aux_source_directory(src SOURCES)

在上述示例中,aux_source_directory 命令将目录 src 下的所有源文件自动添加到变量 SOURCES 中。

通过使用 aux_source_directory 命令,可以方便地将指定目录下的所有源文件添加到变量中,无需手动列出每个源文件的名称。这在大型项目中特别有用,可以简化构建脚本的编写过程。

5.7 file

文件操作相关指令。该命令的语法如下:

file(GLOB variable [RELATIVE path] [globbing
expressions]...)
file(GLOB_RECURSE variable [RELATIVE path]
[globbing expressions]...)
file(REMOVE [directory]...)
file(REMOVE_RECURSE [directory]...)
file(MAKE_DIRECTORY [directory]...)
file(RELATIVE_PATH variable directory file)
file(TO_CMAKE_PATH path result)
file(TO_NATIVE_PATH path result)
file(WRITE filename "message to write"... )
file(APPEND filename "message to write"... )
file(READ filename variable)

以下是一个简单的示例,展示了如何使用 file 命令:.

# 匹配{CUR}目录下的所有文件或目录,并将结果存储在 SUB 变量中:
file(GLOB SUB relative ${CUR} ${CUR}/*)

# 匹配所有子目录下的 .cpp 文件并将结果存储在 SRCS 变量中:
file(GLOB_RECURSE SRCS src/*.cpp)
5.8 include_directories 和 target_include_directories

用于添加(特定目标的)包含目录(include directories)到编译器的搜索路径中。基本语法是:

include_directories([AFTER|BEFORE] [SYSTEM] directory1 [directory2 ...])

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

其中:

  • target 是指定的目标名。
  • AFTERBEFORE 选项用于指定添加目录的位置,AFTER 表示在已有目录之后添加,BEFORE 表示在已有目录之前添加。该选项是可选的,默认为 AFTER
  • SYSTEM 选项用于将目录标记为系统目录,这可以告诉编译器忽略其中的警告信息。该选项也是可选的。
  • directory1, directory2, … 是包含目录的路径。
  • INTERFACE, PRIVATE, PUBLIC 选项用于定义包含目录的可见性。PUBLIC 表示目标及其依赖可以使用该包含目录,PRIVATE 表示仅该目标可以使用该包含目录,INTERFACE 表示仅依赖于该目标的目标可以使用该包含目录。

以下是一个示例用法:

# 添加 include 目录和 third_party/include 目录到编译器的搜索路径中
include_directories(include)
include_directories(SYSTEM third_party/include)

# 将 myapp 目标的包含目录设置为 include/ 目录,并将其可见性设置为 PRIVATE,这意味着仅 myapp 本身可以使用该包含目录。
add_executable(myapp main.cpp)
target_include_directories(myapp PRIVATE include/)

include_directories 全局生效,因此一般写在最外层CMakelists.txt中。

请注意,从 CMake 3.0 开始,推荐使用 target_include_directories 代替 include_directories 来将包含目录与特定的目标(target)相关联。

5.9 target_link_libraries和link_libraries

将库文件链接到指定的目标(可执行文件或库)中。基本语法是:

link_libraries(library1 [library2 ...])

target_link_libraries(target
                      [PRIVATE|PUBLIC|INTERFACE]
                      library1 [library2 ...])

其中:

  • target 是指定的目标名。
  • library1, library2, … 是要链接的库文件的名称。
  • PRIVATE|PUBLIC|INTERFACE是可选项,用于指定链接库的可见性。
    • PRIVATE 表示该目标私有地链接库文件,仅限于该目标本身使用。
    • PUBLIC 表示该目标及其使用该目标的其他目标都可以使用链接的库文件。
    • INTERFACE 表示仅使用该目标的其他目标可以使用链接的库文件。

以下是一个示例用法:

# 将 mylib1 和 mylib2 两个库文件链接到当前目标中
link_libraries(mylib1 mylib2)

#
add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mylib1 mylib2)

link_libraries 全局生效,因此不推荐使用。

5.10 add_subdirectory

将子目录添加到当前项目的命令。通过使用 add_subdirectory,您可以引入其他的 CMake 项目,并在当前项目中构建和链接这些子项目。基本语法如下:

add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])

以下是 add_subdirectory 命令的参数:

  • source_dir:子目录的源代码目录,通常会包含一个 CMakeLists.txt 文件。
  • binary_dir:可选参数,指定子目录二进制文件的输出目录。如果不提供该参数,CMake 将默认使用 source_dir/build 目录作为输出目录。
  • EXCLUDE_FROM_ALL:可选参数,表示将子目录排除在 ALL 构建目标之外,即在构建主项目时不会自动构建子目录。

下面是一个示例用法:

add_subdirectory(libfoo)
add_subdirectory(appfoo)

上述示例将项目中的 libfooappfoo 子目录添加到当前项目中。在构建过程中,CMake 将分别构建和处理这两个子目录,并生成相应的二进制文件。

5.11 add_compile_options

用于向编译器添加编译选项。通过使用 add_compile_options,您可以在 CMake 构建过程中为源文件设置特定的编译选项。

基本语法如下:

add_compile_options([target] <option>...)

以下是 add_compile_options 命令的参数:

  • target:可选参数,指定目标名称,用于将编译选项仅应用于特定的目标。如果不提供该参数,则编译选项将应用于整个项目。
  • <option>:要添加的编译选项,可以指定多个。

下面是一个示例用法:

add_compile_options(-Wall -Wextra)

上述示例将 -Wall-Wextra 编译选项添加到整个项目中。这两个选项可以启用更严格的编译警告。

5.12 add_definitions

用于向编译器添加预定义的宏定义。通过使用 add_definitions,您可以在 CMake 构建过程中为源文件设置特定的预定义宏。基本语法如下:

add_definitions(-D<macro1> -D<macro2> ...)

以下是 add_definitions 命令的参数:

  • -D<macro>:要添加的预定义宏,可以指定多个。

下面是一个示例用法:

add_definitions(-DMY_MACRO)

上述示例将预定义宏 MY_MACRO 添加到整个项目中,这样在编译时就会将它作为宏定义传递给编译器。

请注意,add_definitions 命令添加的宏定义将适用于整个项目,包括所有的源文件和目标。

因此,如果您只想将宏定义应用于特定的目标,可以使用 target_compile_definitions 命令。

5.13 include

INCLUDE 是 CMake 中的一个命令,用于包含其他 CMake 脚本文件。通过使用 INCLUDE,您可以在当前 CMakeLists.txt 文件中导入其他的 CMake 模块或宏定义。基本语法如下:

include(<filename>)

以下是 INCLUDE 命令的参数:

  • <filename>:要包含的 CMake 脚本文件的名称。通常使用相对路径或绝对路径来指定文件位置。

下面是一个示例用法:

include(utils.cmake)

上述示例将当前目录或指定目录中的 utils.cmake 文件包含到当前的 CMakeLists.txt 文件中,以便在构建过程中使用该脚本中定义的函数、宏等。

请注意,在包含其他脚本文件时,CMake 将会按顺序执行这些脚本中的命令和定义。

5.14 configure_file
  1. 用于生成并配置文件。它可以将源文件中的变量替换为 CMake 脚本中定义的值,从而生成最终的目标文件。

  2. 该命令的语法如下:

configure_file(<input> <output> [COPYONLY])

其中,<input> 是源文件的路径和名称(可以是绝对路径或相对路径),<output> 是生成的目标文件的路径和名称。可选参数 COPYONLY 表示只进行文件拷贝而不进行配置替换。

  1. 以下是一个简单的示例,展示了如何使用 configure_file 命令:.
# 定义版本
set (MyApp_VERSION_MAJOR 1)
set (MyApp_VERSION_MINOR 0)

# 配置文件并生成目标文件
configure_file(version.h.in version.h)
// version.h.in
// the configured options and settings for Tutorial
#define MyApp_VERSION_MAJOR @MyApp_VERSION_MAJOR@
#define MyApp_VERSION_MINOR @MyApp_VERSION_MINOR@

在上述示例中,我们首先定义了主版本号MyApp_VERSION_MAJOR和次版本号MyApp_VERSION_MINOR。然后,使用 configure_file 命令将名为 version.h.in 的源文件配置为 version.h 的目标文件。在这个过程中,源文件中的变量 @Demo_VERSION_MAJOR@@Demo_VERSION_MINOR@ 将被替换为变量定义的值。

通过使用 configure_file 命令,我们可以在构建过程中根据需要动态生成配置文件,使得生成的目标文件包含所需的配置信息。这对于需要根据不同的构建选项生成不同配置文件的项目非常有用。

5.15 install
  1. 用于在构建过程中将文件或目标安装到指定位置。
  2. 基本语法是:
install(TARGETS <target1> [target2...]
        [[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
        [DESTINATION <dir>]
        [PERMISSIONS permissions...]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [NAMELINK_COMPONENT <name>]
        [OPTIONAL]
        [EXCLUDE_FROM_ALL]])
        
install(DIRECTORY <dir1> [dir2...]
        DESTINATION <dir>
        [FILE_PERMISSIONS permissions...]
        [DIRECTORY_PERMISSIONS permissions...]
        [USE_SOURCE_PERMISSIONS]
        [CONFIGURATIONS [Debug|Release|...]]
        [COMPONENT <component>]
        [FILES_MATCHING]
        [PATTERN pattern1 [EXCLUDE] [PERMISSIONS permissions...]]
        [...])

install({FILES | PROGRAMS} <file>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])

其中:

  • <target1> [target2...]:要安装的目标文件的名称,可以一次指定多个。
  • [ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]:可选的目标类型。ARCHIVE 表示静态库文件,LIBRARY 表示共享库文件,RUNTIME 表示可执行文件等。
  • [DESTINATION <dir>]:指定安装目标文件的目标目录。
  • [PERMISSIONS permissions...] :可选项,设置安装文件的权限。
  • [CONFIGURATIONS [Debug|Release|...]]:根据配置类型选择安装目标文件。
  • [COMPONENT <component>]:指定安装目标所属的组件。
  • [NAMELINK_COMPONENT <name>]:指定创建名称链接的组件。
  • [OPTIONAL]:如果目标文件不存在,则跳过安装。
  • [EXCLUDE_FROM_ALL]:将目标文件从 ALL 构建目标中排除。
  • [PATTERN pattern1 [EXCLUDE] [PERMISSIONS permissions...]]:指定要匹配的文件模式,并可以选择排除文件和设置文件权限。
  1. 以下是一个示例用法:
add_executable(myapp main.cpp)
# 将名为 `myapp` 的可执行文件安装到 `bin` 目录,并设置了文件的执行和读写权限。
install(TARGETS myapp
        RUNTIME DESTINATION bin
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_EXECUTE WORLD_READ)
        
# 将名为 resources 的源目录安装到 bin 目录,并设置了目录的权限。
# 排除了所有的 .txt 文件,并为所有的 .jpg 文件设置了读权限。
install(DIRECTORY resources
        DESTINATION bin
        DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
        FILES_MATCHING
        PATTERN "*.txt" EXCLUDE
        PATTERN "*.jpg" PERMISSIONS OWNER_READ GROUP_READ)

6. 预定义常量

CMAKE_BUILD_TYPE 是 CMake 中的一个变量,用于指定构建类型。通过设置 CMAKE_BUILD_TYPE,您可以控制在构建过程中使用的编译选项和优化级别。

通常,CMAKE_BUILD_TYPE 变量的值可以是以下之一:

  • Debug:用于调试目的,启用调试符号,并优化性能。

  • Release:用于发布目的,启用更高级别的优化和禁用调试符号。

  • RelWithDebInfo:一种组合模式,同时启用优化和调试符号。

  • MinSizeRel:用于最小化生成文件大小的模式。

CMAKE_SYSTEM_NAME 是 CMake 中表示目标系统的名称。
CMAKE_SIZEOF_VOID_P 是 CMake 中表示当前系统指针的字节大小。它可以用来确定当前系统是 32 位还是 64 位。
CMAKE_SYSTEM_PROCESSOR 是 CMake 中用于指定目标系统的处理器架构。通过设置 CMAKE_SYSTEM_PROCESSOR,可以告诉 CMake 构建针对特定处理器架构的项目。

SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -g")
SET(CMAKE_CXX_FLAGS_RELEASE "-DNODEBUG -O2 -Wall")
SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Wall -O2 -g -DNDEBUG")
SET(CMAKE_C_FILAGS_DEBUG "O0 -Wall -g")
SET(CMAKE_C_FLAGS_RELEASE "-DNODEBUG -O2 -Wall")
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-Wall -O2 -g -DNDEBUG")

7. 语法

7.1 IF

在 CMake 中,您可以使用 if 语句来执行条件判断。if 语句用于根据给定的条件来决定是否执行特定的操作。

以下是 if 语句的基本语法:

if(condition)
    # 在条件为真时执行的代码块
else()
    # 在条件为假时执行的代码块
endif()

if 语句中,condition 是一个表达式,其结果为布尔值(True 或 False)。如果 condition 的结果为 True,则执行 if 代码块中的代码;否则,执行 else 代码块中的代码。

以下是一个简单的示例,检查变量 my_variable 是否等于 5

if(my_variable EQUAL 5)
    message("my_variable is equal to 5")
else()
    message("my_variable is not equal to 5")
endif()

在上述示例中,由于 my_variable 的值确实等于 5,因此将打印出 “my_variable is equal to 5”。

7.2 FOREACH

FOREACH 是 CMake 中用于遍历列表的循环结构。它可以用于遍历列表、范围或者是由表达式生成的元素。

以下是 FOREACH 循环的基本语法:

FOREACH(loop_variable [IN|LIST] item_list)
    # 执行的代码块
ENDFOREACH()

FOREACH 循环中,loop_variable 是用户定义的变量,用于在每次迭代中保存列表中的一个元素。item_list 是待遍历的列表,可以是通过 LIST 关键字指定的变量名,或者是直接提供的元素列表。

以下是一个示例,演示如何使用 FOREACH 遍历一个列表:

FOREACH(item ${my_list})
    message("Item: ${item}")
ENDFOREACH()

在上述示例中,FOREACH 循环将依次将元素赋值给变量 item,并在每次迭代中输出该元素。

7.3 运算符

在 CMake 中,有许多用于条件判断的运算符可用于 if 语句和其他条件表达式。以下是一些常用的 CMake 运算符:

  1. 数值比较运算符:
  • EQUAL:等于
  • LESS:小于
  • GREATER:大于
  • LESS_EQUAL:小于等于
  • GREATER_EQUAL:大于等于
  • 例如:if(a LESS b),表示 a 小于 b
  1. 字符串比较运算符:
  • STREQUAL:等于
  • STRLESS:小于
  • STRGREATER:大于
  • 例如:if(str1 STREQUAL str2),表示字符串 str1 等于 str2
  1. 逻辑运算符:
  • AND&&:逻辑与
  • OR||:逻辑或
  • NOT!:逻辑非
  • 例如:if(a EQUAL 1 AND b LESS 10),表示 a 等于1 并且 b 小于 10。
  1. 文件和路径判断运算符:
  • EXISTS:文件或目录是否存在
  • IS_DIRECTORY:是否为目录
  • 例如:if(EXISTS "path/to/file"),表示路径 path/to/file 存在。
  1. 正则匹配运算符
  • MATCHES:正则匹配

这些运算符可以组合使用,以便进行更复杂的条件判断。还可以使用圆括号(())来控制运算符的求值顺序。

7.4 MACRO

在 CMake 中,MACRO 是一种用于定义可重复使用代码片段的机制。类似于函数,它可以接受参数并执行一系列指令。

以下是 MACRO 的基本语法:

MACRO(macro_name [argument1 [argument2 ...]])
    # 执行的代码块
ENDMACRO()

MACRO 中,macro_name 是用户定义的宏名称,用于调用宏。argument1argument2 等是可选的参数,在调用宏时可以传递给宏并在宏中使用。

以下是一个示例,演示如何定义和使用宏:

MACRO(print_message message)
    message("Message: ${message}")
ENDMACRO()

print_message("Hello, World!")

上述示例定义了一个名为 print_message 的宏,它接受一个参数 message 并将其作为消息输出。然后我们调用了这个宏,传递了字符串 “Hello, World!” 作为参数。

8. 非常用命令

8.1 option

用于在 CMakeLists.txt 文件中设置一个布尔型变量,并为该变量提供一个用户可选的开关选项。使用 option 的基本语法如下:

option(<variable> "help string" [initial value])

其中:

  • <variable> 是定义的变量名。
  • "help string" 是该选项的帮助描述。
  • [initial value] 是该选项的初始值,默认为 OFF

以下是一个示例用法:

option(BUILD_EXAMPLES "Build example programs" ON)

上述示例定义了一个 BUILD_EXAMPLES 变量,并为其提供了名称为 “Build example programs”的帮助字符串,并将其默认值设置为 ON。在编译 CMake 项目时,用户可以通过 -DBUILD_EXAMPLES=OFF 的命令行选项来覆盖默认值。

在 CMakeLists.txt 文件中,我们可以使用 ${BUILD_EXAMPLES} 来引用该变量。例如,我们可以在文件中使用条件语句来根据变量值来控制构建过程:

if (BUILD_EXAMPLES)
    add_subdirectory(examples)
endif()

当用户选择了 BUILD_EXAMPLES,则会构建 examples 目录中的项目。

8.2 SET_TARGET_PROPERTIES

在 CMake 中,SET_TARGET_PROPERTIES 命令用于设置目标(可执行文件、库等)的属性。通过这个命令,可以修改目标的属性,例如编译选项、链接选项、输出路径等。

SET_TARGET_PROPERTIES 的基本语法如下:

SET_TARGET_PROPERTIES(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)

在上述语法中,target1target2 等是目标的名称或者目标列表,prop1prop2 等是要修改的属性,value1value2 等是要设置的属性值。

以下是几个常用的属性示例:

SET_TARGET_PROPERTIES(my_target PROPERTIES
    OUTPUT_NAME "my_executable"
    CXX_STANDARD 17
    LINK_FLAGS "-L/path/to/libs"
)

上述示例中,my_target 是目标的名称,我们使用 SET_TARGET_PROPERTIES 命令设置了三个属性:

  • OUTPUT_NAME:指定生成的可执行文件的名称为 “my_executable”。
  • CXX_STANDARD:指定目标的 C++ 标准为 17。
  • LINK_FLAGS:设置链接器的标志,将目标链接到位于 “/path/to/libs” 目录中的库。

您可以根据需要修改更多的属性来满足项目的需求,具体属性和值取决于您的目标类型和编译器。

请注意,SET_TARGET_PROPERTIES 命令必须在目标被创建之后进行调用。如果您在调用 ADD_EXECUTABLEADD_LIBRARY 命令创建目标时设置了某些属性,您可以使用 SET_TARGET_PROPERTIES 命令进一步修改这些属性。

8.3 string

在 CMake 中,STRING 是一个用于字符串操作的命令。它提供了一些功能来处理和操作字符串变量。

下面是一些常用的 STRING 命令:

#将长度为 13 的字符串 "Hello, World!" 存储在变量 `length` 中,并通过 `MESSAGE` 命令输出。
STRING(LENGTH "Hello, World!" length)
MESSAGE("Length: ${length}")

#从字符串 "Hello, World!" 中提取了从索引 0 开始长度为 5 的子字符串,并将结果存储在变量 `substring` 中
STRING(SUBSTRING "Hello, World!" 0 5 substring)
MESSAGE("Substring: ${substring}")

#从变量 `string_with_spaces` 中去除了首尾的空白字符,并将结果存储在变量 `stripped_string` 中。
STRING(STRIP "${string_with_spaces}" stripped_string)
MESSAGE("Stripped string: ${stripped_string}")
8.4 list

在 CMake 中,LIST 是一个用于列表操作的命令。它提供了一些功能来处理和操作列表变量。

下面是一些常用的 LIST 命令:

  1. LIST(LENGTH <list> <output_variable>):获取给定列表的长度并将结果存储在 <output_variable> 变量中。
#长度为 2 的列表存储在变量 `my_list` 中,并使用 `LIST(LENGTH)` 命令将列表长度存储在变量 `length` 中。
SET(my_list "apple" "orange")
LIST(LENGTH my_list length)
MESSAGE("Length: ${length}")

#从列表 `my_list` 中获取索引为 1 的元素(即第二个元素),并将其存储在变量 `second_item` 中
LIST(GET my_list 1 second_item)
MESSAGE("Second item: ${second_item}")

# 将字符串 "banana""grape" 附加到列表 `my_list` 的末尾
LIST(APPEND my_list "banana" "grape")
MESSAGE("List: ${my_list}")

这些只是 LIST 命令的一些示例,CMake 还提供了其他用于列表操作的命令,例如 LIST(REMOVE_ITEM) 用于删除列表中的指定元素,LIST(INSERT) 用于在列表中插入元素,LIST(REVERSE) 用于反转列表,LIST(SORT) 用于对列表进行排序等。您可以根据需要选择合适的命令来处理和操作列表变量。

8.5 get_filename_component

get_filename_component 是 CMake 中用于获取文件路径相关信息的命令。它可以解析一个文件路径并提取出文件名、目录名或扩展名等信息。

下面是 get_filename_component 命令的语法:

get_filename_component(<variable> <filename> <mode>)

其中,<variable> 是存储提取结果的变量名,<filename> 是要解析的文件路径,<mode> 是提取的模式。

以下是一些常用的 <mode> 值和对应的提取结果:

  • NAME: 提取文件名(包括扩展名)。
  • DIRECTORY: 提取目录路径。
  • EXT: 提取扩展名(不包括点号)。
  • NAME_WE: 提取不带扩展名的文件名。

以下是一个示例用法:

set(dir "../..")
get_filename_component(root_dir ${dir} ABSOLUTE)
message("Absolute path: ${root_dir}")

这些只是 get_filename_component 命令的一些示例用法。您可以根据需要使用不同的模式提取文件路径中的不同信息。

8.6 message

message 是 CMake 中用于输出消息的命令。它可以将文本消息输出到 CMake 构建过程中,以帮助您调试和查看变量值、结果等。

下面是 message 命令的语法:

message([<mode>] "message")

其中,可选的 <mode> 参数用于指定消息输出的模式,常用的模式包括:

  • STATUS:以普通方式输出消息。
  • WARNING:以警告方式输出消息。
  • AUTHOR_WARNING:以作者警告方式输出消息。
  • SEND_ERROR:以发送错误方式输出消息,并停止构建过程。
  • FATAL_ERROR:以致命错误方式输出消息,并停止构建过程。
  • DEPRECATION:以弃用警告方式输出消息。

以下是一些示例:

message("This is a normal message.")
message(WARNING "This is a warning message.")
message(SEND_ERROR "This is an error message.")
8.7 execute_process

execute_process 是 CMake 中用于执行外部命令的命令。它可以运行命令并捕获其输出、返回值等信息,以便您在 CMake 构建过程中进行后续操作。

下面是 execute_process 命令的语法:

execute_process(COMMAND command [args ...]
                [WORKING_DIRECTORY dir]
                [INPUT_FILE file] [OUTPUT_FILE file] [ERROR_FILE file]
                [RESULT_VARIABLE var] [OUTPUT_VARIABLE var] [ERROR_VARIABLE var]
                [INPUT_VARIABLES var1=value1 ...]
                [OUTPUT_QUIET] [ERROR_QUIET])

其中,COMMAND 参数用于指定要执行的命令及其参数,WORKING_DIRECTORY 参数用于指定命令执行时的工作目录,INPUT_FILEOUTPUT_FILEERROR_FILE 参数用于分别指定输入文件、输出文件和错误文件,RESULT_VARIABLE 参数用于指定变量来存储命令的返回值,OUTPUT_VARIABLEERROR_VARIABLE 参数用于分别指定变量来存储命令的标准输出和标准错误输出,INPUT_VARIABLES 参数用于指定命令执行所需的输入变量。

以下是一些示例:

execute_process(COMMAND ls /usr/bin
                RESULT_VARIABLE result
                OUTPUT_VARIABLE output)
message("Command executed with result: ${result}")

上述示例将运行 ls /usr/bin 命令,并将返回值存储在 result 变量中,同时将标准输出存储在 output 变量中。最后使用 message 命令输出。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值