御用 C++ 構建之編譯規范
在開發程序中,我突然對 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 .