首先说一下什么是编译标志(或者加,编译选项)。可执行文件的生成离不开编译和链接,那么如何编译,比如编译时使用 C++ 的哪一个标准?

这些编译设置都在 CMAKE_CXX_FLAGS 变量中,而 C 语言编译选项是在 CMAKE_C_FLAGS 变量中。

设置变量的方法有三种,分别是本文的2.1、2.2 以及 2.3

一、文件树

  1. ├── CMakeLists.txt
  2. ├── main.cpp

1.1 main.cpp

  1. #include <iostream>
  2. int main(int argc, char *argv[]) {
  3. std::cout << "Hello, Compile Flags!" << std::endl;
  4. #ifdef EX2
  5. std::cout << "Hello, Compile Flag EX2!" << std:endl;
  6. #endif
  7. #ifdef EX3
  8. std::cout << "Hello, Compile Flag EX3" << std::endl;
  9. #endif
  10. return 0;
  11. }

1.2 CMakeLists.txt

  1. cmake_minimum_required(VERSION 3.5)
  2. project(compile_flags)
  3. # 强制设置默认 C++ 编译标志量为缓存变量
  4. # 如5.build type所说,该缓存变量被定义在文件中,相当于全局变量,源文件中也可以使用这个变量
  5. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Complier Flags" FORCE)
  6. add_executable(cmake_examples_compile_flags main.cpp)
  7. target_compile_definitions(cmake_examples_compile_flags PRIVATE EX3) # 为可执行文件添加私有编译定义

二、CMake命令解析

2.1 方法1:设置每个目标编译标志

在现代 CMake 中设置 C ++ 标志的推荐方法是专门针对某个目标(target)设置标志,可以通过 target_compile_definitions() 函数设置某个目标的编译标志。

  1. target_compile_definitions(cmake_examples_compile_flags
  2. PRIVATE EX3
  3. )

如果这个目标是一个库(cmake_examples_compile_flags),编译器在编译目标时添加定义 -DEX3 ,并且选择了范围 PUBLIC 或 INTERFACE,该定义 -DEX3 也将包含在链接此目标(cmake_examples_compile_flags)的所有可执行文件中。 注意,本语句使用了 PRIVATE,所以编译选项不会传递。

§ 6. Compile Flags - 图1

对于编译器选项,还可以使用 target_compile_options() 函数。

  1. target_compile_options(<target> [BEFORE]
  2. <INTERFACE|PUBLIC|PRIVATE> [items1...]
  3. [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

是给 target 添加编译选项, target 指的是由 add_executable()产生的可执行文件或 add_library()添加进来的库。<INTERFACE|PUBLIC|PRIVATE>指的是[items...] 选项可以传播的范围, PUBLIC and INTERFACE会传播 <target>INTERFACE_COMPILE_DEFINITIONS 属性, PRIVATE and PUBLIC 会传播 targetCOMPILE_DEFINITIONS 属性。

2.2 方法2:设置默认编译标志

默认的 CMAKE_CXX_FLAGS 为空或包含适用于构建类型的标志。 要设置其他默认编译标志,如下使用:

  1. set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)

§ 6. Compile Flags - 图2 强制设置默认 C++ 编译标志变量为缓存变量,如 《5.build type》所说,该缓存变量被定义在文件中,相当于全局变量,源文件中也可以使用这个变量。这个变量原本包含的参数仍然存在,只是添加了 EX2。

§ 6. Compile Flags - 图3 CACHE STRING "Set C++ Compiler Flags" FORCE命令是为了强制将 CMAKE_CXX_FLAGS 变量 放到 CMakeCache.txt 文件中

§ 6. Compile Flags - 图4 "${CMAKE_CXX_FLAGS} -DEX2"这个字符串可以保留原有的 CMAKE_CXX_FLAGS 中的参数,额外添加了一个 EX2 参数。注意写法:空格,并且参数前加了`-D

§ 6. Compile Flags - 图5 类似设置CMAKE_CXX_FLAGS,还可以设置其他选项:

  • 设置C编译标志: CMAKE_C_FLAGS
  • 设置链接标志:CMAKE_LINKER_FLAGS.

2.3 方法3:命令行设置CMake标志

与构建类型类似,可以使用以下方法设置全局 C++ 编译器标志。

  1. 利用 ccmake 或者 gui
  2. 在 cmake 命令行中:
  1. cmake .. -DCMAKE_CXX_FLAGS="-DEX3" # 设置编译标志

2.4 三种方法区别

  • 2.1 方法是被建议的,只为这个目标设置编译选项
  • 2.2 方法的设置 CMAKE_C_FLAGS和CMAKE_CXX_FLAGS 将为该目录或所有包含的子目录中的所有目标全局设置一个编译器标志。 现在不建议使用该方法,首选使用 target_compile_definitions 函数。
  • 2.3 设置的也是全局编译器选项。

三、构建示例

  1. $ cmake ..
  2. -- The C compiler identification is GNU 8.4.1
  3. -- The CXX compiler identification is GNU 8.4.1
  4. -- Detecting C compiler ABI info
  5. -- Detecting C compiler ABI info - done
  6. -- Check for working C compiler: /usr/bin/cc - skipped
  7. -- Detecting C compile features
  8. -- Detecting C compile features - done
  9. -- Detecting CXX compiler ABI info
  10. -- Detecting CXX compiler ABI info - done
  11. -- Check for working CXX compiler: /usr/bin/c++ - skipped
  12. -- Detecting CXX compile features
  13. -- Detecting CXX compile features - done
  14. -- Configuring done
  15. -- Generating done
  16. -- Build files have been written to: /root/CmakeTest/build
  17. $ make VERBOSE=1
  18. /usr/bin/cmake -S/root/CmakeTest -B/root/CmakeTest/build --check-build-system CMakeFiles/Makefile.cmake 0
  19. /usr/bin/cmake -E cmake_progress_start /root/CmakeTest/build/CMakeFiles /root/CmakeTest/build//CMakeFiles/progress.marks
  20. make -f CMakeFiles/Makefile2 all
  21. make[1]: Entering directory '/root/CmakeTest/build'
  22. make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/depend
  23. make[2]: Entering directory '/root/CmakeTest/build'
  24. cd /root/CmakeTest/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /root/CmakeTest /root/CmakeTest /root/CmakeTest/build /root/CmakeTest/build /root/CmakeTest/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake --color=
  25. make[2]: Leaving directory '/root/CmakeTest/build'
  26. make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/build
  27. make[2]: Entering directory '/root/CmakeTest/build'
  28. [ 50%] Building CXX object CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o
  29. /usr/bin/c++ -DEX3 -DEX2 -MD -MT CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o -MF CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o.d -o CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o -c /root/CmakeTest/main.cpp
  30. [100%] Linking CXX executable cmake_examples_compile_flags
  31. /usr/bin/cmake -E cmake_link_script CMakeFiles/cmake_examples_compile_flags.dir/link.txt --verbose=1
  32. /usr/bin/c++ -DEX2 CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o -o cmake_examples_compile_flags
  33. make[2]: Leaving directory '/root/CmakeTest/build'
  34. [100%] Built target cmake_examples_compile_flags
  35. make[1]: Leaving directory '/root/CmakeTest/build'
  36. /usr/bin/cmake -E cmake_progress_start /root/CmakeTest/build/CMakeFiles 0