CMake基础(7)编译标志

简介: CMake基础(7)编译标志

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#


相关文章
|
8月前
|
C语言 Windows
使用CMake调用Makefile 项目
使用CMake调用Makefile 项目
133 0
|
7月前
|
编译器 C语言
C语言编译详解:GCC分步编译与一次编译多个文件
C语言编译详解:GCC分步编译与一次编译多个文件
624 2
|
7月前
我为什么更推荐你使用cmake编译grpc程序?
我为什么更推荐你使用cmake编译grpc程序?
152 0
|
8月前
|
存储 缓存 算法
【Cmake 增加编译参数 】cmake增加编译参数和预处理指令的几种方法
【Cmake 增加编译参数 】cmake增加编译参数和预处理指令的几种方法
353 1
|
8月前
|
编译器 C语言 C++
CMake基础(9)使用Clang编译
CMake基础(9)使用Clang编译
621 0
|
8月前
|
编译器 程序员 C语言
【GCC 参数】 深入C++编译器常用标志:C/C++ 开发者必备的编译器参数
【GCC 参数】 深入C++编译器常用标志:C/C++ 开发者必备的编译器参数
165 0
|
8月前
|
iOS开发 MacOS
CMake基础:CMake中的常用变量的命令
CMake基础:CMake中的常用变量的命令
97 0
|
8月前
|
自然语言处理 编译器 调度
深入gcc编译器:C/C++代码如何变为可执行程序
深入gcc编译器:C/C++代码如何变为可执行程序
248 0
驱动代码使用Makefile的宏
驱动代码使用Makefile的宏
86 0
|
NoSQL 编译器 Linux
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(三)
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解
348 0
【三、深入浅出GCC编译器】一个源文件到可执行文件是如何生成的:GCC编译工具链及编译参数详解(三)

热门文章

最新文章