从零开始 CMake 学习笔记 (F)Build Type
开始前先默念三遍口诀:
- Declare a target
- Declare target’s traits
- It’s all about targets
本系列主要根据GitHub上的 cmake-examples 项目进行翻译总结,同时对于不清晰的概念及函数进行查阅理解记录形成。
文章目录
1 介绍
本示例展示了如何在生成可执行二进制文件中设置编译类型,这些类型可以指定项目的优化级别以及是否在二进制文件中包含调试信息。
1.1 文件树
F-build-type $ tree
.
├── CMakeLists.txt
├── main.cpp
1.2 文件简介
- CMakeLists.txt - 包含了你希望运行的 CMake 命令
// $ cmake --version
cmake_minimum_required(VERSION 3.5)
// 如果编译类型未指定,那么就设置默认编译类型
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
//message可用于在编译cmake时打印信息,比如我们想打印出 `PROJECT_SOURCE_DIR` 这个变量,就可以按下面这行代码
//message("PROJECT_SOURCE_DIR value is ${PROJECT_SOURCE_DIR}") -- 打印`PROJECT_SOURCE_DIR`变量的值
message("Setting build type to 'RelWithDebInfo' as none was specified.")
//给CMAKE_BUILD_TYPE变量赋值为 RelWithDebInfo ,并将这个值写入缓存,并覆盖缓存中该变量之前的值(如果有的话)。
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
// 当使用cmake-gui的时候,设置编译类型的四个可选项
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
// 设置项目名称
project (build_type)
// 添加可执行文件
add_executable(cmake_examples_build_type main.cpp)
- main.cpp - main 文件
#include <iostream>
int main(int argc, char *argv[])
{
std::cout << "Hello Build Type!" << std::endl;
return 0;
}
2 概念解析
2.1 编译类型
CMake具有许多内置的构建配置,可用于编译工程。 这些配置指定了代码优化的级别,以及调试信息是否包含在二进制文件中。主要有下面四种:
-
Release - 发行版。顾名思义,程序完成开发后的发布版本,对代码做了优化,速度非常快,但无法跟踪代码,不能打断点调试。可以在编译器追加后:
-O3 -DNDEBUG
选择此版本。 -
Debug - 调试版。对代码不做任何优化,可以 debug 项目中的任意文件。一般速度相对会慢,而且体积更大。可以在编译器追加后:
-g
选择此版本。 -
RelWithDebInfo - 非常近似与Release版本,代码也是经过优化的,同时还支持添加断点进行调试。可以在编译器追加后:
-Os -DNDEBUG
选择此版本。 -
MinSizeRel - 最小体积版本。类似与Release版本,但更偏重于优化文件大小,而不是运行速度。可以在编译器追加后:
-O2 -g -DNDEBUG
选择此版本。
2.2 设置当前次的编译类型
2.2.1 CMake图形界面
2.2.2 CMake命令行
CMake命令行中,同配置其他参数一致,使用 -D 选项
cmake .. -DCMAKE_BUILD_TYPE=Release
2.3 设置默认的编译类型
CMake提供的默认编译类型时不包含优化的。因此,如果我们想要将设置的编译类型应用于所有用户的各个子项目,那我们可以考虑直接更改默认的编译类型。你可以直接在项目顶层的 CMakeLists.txt 文件中设置如下:
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message("Setting build type to 'RelWithDebInfo' as none was specified.")
//给CMAKE_BUILD_TYPE变量赋值为 RelWithDebInfo ,并将这个值写入缓存,并覆盖缓存中该变量之前的值(如果有的话)。
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
# 当使用cmake-gui的时候,设置编译类型的四个可选项
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release"
"MinSizeRel" "RelWithDebInfo")
endif()
2.3.1 set() 拓展
set() 命令可以为普通变量、缓存变量、环境变量赋值。下面分别对三种变量的设置进行说明。
2.3.1.1 设置普通变量
命令格式:set(<variable> <value>... [PARENT_SCOPE])
命令含义:将变量variable
设置为值<value>...
,变量variable
的 作用域 为调用set
命令的函数或者当前目录,如果使用了PARENT_SCOPE
选项,意味着该变量的作用域会传递到上一层(也就是上一层目录或者当前函数的调用者,如果是函数则传递到函数的调用者,如果是目录则传递到上一层目录),并且在当前作用域该变量不受带PARENT_SCOPE选项的set命令的影响(如果变量之前没有定义,那么在当前作用域仍然是无定义的;如果之前有定义值,那么值和之前定义的值保持一致,类似于之前target_include_directories
的 INTERFACE
命令,我定义但是我不用)。
关于变量的作用域:每一个新的目录或者函数都会创建一个新的作用域,普通变量的作用域,如果不使用PARENT_SCOPE选项,只能从外层往内层传递。
案例1:
最常用的用法示例如下:
cmake_minimum_required(VERSION 3.5)
project (set_test)
set (normal_var a)
message (">>> value =