- 1 CMP0003
- 2 ccache
- 3 string
- 4 list
- 5 include
- 6
CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
- 7
if(MSVC)
- 8 set
- 9
CMAKE_BUILD_TYPE
- 10
CMAKE_CXX_FLAGS
- 11 定义预处理宏
-D
- 12 测试框架CTest
- 13
CMakeDependentOption
函数 - 14
CMAKE_ROOT
- 15 CMP0自动检测C++编译器003
- 16 GCC
1 CMP0003
该策略与链接指令的相对路径解析有关,就是在链接共享库时如何解释相对路径。
背景介绍
- OLD 行为: 在旧行为下,相对路径被直接传递给链接器。这可能会导致在构建和运行时出现未定义的行为,因为相对路径是相对于构建目录解释的,而不是相对于目标文件的目录。
- NEW 行为: 在新行为下,CMake 将相对路径转换为绝对路径,确保链接器始终能够正确找到共享库。
使用方法
通过设置cmake_policy(SET CMP0003 NEW)
,告诉CMake
使用新行为处理相对路径。这通常是更安全和可靠的选择,尤其是在复杂的项目中。
示例代码
add_executable(MyExecutable main.cpp)
target_link_libraries(MyExecutable ../lib/mylib)
如果不设置 CMP0003 策略,CMake 可能会将 ../lib/mylib 作为相对路径传递给链接器。在一些情况下,这可能会导致链接失败或者运行时找不到库的问题。而通过设置 cmake_policy(SET CMP0003 NEW)
,CMake 会将 ../lib/mylib
转换为绝对路径,例如 /path/to/project/lib/mylib
,这样可以确保链接器正确找到库文件。
# CMake会解析命令cmake_policy是否存在,若存在返回true,否则返回false
# 注意:这是命令函数
if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif()
2 ccache
set(CMAKE_C_COMPILER "ccache") 在 CMake 脚本中将 C 编译器设置为 ccache。不过,通常这是不对的,因为 ccache 不是一个编译器,而是一个编译器缓存工具,需要编译器来加载这个缓存工具。ccache 是一个用于加速 C/C++ 编译的工具,通过缓存编译结果,当相同的代码再次编译时,可以直接从缓存中获取结果,而不需要实际调用编译器。
要正确地使用 ccache 与 CMake,需要设置 C 和 C++ 编译器来使用 ccache 包装实际的编译器,如 gcc 或 clang。下面是一个示例,展示了如何在 CMake 中正确地使用 ccache:
set(CMAKE_C_COMPILER_LAUNCHER ccache)
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
这个配置告诉 CMake 在调用实际的 C 和 C++ 编译器之前,使用 ccache。
cmake_minimum_required(VERSION 3.0)
project(MyProject)
# 使用 ccache 作为编译器缓存工具
set(CMAKE_C_COMPILER_LAUNCHER ccache)
set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
add_executable(MyExecutable main.cpp)
通过这种方式,可以确保每次构建都会使用 ccache,从而加快重复构建的速度。
-
安装 ccache:
sudo apt-get install ccache
-
配置环境变量(可选): 如果希望 ccache 始终生效,可以在你的 shell 配置文件中添加以下内容:
export PATH="/usr/lib/ccache:$PATH"
-
运行 CMake 构建:
mkdir build cd build cmake .. make
通过这种方式,ccache 会被自动使用,帮助加速编译过程.
3 string
在 CMake 中,string 命令用于处理和操作字符串。它提供了多种功能,可以用于字符串的操作,如查找子字符串、替换子字符串、转换大小写等。以下是一些常见的 string 命令及其用法:
常见用法
-
字符串长度
string(LENGTH "Hello, World!" len)
message(STATUS "The length of the string is: ${len}") -
子字符串提取
string(SUBSTRING "Hello, World!" 7 5 substr)
message(STATUS "The substring is: ${substr}") -
查找子字符串
string(FIND "Hello, World!" "World" pos)
message(STATUS "The position of 'World' is: ${pos}") -
字符串替换
将“Hello, World”字符串中的World替换成CMake
string(REPLACE "World" "CMake" new_string "Hello, World!")
message(STATUS "The new string is: ${new_string}") -
字符串比较
string(COMPARE EQUAL "foo" "foo" result)
if (result)
message(STATUS "Strings are equal")
else()
message(STATUS "Strings are not equal")
endif() -
转换大小写
string(TOUPPER "Hello, World!" upper)
message(STATUS "Uppercase: ${upper}")string(TOLOWER "Hello, World!" lower)
message(STATUS "Lowercase: ${lower}") -
字符串拼接
set(str1 "Hello")
set(str2 "World")
set(full_str "${str1}, ${str2}!")
message(STATUS "The concatenated string is: ${full_str}")
实际示例
假设有一个项目,需要根据某些条件动态生成一些文件名。可以使用 string 命令来处理这些字符串。
cmake_minimum_required(VERSION 3.0)
project(MyProject)
# 提取文件名的基础部分
string(REGEX REPLACE "(.+)\\..*" "\\1" base_name "example.txt")
message(STATUS "Base name: ${base_name}")
SET( MARS_VERSION 2.7.1.240708_rc )
# 将每一个段连续的数字都读取出来,并放在变量MARS_VERSIONS中,且以数组的方式存放
STRING( REGEX MATCHALL "[0-9]+" MARS_VERSIONS ${MARS_VERSION} )
LIST( GET MARS_VERSIONS 0 MARS_VERSION_MAJOR) #
LIST( GET MARS_VERSIONS 1 MARS_VERSION_MINOR)
LIST( GET MARS_VERSIONS 2 MARS_VERSION_PATCH)
# 将文件名转换为大写
string(TOUPPER "${base_name}" upper_base_name)
message(STATUS "Uppercase base name: ${upper_base_name}")
# 生成新的文件名
set(new_file "${upper_base_name}.log")
message(STATUS "New file name: ${new_file}")
在这个示例中,首先提取文件名的基础部分,然后将其转换为大写,最后生成一个新的文件名。
总结
CMake 中的 string 命令非常强大,适用于各种字符串操作和处理任务。这些功能在构建复杂项目时尤其有用,可以帮助你动态生成配置、处理文件路径和名称等。掌握这些命令将使你的 CMake 脚本更加灵活和强大。
4 list
在 CMake 中,list 命令用于操作 CMake 列表。CMake 列表是以分号分隔的一系列字符串,它们可以用来存储和管理多个值。list 命令提供了一组函数来操作这些列表,包括添加、删除、查找、替换和排序列表项等。以下是一些常见的 list 命令及其用法示例:
4.1 常见用法
- 创建和初始化列表
set(MY_LIST "item1;item2;item3")
或者通过追加的方式:
list(APPEND MY_LIST "item1" "item2" "item3")
-
添加元素:
list(APPEND MY_LIST "item4" "item5")
-
插入元素:在指定位置插入元素:
list(INSERT MY_LIST 1 "new_item")
,在索引 1 位置插入 new_item。 -
删除元素:
- 根据索引删除元素:
list(REMOVE_AT MY_LIST 1)
,删除索引 1 位置的元素。 - 根据值删除元素:
list(REMOVE_ITEM MY_LIST "item3")
,删除列表中所有等于 item3 的元素。
- 根据索引删除元素:
-
查找元素:
list(FIND MY_LIST "item2" INDEX)
查找 item2 在列表中的索引,并存储在变量 INDEX 中。如果未找到,INDEX 的值将为 -1。 -
获取列表长度:
list(LENGTH MY_LIST LENGTH)
, 获取列表的长度,并存储在变量 LENGTH 中。list(GET MY_LIST 0 FIRST_ITEM)
, 获取索引 0 位置的元素,并存储在变量 FIRST_ITEM 中。
-
合并两个列表:
list(APPEND LIST1 ${LIST2})
将 LIST2 的元素追加到 LIST1 中。 -
分割字符串为列表:
string(REPLACE ";" ";" MY_LIST "item1;item2;item3")
, 这会将字符串 "item1;item2;item3" 转换为列表 MY_LIST。 -
连接列表为字符串:
list(JOIN MY_LIST "," JOINED_STRING)
,这会将 MY_LIST 中的元素使用逗号连接成一个字符串,并存储在变量JOINED_STRING
中。 -
获取列表元素:
list(GET MARS_VERSION 0 MARS_VERSION_MAJOR)
, 将列表中的第一个元素取出来放到变量MARS_VERSION_MAJOR中
4.2 示例
以下是一个完整的示例,展示了如何在 CMake 中使用 list 命令来操作列表
cmake_minimum_required(VERSION 3.0)
project(ListExample)
# 创建和初始化列表
set(MY_LIST "item1;item2;item3")
# 添加元素
list(APPEND MY_LIST "item4" "item5")
# 插入元素
list(INSERT MY_LIST 1 "new_item")
# 删除元素
list(REMOVE_AT MY_LIST 2)
list(REMOVE_ITEM MY_LIST "item5")
# 查找元素
list(FIND MY_LIST "item3" INDEX)
message(STATUS "Index of item3: ${INDEX}")
# 获取列表长度
list(LENGTH MY_LIST LENGTH)
message(STATUS "Length of MY_LIST: ${LENGTH}")
# 获取列表元素
list(GET MY_LIST 0 FIRST_ITEM)
message(STATUS "First item: ${FIRST_ITEM}")
# 合并两个列表
set(OTHER_LIST "other1;other2")
list(APPEND MY_LIST ${OTHER_LIST})
# 连接列表为字符串
list(JOIN MY_LIST "," JOINED_STRING)
message(STATUS "Joined string: ${JOINED_STRING}")
4.3 总结
在 CMake 中,list 命令是处理和操作列表的强大工具。它可以用来创建、修改和查询列表,方便管理和处理多个值。在构建系统中,列表操作非常常见,因此掌握这些命令将有助于编写更加灵活和高效的 CMake 脚本。
5 include
在 CMake 中,include 命令的作用是引入和执行其他 CMake 脚本文件。这允许你将CMake配置拆分成多个文件,以提高可读性和可维护性。include 命令可以加载指定的CMake文件,并在当前作用域内执行其中的命令。
OPTIONAL
: 如是没有该文件,也不会报警。更加灵活
include(<filename>)
<filename>
是要包含的 CMake 文件的路径。如果文件不存在,CMake 会发出警告。
-
假如有如下目录结构:
project/ ├── CMakeLists.txt ├── src/ │ └── CMakeLists.txt └── cmake/ ├── CommonSettings.cmake └── CompilerOptions.cmake
-
主
CMakeLists.txt
如下:cmake_minimum_required(VERSION 3.10) project(MyProject) # 包含通用设置 include(cmake/CommonSettings.cmake) # 包含编译器选项 include(cmake/CompilerOptions.cmake) # 添加子目录 add_subdirectory(src)
-
CommonSettings.cmake
在 cmake/CommonSettings.cmake 中,你可以定义一些通用设置,例如:# 设置一些通用编译选项 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF)
-
CompilerOptions.cmake
在 cmake/CompilerOptions.cmake 中,你可以定义一些与编译器相关的选项,例如:# 设置编译器选项 if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") endif()
-
条件包含
还可以使用条件语句来有选择地包含文件:
if (EXISTS "${CMAKE_SOURCE_DIR}/cmake/OptionalSettings.cmake") include(cmake/OptionalSettings.cmake) endif()
-
include_guard
为了防止多次包含同一个文件(类似于 C/C++ 中的 include guard),你可以使用 include_guard 命令:
include_guard(GLOBAL)
-
总结
include 命令在 CMake 中的主要作用是允许你将构建配置分散到多个文件中,从而提高配置的可维护性和可读性。通过将常见的设置和选项拆分到单独的文件中,你可以更轻松地管理和复用这些配置。
6 CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
是一个CMake
的内部变量,它表示CMAKE_INSTALL_PREFIX
被初始化为默认值。这个变量通常在第一次运行CMake时设置,当在新的构建树中运行CMake且CMAKE_INSTALL_PREFIX
环境变量未设置时,CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
会被设置为true。
这个变量的主要作用是提供一个默认的prefix值,同时保留从命令行覆盖这个默认值的能力。这意味着,如果用户想要改变安装的前缀路径,就可以通过命令行选项来实现,而不需要手动修改CMakeLists.txt
文件中的设置。这种机制使得CMake更加灵活和用户友好,允许用户在构建和安装过程中根据需要调整安装路径。
7 if(MSVC)
在CMake中,使用if(MSVC)是判断是否使用的是Microsoft Visual Studio的编译器。
当你在CMake脚本中使用if(MSVC)时,你正在检查当前编译器是否为Microsoft Visual Studio的编译器。如果条件为真,即当前使用的是Microsoft Visual Studio编译器,那么CMake会执行if(MSVC)块内的命令。这种检查通常用于根据编译器的不同调整构建配置,例如设置特定的编译标志或选择不同的源代码路径。
此外,CMake还提供了其他方法来检测编译器的具体类型和版本,例如通过检查CMAKE_CXX_COMPILER_ID变量的值来确定是否使用的是MSVC或其他类型的编译器。例如,如果使用的是Microsoft Visual Studio编译器,CMAKE_CXX_COMPILER_ID的值将为"MSVC"。而如果是使用Mingw编译器,其值将为"GNU"12。
总的来说,if(MSVC)在CMake中用于特定于Microsoft Visual Studio编译器的条件判断,允许开发者根据编译器的不同进行相应的配置调整。
8 set
set(<variable> <value> [[CACHE <type> <docstring> [FORCE]] | PARENT_SCOPE])
<type>的值可以是以下值之一
:
FILEPATH = File chooser dialog.
PATH = Directory chooser dialog.
STRING = Arbitrary string.
BOOL = Boolean ON/OFF checkbox.
INTERNAL = No GUI entry (used for persistent variables).
9 CMAKE_BUILD_TYPE
它可以有以下四种情况Debug
, Release
,RelWithDebInfo
, 或 MinSizeRel
在 CMake 中,CMAKE_BUILD_TYPE 变量用于指定构建类型,它决定了编译器和链接器的设置。这些设置通常包括优化级别、调试信息、以及其他相关的编译选项。以下是 CMake 中常见的四种构建类型及其区别:
- Debug
- 特点:包含调试信息,禁用优化。
- 编译器选项:
- GCC/Clang:-g
- MSVC:/Zi
- 用途:用于开发和调试。包含详细的调试信息,方便使用调试器(如 gdb、lldb)进行代码调试。
- Release
- 特点:启用优化,不包含调试信息。
- 编译器选项:
- GCC/Clang:-O3 或 -O2(具体取决于 CMake 版本和配置)
- MSVC:/O2
- 用途:用于发布。生成的二进制文件运行速度更快,文件尺寸更小,但不包含调试信息,调试难度较大。
- RelWithDebInfo (Release with Debug Information)
- 特点:启用优化,包含调试信息。
- 编译器选项:
- GCC/Clang:-O2 -g
- MSVC:/O2 /Zi
- 用途:用于需要调试优化后的代码场合。提供了优化后的性能,同时保留了调试信息,便于调试优化后的代码。
- MinSizeRel (Minimum Size Release)
- 特点:优化以减小生成的二进制文件大小,不包含调试信息。
- 编译器选项:
- GCC/Clang:-Os
- MSVC:/O1
- 用途:用于嵌入式系统或存储受限的环境。目标是生成尽可能小的二进制文件,同时尽量保留一定的性能。
示例:假设我有一个简单的 CMake 项目,以下是如何指定不同的构建类型:
# 生成 Debug 构建
cmake -DCMAKE_BUILD_TYPE=Debug ..
# 生成 Release 构建
cmake -DCMAKE_BUILD_TYPE=Release ..
# 生成 RelWithDebInfo 构建
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..
# 生成 MinSizeRel 构建
cmake -DCMAKE_BUILD_TYPE=MinSizeRel ..
总结
- Debug:用于开发和调试,包含调试信息,禁用优化。
- Release:用于发布,启用优化,不包含调试信息。
- RelWithDebInfo:用于需要调试优化后的代码,启用优化,并包含调试信息。
- MinSizeRel:用于存储受限的环境,启用优化以减小文件大小,不包含调试信息。
这些构建类型帮助开发人员根据不同的需求(如开发调试、发布优化、调试优化代码、减小文件大小)生成合适的二进制文件。
10 CMAKE_CXX_FLAGS
在 CMake 中,CMAKE_CXX_FLAGS
和 CMAKE_CXX_FLAGS_<CONFIG>
用于设置编译器的标志,但它们的作用范围不同:
-
CMAKE_CXX_FLAGS
:这是一个全局变量,包含所有构建类型通用的编译器标志。无论你选择什么构建类型(Debug、Release、RelWithDebInfo、MinSizeRel),这些标志都会应用。 -
CMAKE_CXX_FLAGS_<CONFIG>
:这些是特定于某个构建类型的编译器标志。<CONFIG>
可以是 DEBUG、RELEASE、RELWITHDEBINFO、MINSIZEREL 等。只有在对应的构建类型被选中时,这些标志才会应用。cmake_minimum_required(VERSION 3.10) project(MyProject) # 设置全局的编译器标志 set(CMAKE_CXX_FLAGS "-Wall -Wextra") # 设置特定构建类型的编译器标志 set(CMAKE_CXX_FLAGS_DEBUG "-g") set(CMAKE_CXX_FLAGS_RELEASE "-O3") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os")
解释
-
CMAKE_CXX_FLAGS
:-Wall -Wextra
, 这些标志会在所有构建类型中应用。 -
-DBOOST_FUSION_INVOKE_MAX_ARITY=13
SET ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -DBOOST_FUSION_INVOKE_MAX_ARITY=13 -DRCF_MAX_METHOD_COUNT=400" )
-DBOOST_FUSION_INVOKE_MAX_ARITY=13
是一个编译器选项,用于设置Boost.Fusion
库中的宏BOOST_FUSION_INVOKE_MAX_ARITY
的值。详细解释
Boost.Fusion
是 Boost 库的一部分,提供了一组用于处理异构数据结构的模板库。Boost.Fusion
中的一些功能需要处理不同数量的参数,而这些参数的最大数量可以通过设置宏BOOST_FUSION_INVOKE_MAX_ARITY
来控制。BOOST_FUSION_INVOKE_MAX_ARITY
定义:它是一个宏,用于指定Boost.Fusion
库中函数调用(invoke)的最大参数数量。默认值:这个值在默认情况下可能设置为某个固定值(如 10),但可以根据需要进行调整。
作用:增加这个值可以允许
Boost.Fusion
处理更多参数的函数调用,但这也会增加编译时间和内存使用量。用法示例: 假设我在编译一个使用
Boost.Fusion
的项目,并且需要处理多达 13 个参数的函数调用。我可以通过以下方式设置这个值:在命令行中设置:
cmake -DBOOST_FUSION_INVOKE_MAX_ARITY=13 ..
在 CMakeLists.txt 中设置
add_definitions(-DBOOST_FUSION_INVOKE_MAX_ARITY=13)
在源代码中设置 我也可以在源代码中定义这个宏,但这种方式需要在包含任何 Boost.Fusion 头文件之前进行定义:
cpp代码如下:
#define BOOST_FUSION_INVOKE_MAX_ARITY 13 #include <boost/fusion/include/invoke.hpp>
具体示例 假设我有一个使用 Boost.Fusion 的函数,需要处理 13 个参数:
cpp代码如下:
#include <boost/fusion/include/invoke.hpp> #include <boost/fusion/tuple.hpp> #include void my_function(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l, int m) { std::cout << "Sum: " << (a + b + c + d + e + f + g + h + i + j + k + l + m) << std::endl; } int main() { #define BOOST_FUSION_INVOKE_MAX_ARITY 13 boost::fusion::tuple<int, int, int, int, int, int, int, int, int, int, int, int, int> args(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13); boost::fusion::invoke(&my_function, args); return 0; }
在这个例子中,我定义了一个接受 13 个参数的函数 my_function,并使用 Boost.Fusion 的 invoke 函数调用它。通过设置 BOOST_FUSION_INVOKE_MAX_ARITY 为 13,我们确保 Boost.Fusion 可以处理这个函数调用。
总结
-DBOOST_FUSION_INVOKE_MAX_ARITY=13 是一个编译选项,用于设置
Boost.Fusion
库中处理函数调用的最大参数数量。通过增加这个值,可以让 Boost.Fusion 处理更多参数的函数调用,但这也可能增加编译时间和内存使用量。这个设置在需要处理多参数函数调用的情况下非常有用。
11 定义预处理宏-D
在 CMakeLists.txt
文件中,设置 CMAKE_CXX_FLAGS
为 -DRCF_MAX_METHOD_COUNT=400
的作用如下:
-
定义预处理器宏
-D
选项用于定义一个预处理器宏。在这种情况下,RCF_MAX_METHOD_COUNT
被定义为400
。这意味着在编译代码时,所有引用RCF_MAX_METHOD_COUNT
的地方都会被替换为400
。 -
影响编译行为
RCF_MAX_METHOD_COUNT
这个宏的具体作用取决于它在代码中的使用方式。通常,这样的宏定义用于控制代码中的某些配置参数。例如,它可能用于限制或设置某个特定功能的最大值或数量。在这个例子中,RCF_MAX_METHOD_COUNT
可能用于限制某个框架(可能是Remote Call Framework, RCF
)的最大方法数量为 400。 -
代码可读性和可维护性
通过在CMakeLists.txt
中设置预处理器宏,可以使得配置参数更加集中和统一管理。这样,当需要更改这些参数时,只需修改一个地方,而不是在多个文件中手动查找和替换。
具体作用还需要参考项目的相关文档或者代码实现,来看RCF_MAX_METHOD_COUNT
在代码中具体如何使用。例如,它可能用于控制某个数组的大小、某些数据结构的容量、某个循环的次数等等。
12 测试框架CTest
在 CMake 中使用 include(CTest)
和 enable_testing()
有助于为项目配置和启用测试功能。具体作用如下:
include(CTest)
-
引入CTest模块: CTest 是 CMake 自带的测试框架模块,通过
include(CTest)
可以引入该模块。CTest 提供了运行和管理测试的功能。 -
定义测试目标: 通过引入 CTest 模块,你可以使用 CTest 提供的命令(如
add_test(
))来定义测试目标。 -
支持持续集成: 通过引入 CTest 模块,可以更容易地集成到持续集成系统中,如 Jenkins、GitHub Actions 等。
enable_testing()
-
启用测试: 该命令在项目中启用测试功能。它会生成必要的测试文件(如
CTestTestfile.cmake
),并设置测试的基本配置。 -
允许定义测试: 在调用
enable_testing()
之后,你可以使用 CMake 提供的add_test()
命令来添加测试。这些测试可以是可执行文件、脚本或其他可以被执行的程序。 -
支持运行测试: 启用测试后,你可以使用 ctest 命令来运行项目中的测试。例如,运行 ctest 命令可以执行所有定义的测试并报告结果。
下面是一个简化的示例 CMakeLists.txt,展示了如何使用 include(CTest) 和 enable_testing():
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 引入CTest模块
include(CTest)
# 启用测试
enable_testing()
# 添加可执行文件
add_executable(my_program main.cpp)
# 添加测试,NAME是MyTest,运行的可执行文件是my_program
add_test(NAME MyTest COMMAND my_program)
在这个示例中:
include(CTest)
: 引入了 CTest 模块,使得我可以使用 add_test() 命令。enable_testing()
: 启用了测试功能。add_test(NAME MyTest COMMAND my_program)
: 定义了一个名为 MyTest 的测试,该测试会运行 my_program 可执行文件。
通过这种方式,我可以轻松地在 CMake 项目中配置和管理测试,从而确保项目的质量和可靠性。
13 CMakeDependentOption
函数
在 CMake 中,include(CMakeDependentOption) 的主要作用是引入 CMakeDependentOption 模块,以便在 CMakeLists.txt 中使用 CMakeDependentOption() 函数。这些函数可以创建相互依赖的选项(即配置选项),根据某些条件来决定是否启用某个选项。这样可以更加灵活地管理项目配置。
具体来说,CMakeDependentOption() 函数可以根据其他选项的值来自动设置当前选项的默认值,并可以在条件不满足时隐藏该选项。这样可以避免用户在配置项目时混淆或误设无效的选项。
13.1 使用 include(CMakeDependentOption) 的步骤:
-
引入模块:在
CMakeLists.txt
文件中引入CMakeDependentOption
模块。include(CMakeDependentOption)
-
定义依赖选项:使用
CMakeDependentOption()
定义依赖关系。CMakeDependentOption(
OPTION_NAME # 选项名称
"Description of the option" # 选项描述
ON # 默认值
"DEPENDENT_OPTION" # 依赖选项或条件
"CONDITION" # 条件
)
13.2 示例
假设有一个项目,它有一个主选项 ENABLE_FEATURE
,以及一个依赖于它的子选项 ENABLE_SUBFEATURE
。我可以如下配置:
cmake_minimum_required(VERSION 3.0)
project(ExampleProject)
include(CMakeDependentOption)
option(ENABLE_FEATURE "Enable the main feature" ON)
CMakeDependentOption(
ENABLE_SUBFEATURE # 子选项名称
"Enable the sub-feature" # 子选项描述
ON # 默认值
"ENABLE_FEATURE" # 依赖选项
"ENABLE_FEATURE" # 条件,这个条件如何理解
)
if (ENABLE_FEATURE)
message(STATUS "Main feature is enabled.")
if (ENABLE_SUBFEATURE)
message(STATUS "Sub-feature is enabled.")
else()
message(STATUS "Sub-feature is disabled.")
endif()
else()
message(STATUS "Main feature is disabled.")
endif()
在这个例子中,如果 ENABLE_FEATURE
被禁用(OFF
),则ENABLE_SUBFEATURE
也会被禁用,且用户在 CMake GUI
或命令行中看不到 ENABLE_SUBFEATURE
选项。这种依赖关系使得配置选项更加直观和便于管理。
14 CMAKE_ROOT
CMAKE_ROOT
:/usr/share/cmake-3.5
15 自动检测C++编译器
INCLUDE (${CMAKE_ROOT}/Modules/CMakeDetermineCXXCompiler.cmake)
是 CMake 中用于确定 C++ 编译器的模块。这个命令在配置 CMake 项目时有助于自动检测和设置适当的 C++ 编译器,使得构建过程更加简化和自动化。
15.1 作用和功能
自动检测 C++ 编译器:CMakeDetermineCXXCompiler.cmake
模块会搜索系统中可用的 C++ 编译器,并选择一个适合的编译器。例如,它会检查 g++、clang++ 等常见的 C++ 编译器。
设置相关变量:该模块会设置一些关键的 CMake 变量,如 CMAKE_CXX_COMPILER
,这些变量在后续的配置和构建过程中会被使用。
检查编译器有效性:它会验证找到的编译器是否可用,确保所选的编译器能够正确编译和链接 C++ 代码。
- 编译器
GCC
本身包含多个编译器,(如:gcc
用于C
,g++
用于C++
),负责将源代码转换为目标代码(中间的机器码)
15.2 使用场景
在一些自定义的 CMake 配置文件或项目中,可能需要显式包含这个模块来确保编译器的检测和设置。这在某些特殊的构建环境或复杂的项目中可能特别有用。
15.2.1 示例
以下是一个示例,说明如何在自定义的 CMake 脚本中使用 CMakeDetermineCXXCompiler.cmake 模块:
cmake_minimum_required(VERSION 3.0)
# 指定项目名称和语言
project(ExampleProject CXX)
# 显式包含 CMakeDetermineCXXCompiler 模块
INCLUDE(${CMAKE_ROOT}/Modules/CMakeDetermineCXXCompiler.cmake)
# 其他项目配置和设置
set(SOURCE_FILES main.cpp)
add_executable(ExampleExecutable ${SOURCE_FILES})
# 输出所选择的编译器
message(STATUS "C++ Compiler: ${CMAKE_CXX_COMPILER}")
在这个示例中,INCLUDE(${CMAKE_ROOT}/Modules/CMakeDetermineCXXCompiler.cmake) 会自动检测系统上的 C++ 编译器,并设置相关变量。然后,我们可以使用这些变量进行进一步的配置和构建过程。
15.3 总结
INCLUDE(${CMAKE_ROOT}/Modules/CMakeDetermineCXXCompiler.cmake) 在 CMake 中主要用于自动检测和设置 C++ 编译器,确保项目能够在不同的构建环境中正确编译和链接。这对提高构建过程的自动化和可移植性非常有帮助。
16GCC
GCC(GNU Compiler Collection)不仅是编译器,也是链接器。GCC 充当了一个集成工具,调用了不同的程序来完成每个阶段的工作。
16.1 编译器和链接器
编译器:GCC 本身包含了多个编译器(如 gcc 用于 C,g++ 用于 C++),负责将源代码转换为目标代码(中间的机器代码)。
链接器:GCC 调用了链接器(通常是 ld),负责将多个目标文件和库文件链接在一起,生成可执行文件。
16.2 GCC 的角色
作为编译器驱动程序:GCC 根据命令行参数自动决定调用预处理器
、编译器
、汇编器
和链接器
的顺序。我只需使用一个命令,它就会自动完成整个编译和链接过程。
作为链接器的接口:在链接阶段,GCC 充当接口,将目标文件和库文件传递给链接器(通常是 ld
)以生成可执行文件