御用 C++ 构建之编译规范

jopen 9年前

在开发程序中,我突然对 C++ 的编译选项产生了兴趣,这方面也大有规范可立。于是搜索到的第一结果是 Hacker News 上的 What Are Your GCC Flags? 还有个变本加厉的 How to turn on (literally) ALL of GCC’s warnings? 以及 Flags to enable thorough and verbose g++ warnings .

然后我又跑去 各大热门 C++ 项目 扒 flags. 出乎意料,leveldb 这种重量级 Google 项目的编译选项都很简单。无非全是 -Wall -Wextra -O2 之类的。但我还发现,它们几乎都用 CMake 来构建,于是我便投入精力学习了 CMake 一番。

调研还挺辛苦,总之从此 御用编译器是 GCC , Clang 似乎也不赖,但目前还在观望; 御用构建系统是 CMake , StarBrilliant 如此评价它:「又玄学又难用,但没有更好的代替品了。」;我还在熟悉 CMake 中, 所以只总结了御用 C++ 构建之编译规范,即 CMAKE_CXX_FLAGS 如下 :

set(CMAKE_CXX_STANDARD 14)  set(CMAKE_CXX_FLAGS "-Wall -Wextra")  set(CMAKE_BUILD_TYPE "RelWithDbgInfo")  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -g -ggdb -DDEBUG")  set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -O2")  set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -Og")

CMAKE_CXX_STANDARD 指定 C++14, 我先进我自豪!

CMAKE_BUILD_TYPE 默认指定 RelWithDbgInfo 编译类型 ,即 CMAKE_CXX_FLAGS_RELWITHDEBINFO , 同时也是日常开发的编译类型; 且 -Og 会尽量开启不影响 debug 的优化,即接近 -O2 选项, 所以这类型在 profile, debug, develop, optimize 上都取得了很好的平衡点。 如果是开源项目的话,开发者还可以一时高兴,直接用这编译类型发布算了。若下游的打包者不想要 debug info, 也可以自行 strip 掉。

CMAKE_CXX_FLAGS_DEBUG 专门 debug 用 ,特点是禁用优化,可以 debug 宏,额外编译 DEBUG 宏(Caffe 就用来输出调试信息)。虽然 御用编程规范本身就禁用宏 ,不过我发现 DEBUG 宏可能是例外 ,用好了对 debug 很有帮助,而且这编译选项也就只在 debug 时用,大家知道这点就好。

CMAKE_CXX_FLAGS_RELEASE 当然专门发布 release 版了 。事实上,在 CMake 时可以在命令行选项指定该编译类型: cmake -CMAKE_BUILD_TYPE=Release (<path-to-source> | <path-to-existing-build>) .

事实上,还有一大堆有用的 flags 我还没放进 CMAKE_CXX_FLAGS_RELWITHDEBINFO , 具体作用还请自查 man gcc :

-funroll-loops -Wcast-align -Wcast-qual -Wctor-dtor-privacy -Wdisabled-optimization -Wno-invalid-offsetof -Wmissing-declarations -Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual -Wredundant-decls -Wshadow -Wsign-compare -Wsign-conversion -Wsigin-promo -Wstrict-null-sentinel -Wswitch-default -Wswitch-enum -pendantic -Wredundant-decls -Wconversion -Weffec++ -Wnon-virtual-dtor -Wconversion -Wwrite-strings

毕竟多多益善,而且我还要再补充最后一个终极 flag: -Werror ! 把所有警告转化为错误,从而强制 C++ 工程师完美无瑕之零警告 ,也应了 Effective C++ 第五十三条款「不要轻忽编译器的警告」。 但这些 flags 恐怕难以在组织推广Linus 先生对此开地图炮过 ,我对此深有同感。

此外我和 felixonmars 讨论了 Arch Linux 发行版打包的编译选项,对话如下:

Isaac Ge: @felixonmars 你们打包 C/C++ 在会调 GCC_FLAGS 还是直接用开发者的设置?

[felixonmars] acgtyrant: 会尽量调整成我们的要求,有些默认差不多的其实也没管

[felixonmars] 默认开 native、禁用安全策略等严重问题是主要的调整目标

[felixonmars] 小问题可能我们都没发现……

[felixonmars] 我今天 rebuild 了手上的全部 go 包,启用了安全策略

[felixonmars] 另外还有 –as-needed,是最近一段时间开始重视的

[felixonmars] 链接了一大堆不相干库的,我们会尝试强行加 –as-needed

Isaac Ge: 安全策略?第一次听说Isaac Ge: @felixonmars 有公开的明文规范吗?

[felixonmars] 比如 -fstack-protector-strong –param=ssp-buffer-size=4

Kasei Wang: gcc防溢出的那几个选项么

[felixonmars] 这种就算安全策略

Kasei Wang: 哦那个我自己开着

[felixonmars] acgtyrant: 可以安装 checksec 查看

[felixonmars] 类似这样用:checksec –file /usr/bin/ls

[felixonmars] 我们的目标是全发行版全绿(

[felixonmars] 现在因为 PIE 支持不科学,暂时没考虑 PIE 那一项

[felixonmars] 目前我们的 CFLAGS 默认会做到除 PIE 以外只有 RELRO 是黄的,其他全绿

[felixonmars] 所有没有达到这个效果的,都是应该修的

Written with StackEdit .

</div> </div>

来自: http://tech.acgtyrant.com/御用-C-构建之编译规范/