0x01 介绍
CMake 有许多内置的构建配置,可用于编译你的项目。它们指定优化级别以及调试信息是否包含在二进制文件中。CMAKE_BUILD_TYPE 是 CMake 中的一个变量,它指定了要使用的编译选项。
提供的级别包括:
- Release - 将标志-O3 -DNDEBUG添加到编译器
- Debug - 添加标志-g
- MinSizeRel - 添加标志-Os -DNDEBUG
- RelWithDebInfo - 添加标志-O2 -g -DNDEBUG
可以在 CMake 项目的根目录下的 CMakeLists.txt 文件中使用 set 命令来设置 CMAKE_BUILD_TYPE 变量:
set(CMAKE_BUILD_TYPE Debug)
也可以在命令行上使用 -DCMAKE_BUILD_TYPE=<type> 选项来设置 CMAKE_BUILD_TYPE 变量:
cmake -DCMAKE_BUILD_TYPE=Debug path/to/source
当 CMake 生成器生成构建脚本时,它会使用 CMAKE_BUILD_TYPE 的值来确定使用哪些编译选项。例如,如果 CMAKE_BUILD_TYPE 设置为 Debug,则 CMake 会启用调试信息和其他与调试有关的编译选项。
有关 CMAKE_BUILD_TYPE 变量的更多信息,请参阅 CMake 文档:
https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
CMake 生成类型是指 CMake 生成器使用的编译器或构建工具的类型。CMake 支持多种不同的生成类型,如 Unix Makefiles、Ninja、Visual Studio、Xcode 等。
可以使用 -G 选项在命令行上指定 CMake 生成类型。例如,要使用 Unix Makefiles 生成类型,可以在命令行上运行:
cmake -G "Unix Makefiles" path/to/source
CMake 生成类型可以影响 CMake 生成器生成的文件和目录的结构,以及使用的编译器和构建工具的选择。因此,在选择 CMake 生成类型时应该考虑最终需要生成的目标平台和构建工具。
在使用 CMake 构建 C++ 项目时,常见的选择是 Unix Makefiles 或 Ninja 生成类型,或者使用 Visual Studio 生成类型在 Windows 上构建。如果要在 macOS 或 iOS 上构建,则可以使用 Xcode 生成类型。
有关 CMake 生成类型的更多信息,请参阅 CMake 文档:
https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html
0x02 示例
本教程中的文件如下:
root@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_06# tree . ├── CMakeLists.txt ├── build └── main.cpp 1 directory, 2 files [CMakeLists.txt] - 包含你希望运行的 CMake 命令 # 指定CMake的最低版本要求。 cmake_minimum_required(VERSION 3.1) # Set a default build type if none was specified if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message("Setting build type to 'RelWithDebInfo' as none was specified.") set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() # Set the project name project (build_type) # Add an executable add_executable(cmake_examples_build_type main.cpp)
[main.cpp] - 主源文件
#include <iostream> int main(int argc, char *argv[]) { std::cout << "Hello Build Type!" << std::endl; return 0; }
root@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_06/build# cmake .. -DCMAKE_BUILD_TYPE=Release && make -j24 VERBOSE=1 -- Configuring done -- Generating done -- Build files have been written to: /mnt/d/Project/Cmake_examples/cmake_basics_06/build /usr/bin/cmake -S/mnt/d/Project/Cmake_examples/cmake_basics_06 -B/mnt/d/Project/Cmake_examples/cmake_basics_06/build --check-build-system CMakeFiles/Makefile.cmake 0 /usr/bin/cmake -E cmake_progress_start /mnt/d/Project/Cmake_examples/cmake_basics_06/build/CMakeFiles /mnt/d/Project/Cmake_examples/cmake_basics_06/build/CMakeFiles/progress.marks make -f CMakeFiles/Makefile2 all make[1]: Entering directory '/mnt/d/Project/Cmake_examples/cmake_basics_06/build' make -f CMakeFiles/cmake_examples_build_type.dir/build.make CMakeFiles/cmake_examples_build_type.dir/depend make[2]: Entering directory '/mnt/d/Project/Cmake_examples/cmake_basics_06/build' cd /mnt/d/Project/Cmake_examples/cmake_basics_06/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /mnt/d/Project/Cmake_examples/cmake_basics_06 /mnt/d/Project/Cmake_examples/cmake_basics_06 /mnt/d/Project/Cmake_examples/cmake_basics_06/build /mnt/d/Project/Cmake_examples/cmake_basics_06/build /mnt/d/Project/Cmake_examples/cmake_basics_06/build/CMakeFiles/cmake_examples_build_type.dir/DependInfo.cmake --color= make[2]: Leaving directory '/mnt/d/Project/Cmake_examples/cmake_basics_06/build' make -f CMakeFiles/cmake_examples_build_type.dir/build.make CMakeFiles/cmake_examples_build_type.dir/build make[2]: Entering directory '/mnt/d/Project/Cmake_examples/cmake_basics_06/build' [ 50%] Building CXX object CMakeFiles/cmake_examples_build_type.dir/main.cpp.o /usr/bin/c++ -O3 -DNDEBUG -o CMakeFiles/cmake_examples_build_type.dir/main.cpp.o -c /mnt/d/Project/Cmake_examples/cmake_basics_06/main.cpp [100%] Linking CXX executable cmake_examples_build_type /usr/bin/cmake -E cmake_link_script CMakeFiles/cmake_examples_build_type.dir/link.txt --verbose=1 /usr/bin/c++ -O3 -DNDEBUG -rdynamic CMakeFiles/cmake_examples_build_type.dir/main.cpp.o -o cmake_examples_build_type make[2]: Leaving directory '/mnt/d/Project/Cmake_examples/cmake_basics_06/build' [100%] Built target cmake_examples_build_type make[1]: Leaving directory '/mnt/d/Project/Cmake_examples/cmake_basics_06/build' /usr/bin/cmake -E cmake_progress_start /mnt/d/Project/Cmake_examples/cmake_basics_06/build/CMakeFiles 0
1.设置生成类型
可以使用以下方法设置生成类型。
- 使用 GUI 工具,如 ccmake/cmake-gui
- 通过命令行传递到 cmake:
cmake .. -DCMAKE_BUILD_TYPE=Release
2.设置默认生成类型
CMake 提供的默认构建类型是不包含用于优化的编译器标志。对于某些项目,你可能希望设置默认生成类型,以便不必记住设置它。为此,你可以将以下代码添加到顶级 CMakeLists.txt 中。
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message("Setting build type to 'RelWithDebInfo' as none was specified.") set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif()
3.set_property
在指定域中设置一个命名属性
CMake 的 set_property 命令允许在 CMake 工程中设置属性。这些属性可以为特定目标(例如库或可执行文件)或特定源文件设置,也可以为整个工程设置。
set_property(<GLOBAL | DIRECTORY [dir] | TARGET target [APPEND] | SOURCE source
[APPEND]> PROPERTY <name> [value1 [value2 [...]]])
其中:
- GLOBAL 表示将属性设置为整个工程的全局属性 , 唯一的,并且不接特殊的任何名字。
- DIRECTORY 表示将属性设置为指定目录下的属性 , 默认为当前目录,但也可以用全路径或相对路径指定其他的目录(前提是该目录已经被 CMake 处理)。
- TARGET 表示将属性设置为指定目标的属性 , 可命名零或多个已经存在的目标。
- SOURCE 表示将属性设置为指定源文件的属性 , 可命名零或多个源文件。注意:源文件属性只对在相同目录下的目标是可见的 (CMakeLists.txt)。
可以使用 APPEND 选项将值添加到已存在属性的值列表中,而不是覆盖它。
例如,可以使用以下命令将目标 my_target 的 PUBLIC_HEADER 属性设置为包含文件 my_header.h:
set_property(TARGET my_target PROPERTY PUBLIC_HEADER my_header.h)
可以使用以下命令将目录 src 的 INCLUDE_DIRECTORIES 属性设置为包含目录 include:
set_property(DIRECTORY src PROPERTY INCLUDE_DIRECTORIES include)
必选项 PROPERTY 后面紧跟着要设置的属性的名字。其他的参数用于构建以分号隔开的列表形式的属性值。如果指定了 APPEND 选项,则指定的列表将会追加到任何已存在的属性值当中。如果指定了 APPEND_STRING 选项,则会将值作为字符串追加到任何已存在的属性值。
以使用 set_property 命令来设置各种类型的属性,具体取决于选择的目标、源文件或目录。有关可用属性的完整列表,参阅 CMake 文档:
https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html
这里是一些常见属性的例子:
- INCLUDE_DIRECTORIES:设置包含目录列表。这些目录将用于编译器搜索头文件。
- COMPILE_DEFINITIONS:设置编译器定义列表。这些定义将用于编译代码。
- COMPILE_OPTIONS:设置编译器选项列表。这些选项将用于编译代码。
- LINK_LIBRARIES:设置链接库列表。这些库将用于链接目标。
- LINK_OPTIONS:设置链接器选项列表。这些选项将用于链接目标。
例如,可以使用以下命令将目录 src 的 INCLUDE_DIRECTORIES 属性设置为包含目录 include:
set_property(DIRECTORY src PROPERTY INCLUDE_DIRECTORIES include)
也可以使用以下命令将目标 my_target 的 LINK_LIBRARIES 属性设置为包含库 my_lib:
set_property(TARGET my_target PROPERTY LINK_LIBRARIES my_lib)
可以使用 set_property 命令来设置自定义属性。这些自定义属性可以在 CMake 脚本中使用,也可以在生成工具(如 make)中使用。
为了在 CMake 脚本中使用自定义属性,可以使用 get_property 命令来获取属性值。例如,假设使用以下命令设置了目标 my_target 的自定义属性 MY_CUSTOM_PROPERTY:
set_property(TARGET my_target PROPERTY MY_CUSTOM_PROPERTY value)
然后,可以使用以下命令获取该属性的值:
get_property(custom_property TARGET my_target PROPERTY MY_CUSTOM_PROPERTY)
在 CMake 脚本外,还可以在生成工具(如 make)中使用自定义属性。例如,假设使用以下命令设置了目标 my_target 的自定义属性 MY_CUSTOM_PROPERTY:
set_property(TARGET my_target PROPERTY MY_CUSTOM_PROPERTY value)
然后,可以在 make 命令中使用如下所示的环境变量来访问该属性:
make my_target MY_CUSTOM_PROPERTY=new_value
请注意,在使用自定义属性时,需要自行确保属性名称的唯一性。
有关使用自定义属性的更多信息,参阅 CMake 文档:
https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html#custom
需要注意的是,set_property 命令仅在当前 CMake 脚本中有效。如果希望在多个 CMake 脚本之间共享属性值,则可以使用 set 命令将变量设置为全局变量。然后,可以在其他 CMake 脚本中使用 get_property 命令获取该变量的值。
例如,假设在 CMake 脚本 A 中使用以下命令设置了全局变量 MY_VAR:
set(MY_VAR value CACHE STRING "My variable")
然后,在 CMake 脚本 B 中,可以使用以下命令获取该变量的值:
get_property(my_var CACHE MY_VAR PROPERTY VALUE)
有关使用 set 命令设置全局变量的更多信息,参阅 CMake 文档:
https://cmake.org/cmake/help/latest/command/set.html
4.get_property
get_property 是 CMake 命令,用于获取指定对象的属性值。
用法:
get_property(<output variable> <scope> <property> [<variable>])
参数说明:
- output variable:用于存储属性值的变量名。
- scope:要查询属性的对象的作用域。可能的值有:
- GLOBAL:全局作用域(整个 CMake 项目)
- DIRECTORY:当前目录作用域(当前 CMakeLists.txt 文件所在目录)
- TARGET:目标作用域(指定的目标)
- SOURCE:源文件作用域(指定的源文件)
- CACHE:缓存作用域(整个 CMake 项目的缓存)
- TEST:测试作用域(指定的测试)
- property:要查询的属性名称。
- variable:可选参数,用于在查询属性时指定变量。
例如,要查询全局作用域中的 CMAKE_BUILD_TYPE 属性的值,可以使用以下命令:
get_property(build_type GLOBAL PROPERTY CMAKE_BUILD_TYPE)
这样,build_type 变量就会被设置为 CMAKE_BUILD_TYPE 属性的值。
注意:如果指定的属性不存在,get_property 命令将会失败。因此,在使用 get_property 命令时,应该先使用 set_property 命令设置属性值
你可能还想知道,get_property 命令还有一个重载版本,允许查询指定变量的值:
get_property(<output variable> <variable> [<property>])
参数说明:
- output variable:用于存储变量值的变量名。
- variable:要查询的变量名。
- property:可选参数,用于在查询变量时指定属性。
例如,要查询全局作用域中的 CMAKE_BUILD_TYPE 变量的值,可以使用以下命令:
get_property(build_type VARIABLE CMAKE_BUILD_TYPE)
这样,build_type 变量就会被设置为 CMAKE_BUILD_TYPE 变量的值。
注意:如果指定的变量不存在,get_property 命令将会失败。因此,在使用 get_property 命令时,应该先使用 set 命令设置变量值。
相关域的说明与 set_property 意义相同。
有关使用 get_property 命令获取变量值的更多信息,参阅 CMake 文档:
https://cmake.org/cmake/help/latest/command/get_property.html