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
当工程目录单一,文件相对较少
c
# 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
c
# 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只会将当前目录的源文件添加到构建中
# 子目录的源文件和所有头文件都不会添加到构建中
c
# 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 版本。命令的语法如下:
c
cmake_minimum_required(VERSION <min-version> [FATAL_ERROR])
其中 <min-version>
是指定的最低 CMake 版本。它可以是一个具体的版本号,也可以是一个版本范围。
示例用法如下:
c
cmake_minimum_required(VERSION 3.16)
在上述示例中,cmake_minimum_required
命令指定了所需的最低 CMake 版本为 3.16。
5.2 project
定义一个项目,并设置项目名称和版本信息。命令的语法如下:
c
project(<project-name> [VERSION <project-version>] [LANGUAGES <language1> <language2> ...])
其中 <project-name>
是指定的项目名称,<project-version>
是可选的项目版本号,<language1> <language2> ...
是可选的项目所使用的编程语言。
示例用法如下:
c
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
创建新的变量或修改现有变量的值。命令的语法如下:
c
set(<variable> <value> [CACHE <type> <docstring> [FORCE]])
其中 <variable>
是要设置的变量名,<value>
是要给变量赋予的值,<type>
是可选的缓存类型,<docstring>
是可选的参数描述,FORCE
是可选的强制标志。
示例用法如下:
c
set(SRC_FILES file1.cpp file2.cpp)
set(MY_FLAG ON CACHE BOOL "Enable feature X" FORCE)
在上述示例中:
- 第一个
set
命令创建了一个名为SRC_FILES
的变量,并将其设置为包含两个源文件的列表。 - 第二个
set
命令创建了一个名为MY_FLAG
的变量,并将其设置为逻辑值ON
。CACHE BOOL
表示将该变量作为缓存变量,"Enable feature X"
是缓存变量的描述信息,FORCE
表示即使已经存在同名的缓存变量也强制设置。
通过使用 set
命令,可以在 CMake 脚本中定义和修改变量,这些变量可以在后续的配置和生成过程中使用。变量可以用于存储路径、编译选项、依赖项等信息,从而实现对构建过程的灵活控制和配置。
5.4 add_executable
创建一个可执行文件并指定其源代码文件。它是 CMake 构建系统中常用的一个命令之一。命令的语法如下:
c
add_executable(<target-name> [source1] [source2 ...])
其中 <target-name>
是要创建的可执行文件的目标名,[source1] [source2 ...]
是指定的源代码文件列表。
示例用法如下:
c
add_executable(MyApp main.cpp utils.cpp)
在上述示例中,add_executable
命令创建了一个名为 MyApp
的可执行文件,该文件由 main.cpp
和 utils.cpp
两个源文件构成。
通过使用 add_executable
命令,可以在 CMake 构建系统中创建可执行文件,并指定源代码文件。可执行文件可以包含多个源文件,也可以从其他库或对象文件中引用符号和函数。在构建过程中,CMake 将根据指定的源代码文件生成编译输出,并将其链接到最终的可执行文件中。
5.5 add_library
创建一个库文件并指定其源代码文件。它是 CMake 构建系统中常用的一个命令之一。命令的语法如下:
c
add_library(<target-name> [library-type] [source1] [source2 ...])
其中 <target-name>
是要创建的库文件的目标名,[library-type]
是可选的库类型参数,[source1] [source2 ...]
是指定的源代码文件列表。
示例用法如下:
c
add_library(MyLib STATIC utils.cpp)
在上述示例中,add_library
命令创建了一个名为 MyLib
的静态库文件,该文件由 utils.cpp
一个源文件构成。
通过使用 add_library
命令,可以在 CMake 构建系统中创建库文件,并指定源代码文件。库文件可以包含多个源文件,也可以从其他库或对象文件中引用符号和函数。根据 [library-type]
的值,可以创建静态库(STATIC
)或共享库(SHARED
)。
在构建过程中,CMake 将根据指定的源代码文件生成编译输出,并将其打包成库文件供其他项目使用。
5.6 aux_source_directory
将指定目录下的所有源文件自动添加到变量中。这个命令的语法如下:
c
aux_source_directory(<dir> <variable>)
其中,<dir>
是指定的目录名称,而 <variable>
则是一个将包含找到的源文件列表的变量名。
以下是一个示例,展示了如何使用 aux_source_directory
命令:
c
# 将指定目录下的源文件添加到变量中
aux_source_directory(src SOURCES)
在上述示例中,aux_source_directory
命令将目录 src
下的所有源文件自动添加到变量 SOURCES
中。
通过使用 aux_source_directory
命令,可以方便地将指定目录下的所有源文件添加到变量中,无需手动列出每个源文件的名称。这在大型项目中特别有用,可以简化构建脚本的编写过程。
5.7 file
文件操作相关指令。该命令的语法如下:
c
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
命令:.
bash
# 匹配{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)到编译器的搜索路径中。基本语法是:
c
include_directories([AFTER|BEFORE] [SYSTEM] directory1 [directory2 ...])
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
其中:
target
是指定的目标名。AFTER
或BEFORE
选项用于指定添加目录的位置,AFTER
表示在已有目录之后添加,BEFORE
表示在已有目录之前添加。该选项是可选的,默认为AFTER
。SYSTEM
选项用于将目录标记为系统目录,这可以告诉编译器忽略其中的警告信息。该选项也是可选的。directory1
,directory2
, ... 是包含目录的路径。INTERFACE
,PRIVATE
,PUBLIC
选项用于定义包含目录的可见性。PUBLIC
表示目标及其依赖可以使用该包含目录,PRIVATE
表示仅该目标可以使用该包含目录,INTERFACE
表示仅依赖于该目标的目标可以使用该包含目录。
以下是一个示例用法:
c
# 添加 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
将库文件链接到指定的目标(可执行文件或库)中。基本语法是:
c
link_libraries(library1 [library2 ...])
target_link_libraries(target
[PRIVATE|PUBLIC|INTERFACE]
library1 [library2 ...])
其中:
target
是指定的目标名。library1
,library2
, ... 是要链接的库文件的名称。PRIVATE|PUBLIC|INTERFACE
是可选项,用于指定链接库的可见性。PRIVATE
表示该目标私有地链接库文件,仅限于该目标本身使用。PUBLIC
表示该目标及其使用该目标的其他目标都可以使用链接的库文件。INTERFACE
表示仅使用该目标的其他目标可以使用链接的库文件。
以下是一个示例用法:
c
# 将 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 项目,并在当前项目中构建和链接这些子项目。基本语法如下:
c
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
构建目标之外,即在构建主项目时不会自动构建子目录。
下面是一个示例用法:
c
add_subdirectory(libfoo)
add_subdirectory(appfoo)
上述示例将项目中的 libfoo
和 appfoo
子目录添加到当前项目中。在构建过程中,CMake 将分别构建和处理这两个子目录,并生成相应的二进制文件。
5.11 add_compile_options
用于向编译器添加编译选项。通过使用 add_compile_options
,您可以在 CMake 构建过程中为源文件设置特定的编译选项。
基本语法如下:
c
add_compile_options([target] <option>...)
以下是 add_compile_options
命令的参数:
target
:可选参数,指定目标名称,用于将编译选项仅应用于特定的目标。如果不提供该参数,则编译选项将应用于整个项目。<option>
:要添加的编译选项,可以指定多个。
下面是一个示例用法:
c
add_compile_options(-Wall -Wextra)
上述示例将 -Wall
和 -Wextra
编译选项添加到整个项目中。这两个选项可以启用更严格的编译警告。
5.12 add_definitions
用于向编译器添加预定义的宏定义。通过使用 add_definitions
,您可以在 CMake 构建过程中为源文件设置特定的预定义宏。基本语法如下:
c
add_definitions(-D<macro1> -D<macro2> ...)
以下是 add_definitions
命令的参数:
-D<macro>
:要添加的预定义宏,可以指定多个。
下面是一个示例用法:
c
add_definitions(-DMY_MACRO)
上述示例将预定义宏 MY_MACRO
添加到整个项目中,这样在编译时就会将它作为宏定义传递给编译器。
请注意,add_definitions
命令添加的宏定义将适用于整个项目,包括所有的源文件和目标。
因此,如果您只想将宏定义应用于特定的目标,可以使用 target_compile_definitions
命令。
5.13 include
INCLUDE
是 CMake 中的一个命令,用于包含其他 CMake 脚本文件。通过使用 INCLUDE
,您可以在当前 CMakeLists.txt 文件中导入其他的 CMake 模块或宏定义。基本语法如下:
c
include(<filename>)
以下是 INCLUDE
命令的参数:
<filename>
:要包含的 CMake 脚本文件的名称。通常使用相对路径或绝对路径来指定文件位置。
下面是一个示例用法:
c
include(utils.cmake)
上述示例将当前目录或指定目录中的 utils.cmake
文件包含到当前的 CMakeLists.txt 文件中,以便在构建过程中使用该脚本中定义的函数、宏等。
请注意,在包含其他脚本文件时,CMake 将会按顺序执行这些脚本中的命令和定义。
5.14 configure_file
-
用于生成并配置文件。它可以将源文件中的变量替换为 CMake 脚本中定义的值,从而生成最终的目标文件。
-
该命令的语法如下:
c
configure_file(<input> <output> [COPYONLY])
其中,<input>
是源文件的路径和名称(可以是绝对路径或相对路径),<output>
是生成的目标文件的路径和名称。可选参数 COPYONLY
表示只进行文件拷贝而不进行配置替换。
- 以下是一个简单的示例,展示了如何使用
configure_file
命令:.
c
# 定义版本
set (MyApp_VERSION_MAJOR 1)
set (MyApp_VERSION_MINOR 0)
# 配置文件并生成目标文件
configure_file(version.h.in version.h)
cpp
// 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
- 用于在构建过程中将文件或目标安装到指定位置。
- 基本语法是:
c
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...]]
:指定要匹配的文件模式,并可以选择排除文件和设置文件权限。
- 以下是一个示例用法:
c
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 构建针对特定处理器架构的项目。
c
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
语句的基本语法:
c
if(condition)
# 在条件为真时执行的代码块
else()
# 在条件为假时执行的代码块
endif()
在 if
语句中,condition
是一个表达式,其结果为布尔值(True 或 False)。如果 condition
的结果为 True,则执行 if
代码块中的代码;否则,执行 else
代码块中的代码。
以下是一个简单的示例,检查变量 my_variable
是否等于 5
:
c
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
循环的基本语法:
c
FOREACH(loop_variable [IN|LIST] item_list)
# 执行的代码块
ENDFOREACH()
在 FOREACH
循环中,loop_variable
是用户定义的变量,用于在每次迭代中保存列表中的一个元素。item_list
是待遍历的列表,可以是通过 LIST
关键字指定的变量名,或者是直接提供的元素列表。
以下是一个示例,演示如何使用 FOREACH
遍历一个列表:
c
FOREACH(item ${my_list})
message("Item: ${item}")
ENDFOREACH()
在上述示例中,FOREACH
循环将依次将元素赋值给变量 item
,并在每次迭代中输出该元素。
7.3 运算符
在 CMake 中,有许多用于条件判断的运算符可用于 if
语句和其他条件表达式。以下是一些常用的 CMake 运算符:
- 数值比较运算符:
EQUAL
:等于LESS
:小于GREATER
:大于LESS_EQUAL
:小于等于GREATER_EQUAL
:大于等于- 例如:
if(a LESS b)
,表示a
小于b
。
- 字符串比较运算符:
STREQUAL
:等于STRLESS
:小于STRGREATER
:大于- 例如:
if(str1 STREQUAL str2)
,表示字符串str1
等于str2
。
- 逻辑运算符:
AND
或&&
:逻辑与OR
或||
:逻辑或NOT
或!
:逻辑非- 例如:
if(a EQUAL 1 AND b LESS 10)
,表示a
等于1 并且b
小于 10。
- 文件和路径判断运算符:
EXISTS
:文件或目录是否存在IS_DIRECTORY
:是否为目录- 例如:
if(EXISTS "path/to/file")
,表示路径path/to/file
存在。
- 正则匹配运算符
MATCHES
:正则匹配
这些运算符可以组合使用,以便进行更复杂的条件判断。还可以使用圆括号((
和 )
)来控制运算符的求值顺序。
7.4 MACRO
在 CMake 中,MACRO
是一种用于定义可重复使用代码片段的机制。类似于函数,它可以接受参数并执行一系列指令。
以下是 MACRO
的基本语法:
c
MACRO(macro_name [argument1 [argument2 ...]])
# 执行的代码块
ENDMACRO()
在 MACRO
中,macro_name
是用户定义的宏名称,用于调用宏。argument1
、argument2
等是可选的参数,在调用宏时可以传递给宏并在宏中使用。
以下是一个示例,演示如何定义和使用宏:
c
MACRO(print_message message)
message("Message: ${message}")
ENDMACRO()
print_message("Hello, World!")
上述示例定义了一个名为 print_message
的宏,它接受一个参数 message
并将其作为消息输出。然后我们调用了这个宏,传递了字符串 "Hello, World!" 作为参数。
8. 非常用命令
8.1 option
用于在 CMakeLists.txt 文件中设置一个布尔型变量,并为该变量提供一个用户可选的开关选项。使用 option
的基本语法如下:
c
option(<variable> "help string" [initial value])
其中:
<variable>
是定义的变量名。"help string"
是该选项的帮助描述。[initial value]
是该选项的初始值,默认为OFF
。
以下是一个示例用法:
c
option(BUILD_EXAMPLES "Build example programs" ON)
上述示例定义了一个 BUILD_EXAMPLES
变量,并为其提供了名称为 "Build example programs"的帮助字符串,并将其默认值设置为 ON
。在编译 CMake 项目时,用户可以通过 -DBUILD_EXAMPLES=OFF
的命令行选项来覆盖默认值。
在 CMakeLists.txt 文件中,我们可以使用 ${BUILD_EXAMPLES}
来引用该变量。例如,我们可以在文件中使用条件语句来根据变量值来控制构建过程:
c
if (BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
当用户选择了 BUILD_EXAMPLES
,则会构建 examples 目录中的项目。
8.2 SET_TARGET_PROPERTIES
在 CMake 中,SET_TARGET_PROPERTIES
命令用于设置目标(可执行文件、库等)的属性。通过这个命令,可以修改目标的属性,例如编译选项、链接选项、输出路径等。
SET_TARGET_PROPERTIES
的基本语法如下:
c
SET_TARGET_PROPERTIES(target1 target2 ... PROPERTIES prop1 value1 prop2 value2 ...)
在上述语法中,target1
、target2
等是目标的名称或者目标列表,prop1
、prop2
等是要修改的属性,value1
、value2
等是要设置的属性值。
以下是几个常用的属性示例:
c
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_EXECUTABLE
或 ADD_LIBRARY
命令创建目标时设置了某些属性,您可以使用 SET_TARGET_PROPERTIES
命令进一步修改这些属性。
8.3 string
在 CMake 中,STRING
是一个用于字符串操作的命令。它提供了一些功能来处理和操作字符串变量。
下面是一些常用的 STRING
命令:
c
#将长度为 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
命令:
LIST(LENGTH <list> <output_variable>)
:获取给定列表的长度并将结果存储在<output_variable>
变量中。
c
#长度为 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
命令的语法:
c
get_filename_component(<variable> <filename> <mode>)
其中,<variable>
是存储提取结果的变量名,<filename>
是要解析的文件路径,<mode>
是提取的模式。
以下是一些常用的 <mode>
值和对应的提取结果:
NAME
: 提取文件名(包括扩展名)。DIRECTORY
: 提取目录路径。EXT
: 提取扩展名(不包括点号)。NAME_WE
: 提取不带扩展名的文件名。
以下是一个示例用法:
c
set(dir "../..")
get_filename_component(root_dir ${dir} ABSOLUTE)
message("Absolute path: ${root_dir}")
这些只是 get_filename_component
命令的一些示例用法。您可以根据需要使用不同的模式提取文件路径中的不同信息。
8.6 message
message
是 CMake 中用于输出消息的命令。它可以将文本消息输出到 CMake 构建过程中,以帮助您调试和查看变量值、结果等。
下面是 message
命令的语法:
c
message([<mode>] "message")
其中,可选的 <mode>
参数用于指定消息输出的模式,常用的模式包括:
STATUS
:以普通方式输出消息。WARNING
:以警告方式输出消息。AUTHOR_WARNING
:以作者警告方式输出消息。SEND_ERROR
:以发送错误方式输出消息,并停止构建过程。FATAL_ERROR
:以致命错误方式输出消息,并停止构建过程。DEPRECATION
:以弃用警告方式输出消息。
以下是一些示例:
c
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
命令的语法:
c
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_FILE
、OUTPUT_FILE
和 ERROR_FILE
参数用于分别指定输入文件、输出文件和错误文件,RESULT_VARIABLE
参数用于指定变量来存储命令的返回值,OUTPUT_VARIABLE
和 ERROR_VARIABLE
参数用于分别指定变量来存储命令的标准输出和标准错误输出,INPUT_VARIABLES
参数用于指定命令执行所需的输入变量。
以下是一些示例:
c
execute_process(COMMAND ls /usr/bin
RESULT_VARIABLE result
OUTPUT_VARIABLE output)
message("Command executed with result: ${result}")
上述示例将运行 ls /usr/bin
命令,并将返回值存储在 result
变量中,同时将标准输出存储在 output
变量中。最后使用 message
命令输出。