0x01 介绍
CMake是一个开源的跨平台构建系统,它使用一个名为CMakeLists.txt的文件来描述项目的构建过程。CMake提供了许多编译标志,可用于在编译过程中调整构建过程的行为。
1.CMake编译标志简要
以下是一些常用的CMake编译标志的简要说明:
- CMAKE_BUILD_TYPE:指定项目的构建类型。可能的值包括Debug、Release、RelWithDebInfo和MinSizeRel。
- CMAKE_C_COMPILER和CMAKE_CXX_COMPILER:指定用于编译C和C++代码的编译器。
- CMAKE_C_FLAGS和CMAKE_CXX_FLAGS:指定编译C和C++代码时使用的编译器选项。
- CMAKE_EXE_LINKER_FLAGS:指定链接可执行文件时使用的链接器选项。
- CMAKE_INSTALL_PREFIX:指定安装目标的根目录。
- CMAKE_MODULE_PATH:指定要搜索的CMake模块的目录。
- CMAKE_PREFIX_PATH:指定要搜索的库文件和头文件的目录。
- CMAKE_VERBOSE_MAKEFILE:设置为ON时,会在编译过程中打印所有命令。
这些编译标志可以在CMakeLists.txt文件中使用set命令来设置,或者在命令行中使用-D选项来设置。例如,要将CMAKE_BUILD_TYPE设置为Debug,可以使用以下命令:
cmake -DCMAKE_BUILD_TYPE=Debug
在CMakeLists.txt文件中:
set(CMAKE_BUILD_TYPE Debug)
此外,还有许多其他的CMake编译标志可用,它们的作用各不相同。例如:
- CMAKE_C_STANDARD:指定C语言的标准版本,如C11。
- CMAKE_CXX_STANDARD:指定C++语言的标准版本,如C++11。
- CMAKE_POSITION_INDEPENDENT_CODE:将其设置为ON,则生成的代码将是位置独立的,可以在动态链接库中使用。
- CMAKE_SKIP_INSTALL_ALL_DEPENDENCY:将其设置为ON,则在安装项目时会跳过所有依赖项的安装。
有关CMake编译标志的更多信息,可以参考CMake官方文档:
https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html
2.target_compile_definitions
target_compile_definitions是CMake中的一个内置命令,用于向特定目标的编译器添加定义。它的语法如下:
target_compile_definitions(<target> [INTERFACE|PUBLIC|PRIVATE] [items1...] [items2...] ...)
其中,<target>是要添加定义的目标的名称。接下来的三个参数都是可选的,用于指定定义的可见性。
- INTERFACE:这些定义对于目标的所有用户都是可见的。
- PUBLIC:这些定义对于目标的所有用户和目标的所有依赖项都是可见的。
- PRIVATE:这些定义仅对于目标内部是可见的,对于目标的所有用户和依赖项都是不可见的。
后面的参数是一系列的定义,可以是字符串或者变量。这些定义会被添加到目标的编译器选项中,在编译目标时会生效。
例如,假设我们有一个叫做mylib的库目标,要为它添加一个名为MY_DEFINITION的定义,可以这样写:
target_compile_definitions(mylib PRIVATE MY_DEFINITION)
这会导致在编译mylib时添加-DMY_DEFINITION编译器选项。
target_compile_definitions命令可以在CMakeLists.txt文件中使用,也可以在使用add_definitions命令之后使用。
例如,假设我们有一个库目标mylib和一个可执行文件目标myapp,要为这两个目标添加定义,可以这样写:
add_definitions(-DGLOBAL_DEFINITION)
target_compile_definitions(mylib PRIVATE MY_DEFINITION)
target_compile_definitions(myapp PRIVATE MY_DEFINITION)
这会导致在编译mylib和myapp时添加-DGLOBAL_DEFINITION和-DMY_DEFINITION编译器选项。
注意,如果使用add_definitions命令添加的定义对于所有目标都是可见的,那么使用target_compile_definitions命令添加的定义将被覆盖。
有关target_compile_definitions命令的更多信息,可以参考CMake官方文档:
https://cmake.org/cmake/help/latest/command/target_compile_definitions.html
3.CMAKE_C_FLAGS和CMAKE_CXX_FLAGS
是CMake中的系统变量,用于指定编译C和C++代码时使用的编译器选项。
这两个变量可以在CMakeLists.txt文件中使用set命令来设置,也可以在命令行中使用-D选项来设置。例如,要将CMAKE_C_FLAGS设置为-O2,可以使用以下命令:
在CMakeLists.txt文件中:
set(CMAKE_C_FLAGS "-O2")
在命令行中:
cmake -DCMAKE_C_FLAGS=-O2
这些编译器选项会被添加到所有使用C或C++编译器的目标的编译命令中。
例如,假设我们有一个名为mylib的库目标,它包含一个名为foo.c的C文件,要为这个文件使用-O2优化选项,可以这样写:
set(CMAKE_C_FLAGS "-O2")
add_library(mylib foo.c)
这会导致在编译mylib时使用-O2优化选项。
此外,还可以使用target_compile_options命令为特定目标添加编译器选项。例如,要为mylib目标添加-O2优化选项,可以这样写:
target_compile_options(mylib PRIVATE -O2)
CMAKE_C_FLAGS 和 CMAKE_CXX_FLAGS 是 CMake 中的变量,它们可用于在编译 C 和 C++ 源文件时指定传递给编译器的额外标志。它们可以使用 CMake 脚本中的 set 命令进行设置,例如:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall")
这些标志通常用于启用特定的编译器优化、启用或禁用特定的警告消息,或指定其他编译器选项。
例如,-O2 标志指定编译器应使用优化级别 2(通常在性能和代码大小之间提供良好的平衡)。-Wall 标志启用所有由-Wformat、-Wuninitialized、-Wparentheses 和-Wreturn-type 打开的警告消息。
值得注意的是,CMAKE_C_FLAGS 和 CMAKE_CXX_FLAGS 的值会追加到,而不是替换 CMake 默认的标志。这意味着这些变量中指定的任何标志都将添加到 CMake 设置的默认标志,而不是替换它们。
例如,如果想为 C 源文件启用优化级别 2 并添加一些额外的警告标志,可以在 CMake 脚本中使用以下命令:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -Wformat-security -Wuninitialized")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wformat-security -Wuninitialized")
这将为 C 和 C++ 源文件同时添加 -O2、-Wformat-security 和 -Wuninitialized 标志,而不会替换 CMake 默认的标志。
如果想要完全替换 CMake 默认的标志,可以使用如下命令:
set(CMAKE_C_FLAGS "-O2 -Wformat-security -Wuninitialized")
set(CMAKE_CXX_FLAGS "-O2 -Wformat-security -Wuninitialized")
0x02 示例
CMake 支持以多种不同方式设置编译标志:
- 使用 target_compile_definitions()函数
- 使用 CMAKE_C_FLAGS 和 CMAKE_CXX_FLAGS 变量。
本教程中的文件如下:
ln28@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_07$ tree . ├── CMakeLists.txt ├── build └── main.cpp 1 directory, 2 files
[CMakeLists.txt] - 包含要运行的 CMake 命令
cmake_minimum_required(VERSION 3.1) # Set a default C++ compile flag # set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE) # Set the project name project (compile_flags) # Add an executable add_executable(cmake_examples_compile_flags main.cpp) target_compile_definitions(cmake_examples_compile_flags PRIVATE EX3 ) # cmake .. -DCMAKE_C_FLAGS=-O2 && make -j24 # cmake .. -DCMAKE_CXX_FLAGS=-DEX2 && make -j24
[main.cpp] - 具有 main 的源文件
#include <iostream> int main(int argc, char *argv[]) { std::cout << "Hello Compile Flags!" << std::endl; // only print if compile flag set #ifdef EX2 std::cout << "Hello Compile Flag EX2!" << std::endl; #endif #ifdef EX3 std::cout << "Hello Compile Flag EX3!" << std::endl; #endif return 0; }
cmake .. && make -j24 VERBOSE=1 -- Configuring done -- Generating done -- Build files have been written to: /mnt/d/Project/Cmake_examples/cmake_basics_07/build /usr/bin/cmake -S/mnt/d/Project/Cmake_examples/cmake_basics_07 -B/mnt/d/Project/Cmake_examples/cmake_basics_07/build --check-build-system CMakeFiles/Makefile.cmake 0 /usr/bin/cmake -E cmake_progress_start /mnt/d/Project/Cmake_examples/cmake_basics_07/build/CMakeFiles /mnt/d/Project/Cmake_examples/cmake_basics_07/build/CMakeFiles/progress.marks make -f CMakeFiles/Makefile2 all make[1]: Entering directory '/mnt/d/Project/Cmake_examples/cmake_basics_07/build' make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/depend make[2]: Entering directory '/mnt/d/Project/Cmake_examples/cmake_basics_07/build' cd /mnt/d/Project/Cmake_examples/cmake_basics_07/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /mnt/d/Project/Cmake_examples/cmake_basics_07 /mnt/d/Project/Cmake_examples/cmake_basics_07 /mnt/d/Project/Cmake_examples/cmake_basics_07/build /mnt/d/Project/Cmake_examples/cmake_basics_07/build /mnt/d/Project/Cmake_examples/cmake_basics_07/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake --color= make[2]: Leaving directory '/mnt/d/Project/Cmake_examples/cmake_basics_07/build' make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/build make[2]: Entering directory '/mnt/d/Project/Cmake_examples/cmake_basics_07/build' make[2]: Nothing to be done for 'CMakeFiles/cmake_examples_compile_flags.dir/build'. make[2]: Leaving directory '/mnt/d/Project/Cmake_examples/cmake_basics_07/build' [100%] Built target cmake_examples_compile_flags make[1]: Leaving directory '/mnt/d/Project/Cmake_examples/cmake_basics_07/build' /usr/bin/cmake -E cmake_progress_start /mnt/d/Project/Cmake_examples/cmake_basics_07/build/CMakeFiles 0 ln28@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_07/build$ ./cmake_examples_compile_flags Hello Compile Flags! Hello Compile Flag EX3!
1.设置每个目标的 C++ 标志#
在现代 CMake 中设置 C++ 标志的推荐方式是使用每个目标的标志,这些标志可以通过target_compile_definitions()函数的作用域(或者说接口范围)递到其他目标(INTERFACE 或 PUBLIC)。这将填充库的INTERFACE_COMPILE_DEFINITIONS,并根据作用域将定义传递到链接的目标。
target_compile_definitions(cmake_examples_compile_flags
PRIVATE EX3
)
这将导致编译器在编译目标时添加定义 -DEX3。
如果目标是库,并且已经选择了作用域 PUBLIC 或者 INTERFACE,则该定义也将包含在链接该目标的任何可执行文件中。
对于编译器选项,你还可以使用target_compile_options()函数。
2.设置默认 C++ 标志#
CMAKE_CXX_FLAGS的默认值为空或包含生成类型的相应标志。
要设置其他默认编译标志,可以将以下内容添加到顶级 CMakeLists.txt。
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)
与 CMAKE_CXX_FLAGS 类似的其他选项包括:
- 使用 CMAKE_C_FLAGS 设置 C 编译器标志
- 使用 CMAKE_LINKER_FLAGS 设置链接器标志
上述命令中的值 CACHE STRING "Set C++ Compiler Flags" FORCE
用于强制在 CMakeCache.txt 文件中设置此变量。有关更多详细信息,请参阅此处。
一旦设置,CMAKE_C_FLAGS 和 CMAKE_CXX_FLAGS 将为该目录或任何包含的子目录中的所有目标全局设置编译器标志 / 定义。现在不建议将此方法用于一般用途,最好使用target_compile_definitions函数。
3.设置 CMake 编译器标志
与构建类型类似,可以使用以下方法设置全局 C++ 编译器标志。
- 使用 GUI 工具,如 ccmake/cmake-gui
- 传递到 cmake
注释掉# set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)这行 , 通过命令来添加编译标志 , 正常情况下注释是没有EX2的输出 。
ln28@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_07/build# cmake .. -DCMAKE_CXX_FLAGS=-DEX2 && make -j24 -- Configuring done -- Generating done -- Build files have been written to: /mnt/d/Project/Cmake_examples/cmake_basics_07/build [100%] Built target cmake_examples_compile_flags root@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_07/build# ./cmake_examples_compile_flags Hello Compile Flags! Hello Compile Flag EX2! Hello Compile Flag EX3! ln28@DESKTOP-FS9U3GT:/mnt/d/Project/Cmake_examples/cmake_basics_07/build#