工程实践:CMake 编译类型的配置

以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」mp.weixin.qq.com/s/CsvCzH6r8...

程序在正常情况下的运转,我们都希望它跑得又稳又快,资源又不占用太多,文件大小还不占空间,在开发者看来,这属于发布版本,编译输出时应该是 Release 模式。

相反,在软件开发过程中,大多数时候编译类型都是默认调试(Debug)模式,因为 Debug 模式可以输出大量方便调试的信息,在 linux 系统下甚至允许产生 core-dump 文件,帮助还原崩溃现场的堆栈信息,但对运行速度却没有过多要求。

那么为什么编译类型不同会对执行程序的使用产生不一样的能力呢?

其实说白了,编译类型对执行程序的影响是通过编译器在编译时对软件功能的开关作用和代码结构的转化等。不同编译参数和选项,开关不同的功能,比如调试信息的输出,以及对应不同的代码优化策略:

冗余的删除,比如死代码删除,常量或者复写传播,公共子表达式删除等等。
计算强度削弱,包含但不仅限于一些基于逻辑或者算术表达式的优化,例如把乘法转化成一系列的位移和加减法的组合,常量计算过程转换成结果等。
扩大优化器的作用范围的优化,例如内联,基本块合并等等,基本目的在于获得更大的优化目标
体系相关的优化,简单如指令选择时的一些窥孔性质的指令合并,复杂如寄存器分配,指令调度等np问题的解决。

以 C/C++ 流行的构建系统 cmake 为例,cmake 会依据预定义的编译类型给编译器输入指定的参数和标志位,也即是说编译类型对于 cmake 来说就是枚举类型,但是每个类型分别对应着不同的编译参数和标志。既然如此,编译类型其实也可以自定义,因为最终关心的是给编译器输入什么具体参数。

那么除了 debug 模式,cmake 提供了哪几种预定义的可配置编译类型呢?

CMAKE_BUILD_TYPE 说明
Debug 调试版本,没有优化,开启断言,最全调试信息
Release 正式版本,最高优化,没有调试信息,关闭断言
MinSizeRel 体积较小的版本,但速度没有优化
RelWithDebInfo 优化,保留了调试信息,关闭断言

上面的这些预定义的编译类型又是如何控制传递给编译器的参数和标志位呢?

Cmake 提供了两组很直观的参数变量:

CMAKE_<LANG>_FLAGS
CMAKE_C_FLAGS
CMAKE_CXX_FLAGS
...
CMAKE_<LANG>_FLAGS_<CONFIG>
CMAKE_C_FLAGS_DEBUG
CMAKE_CXX_FLAGS_DEBUG
CMAKE_C_FLAGS_RELEASE
CMAKE_CXX_FLAGS_RELEASE
CMAKE_C_FLAGS_MINSIZEREL
CMAKE_CXX_FLAGS_MINSIZEREL
CMAKE_C_FLAGS_RELWITHDEBINFO
CMAKE_CXX_FLAGS_RELWITHDEBINFO
...

CMAKE_<LANG>_FLAGS 变量组存储的是针对特定语言的编译参数和选项。编译代码的时候,编译器输入的参数会包含这组参数变量中对应变量的内容。

比如,编译 C 语言代码,会传输 CMAKE_C_FLAGS 的内容给到编译器;编译 C++ 语言代码,会传输 CMAKE_CXX_FLAGS 的内容给到编译器。

通常,CMAKE_<LANG>_FLAGS_<CONFIG> 变量组会包含特定语言特定模式的对应编译参数和选项。编译代码的时候,编译器输入的参数会按照编译类型来决定包含这组参数变量中对应变量的内容。

比如,编译 C 语言代码,如果选择 Debug 模式,会输入 CMAKE_C_FLAGS_DEBUG 的内容给到编译器;如果选择 Release 模式,会输入 CMAKE_C_FLAGS_RELEASE 的内容给到编译器,以此类推。

配置方法

1. 配置 CMAKE_<LANG>_FLAGS

如果是直接配置 CMAKE_<LANG>_FLAGS 的值,则可以忽略 CMAKE_BUILD_TYPE 的值。<LANG> 代指各种编程语言,比如 C、CXX

scss 复制代码
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -lm -lrt -Os -g -rdynamic -funwind-tables -ffunction-sections")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -lm -lrt -Os -g -rdynamic -funwind-tables -ffunction-sections")
SET(LIBRARY_OUTPUT_PATH "./../../src/libs")

但通常写法是利用 CMAKE_BUILD_TYPE 的值作为条件变量,用于判断选择配置 CMAKE_<LANG>_FLAGS 的值

scss 复制代码
IF (CMAKE_BUILD_TYPE STREQUAL Debug)
    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -lm -lrt -Os -g -rdynamic -funwind-tables -ffunction-sections -Wall -Werror")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -lm -lrt -Os -g -rdynamic -funwind-tables -ffunction-sections -Wall -Werror")
ELSEIF (CMAKE_BUILD_TYPE STREQUAL Release)
    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -lm -lrt -Os -s -ffunction-sections -Wall")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -lm -lrt -Os -s -ffunction-sections -Wall -Werror")
ELSE ()
    SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread -lm -lrt -Os -s")
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -lm -lrt -Os -s")
ENDIF()

2. 配置 CMAKE_<LANG>_FLAGS_<CONFIG>

配置所有 CMAKE_<LANG>_FLAGS_<CONFIG> 的值,CMake 自动根据 CMAKE_BUILD_TYPE 的值选择将哪个 CMAKE_<LANG>_FLAGS_<CONFIG> 值传递给编译器

bash 复制代码
# SET(CMAKE_BUILD_TYPE Debug)
SET(CMAKE_BUILD_TYPE Release)

SET(FLAGS_C "-pthread -lm -lrt")
SET(FLAGS_CXX "-pthread -lm -lrt")

SET(FLAGS_DEBUG "-g -rdynamic -funwind-tables -ffunction-sections -Wall -ggdb")
#SET(FLAGS_RELEASE "-O3 -s -DNDEBUG -DLINUX -fshort-enums -lmsmart")
SET(FLAGS_RELEASE "-pthread -lm -lrt -Os -s -fPIC -O2 -g -DLINUX -Wall -Werror")
SET(FLAGS_MINSIZEREL "-Os -s -DNDEBUG")

SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} ${FLAGS_C} ${FLAGS_DEBUG}")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS} ${FLAGS_CXX} ${FLAGS_DEBUG}")
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} ${FLAGS_C} ${FLAGS_RELEASE}")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS} ${FLAGS_CXX} ${FLAGS_RELEASE}")
SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS} ${FLAGS_C} ${FLAGS_MINSIZEREL}")
SET(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS} ${FLAGS_CXX} ${FLAGS_MINSIZEREL}")

从名字来看,cmake 的自带变量都是以 CMAKE 开头。FLAGS_C、FLAGS_CXX、FLAGS_DEBUG、FLAGS_RELEASE、FLAGS_MINSIZEREL 都是自定义变量,存储了某些参数选项,方便重复使用。

CMAKE_BUILD_TYPE CMAKE_<LANG>FLAGS<CONFIG>
Debug CMAKE_C_FLAGS_DEBUG
Debug CMAKE_CXX_FLAGS_DEBUG
Debug ...
Release CMAKE_C_FLAGS_RELEASE
Release CMAKE_CXX_FLAGS_RELEASE
Release ...
MinSizeRel CMAKE_C_FLAGS_MINSIZEREL
MinSizeRel CMAKE_CXX_FLAGS_MINSIZEREL
MinSizeRel ...
RelWithDebInfo CMAKE_C_FLAGS_RELWITHDEBINFO
RelWithDebInfo CMAKE_CXX_FLAGS_RELWITHDEBINFO
RelWithDebInfo ...
相关推荐
charlee444 天前
CMake构建学习笔记17-uriparser库的构建和使用
学习·cmake·c/c++·uri
charlee444 天前
CMake构建学习笔记15-组建第一个程序项目
笔记·cmake·c/c++·构建
charlee446 天前
CMake构建学习笔记16-使用VS进行CMake项目的开发
cmake·c/c++·构建
玫瑰花店6 天前
OpengGL教程(三)---使用VAO和VBO方式绘制三角形
c++·ubuntu·计算机视觉·cmake·opengl
Code_ADing8 天前
一个CMake项目中的文件的整体结构
笔记·学习·cmake
Mr.zwX9 天前
【CMake编译报错小复盘】CMAKE_CUDA_ARCHITECTURES,CMake version,GCC version问题
c++·编译·cmake·gcc
长沙红胖子Qt13 天前
关于 ubuntu系统install的cmake版本较低无法编译项目升级其版本 的解决方法
linux·ubuntu·cmake·cmake升级
charlee4417 天前
CMake构建学习笔记14-依赖库管理工具
cmake·管理·c/c++·构建
charlee4420 天前
CMake构建学习笔记12-libzip库的构建
c++·学习·zip·cmake·构建
码农飞飞20 天前
CMake基本语法大全
c++·跨平台·cmake·项目组织·语法大全