当前位置: 首页 > 工具软件 > color-compile > 使用案例 >

从零开始 CMake 学习笔记 (G)compile-flags

宫俊才
2023-12-01

从零开始 CMake 学习笔记 (G)compile-flags

开始前先默念三遍口诀:

  • Declare a target
  • Declare target’s traits
  • It’s all about targets

本系列主要根据GitHub上的 cmake-examples 项目进行翻译总结,同时对于不清晰的概念及函数进行查阅理解记录形成。

1 介绍

本节展示了如何在 CMake 项目中灵活使用编译标志。整体的文件架构如下所示:

1.1 文件树

G-compile-flags $ tree
.
├── CMakeLists.txt
├── main.cpp

1.2 文件简介

  • CMakeLists.txt - 包含了希望运行的 CMake 命令
cmake_minimum_required(VERSION 3.5)

// 设置默认的C++的编译标志
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEX2" CACHE STRING "Set C++ Compiler Flags" FORCE)

// 设置项目名称
project (compile_flags)

// 添加可执行文件
add_executable(cmake_examples_compile_flags main.cpp)

//对可执行二进制文件添加编译标志
target_compile_definitions(cmake_examples_compile_flags 
    PRIVATE EX3
)
  • 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;
}

2 概念解析

    首先,什么是编译标志? 首先,像我们在编译整个项目时,要用哪一个 C++/C 标准来来编译每个项目。CMake 中像我们提供了 CMAKE_CXX_FLAGSCMAKE_C_FLAGS 这样的标志来选择C++/C版本的编译标志。
    其次,对于大型的项目,如果我们想对提升代码的复用性,在使用不同编译标志时,分别执行不同的代码等等,那同样可以对不同的目标设置自己的编译标志,利用 target_compile_definitions() 这个函数。目前视野比较窄,暂时没想到其他用法。

2.1 设置不同目标的编译标志

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

target_compile_definitions(cmake_examples_compile_flags
    PRIVATE EX3
)

上面的语句就是对 可执行二进制文件cmake_examples_compile_flags设置了编译标志 EX3 (如果在此之前它有默认编译标志的话,会继续追加,而不会更改!)。 PRIVATEPUBLICINTERFACE的含义与之前从零开始 CMake 学习笔记 (C)static-librarytarget_include_directories()函数中说过的一样,无非就是三种,我用你不能用我有我不用你用我用大家用,比较好理解。

2.1.1 target_compile_definitions拓展

主要作用是对个目标设置编译标志,完整参数展示如下:

target_compile_definitions(<target>
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

指定编译给定目标时要使用的编译标志。命名目标必须是由 add_executable() 或 add_library() 等命令创建的,并且不能是 ALIAS 目标。

定义、删除与忽略
当然,可以指定,那就需要可以删除的方法,下面命令就展示了清除target_compile_definitions() 指定的编译标志的方法:

target_compile_definitions(foo PUBLIC FOO)  //指定foo库的编译标志为 PUBLIC 状态的 FOO
target_compile_definitions(foo PUBLIC -DFOO)  //-D参数代表移除 foo 库的编译标志 FOO
target_compile_definitions(foo PUBLIC "" FOO) // "" 参数代表目前忽略 foo 库的编译标志 FOO
target_compile_definitions(foo PUBLIC -D FOO) //注意:这里-D后有空格!!!  编译器遇到后会先将 -D 变为 "", 然后忽略这个编译标志!

2.2 设置默认的编译标志

CMake同样提供了 默认的CMAKE_CXX_FLAGS / CMAKE_C_FLAGS的标志来设置整个项目的默认编译标志。 使用如下:

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

关于这个 set 命令,我们在上节已经详细展开过了,也知道要清除 set 设置的值,可以给定一个空值。可以参考上篇博客从零开始 CMake 学习笔记 (F)Build Type

这里的作用就是强制设置默认C++编译标志变量为缓存变量,该缓存变量被定义在文件中,相当于全局变量,源文件中也可以使用这个变量。
注意
    这个变量原本为空的话,会设置为新的给定值,并写入缓存。如果这个变量不为空的话,会追加的写入这个份变量的值,并追加的强行写入缓存。

清除默认标志
像上面,我们用 set 命令设置了默认的 C++ 编译器的标志,若需要清除这个标志,目前了解到的有两种方法:

  1. set 传入空值,这个我们上篇博客从零开始 CMake 学习笔记 (F)Build Type介绍过:
set (CMAKE_CXX_FLAGS "")
  1. 使用 unset 命令,用法如下:
unset (CMAKE_CXX_FLAGS CACHE)

清除 CMAKE_CXX_FLAGS 变量的值,这里添加了 CACHE 表示同时清除缓存中的值

3 运行结果

G-compile-flags $ mkdir build

G-compile-flags $ cd build/

G-compile-flags $ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build

G-compile-flags $ make VERBOSE=1
/usr/bin/cmake -H/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags -B/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/progress.marks
make -f CMakeFiles/Makefile2 all
make[1]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build'
make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/depend
make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build'
cd /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake --color=
Dependee "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/DependInfo.cmake" is newer than depender "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/depend.internal".
Dependee "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/CMakeDirectoryInformation.cmake" is newer than depender "/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles/cmake_examples_compile_flags.dir/depend.internal".
Scanning dependencies of target cmake_examples_compile_flags
make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build'
make -f CMakeFiles/cmake_examples_compile_flags.dir/build.make CMakeFiles/cmake_examples_compile_flags.dir/build
make[2]: Entering directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build'
/usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles 1
[100%] Building CXX object CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o
/usr/bin/c++    -DEX2   -o CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o -c /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/main.cpp
Linking CXX executable cmake_examples_compile_flags
/usr/bin/cmake -E cmake_link_script CMakeFiles/cmake_examples_compile_flags.dir/link.txt --verbose=1
/usr/bin/c++    -DEX2    CMakeFiles/cmake_examples_compile_flags.dir/main.cpp.o  -o cmake_examples_compile_flags -rdynamic
make[2]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build'
/usr/bin/cmake -E cmake_progress_report /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles  1
[100%] Built target cmake_examples_compile_flags
make[1]: Leaving directory `/home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build'
/usr/bin/cmake -E cmake_progress_start /home/matrim/workspace/cmake-examples/01-basic/G-compile-flags/build/CMakeFiles 0
 类似资料: