深度解析:從CMAKE_CXX_FLAGS到跨平臺構(gòu)建實(shí)戰(zhàn))
1. 項(xiàng)目概述為什么CMAKE_CXX_FLAGS如此關(guān)鍵如果你用CMake管理過C項(xiàng)目大概率在CMakeLists.txt里見過CMAKE_CXX_FLAGS這個變量。它看起來平平無奇不就是設(shè)置編譯器參數(shù)的地方嗎但恰恰是這個變量是連接CMake的抽象構(gòu)建指令與底層編譯器如GCC、Clang、MSVC具體行為的橋梁。我見過不少項(xiàng)目編譯出來的二進(jìn)制文件要么性能不達(dá)標(biāo)要么體積臃腫要么調(diào)試信息缺失追根溯源問題往往就出在對CMAKE_CXX_FLAGS的設(shè)置一知半解上。簡單說CMAKE_CXX_FLAGS是CMake用來控制C編譯器CMAKE_CXX_COMPILER行為的全局變量。你通過它傳遞的每一個-O、-g、-Wall最終都會原封不動地交給編譯器命令行。它的“詳解”遠(yuǎn)不止記住幾個參數(shù)那么簡單而是關(guān)乎如何系統(tǒng)化地構(gòu)建一套高效、安全、可維護(hù)的編譯策略。對于新手理解它能避免“編譯通過就行”的誤區(qū)對于老手精細(xì)調(diào)控它是優(yōu)化項(xiàng)目構(gòu)建、統(tǒng)一團(tuán)隊(duì)開發(fā)環(huán)境、實(shí)現(xiàn)跨平臺兼容的核心技能。接下來我們就把它掰開揉碎了講清楚。2. CMAKE_CXX_FLAGS的核心機(jī)制與作用域在動手添加各種-O2或-Wall之前必須搞清楚CMake中標(biāo)志Flags的傳遞機(jī)制和作用域否則很容易出現(xiàn)“設(shè)置了卻沒生效”或者“不該生效的地方生效了”的混亂局面。2.1 變量類型與繼承關(guān)系CMake中有幾個容易混淆的變量它們共同構(gòu)成了編譯選項(xiàng)的層次結(jié)構(gòu)CMAKE_CXX_FLAGS這是全局變量。它的設(shè)置會影響當(dāng)前CMakeLists.txt及其下所有子目錄中的所有C目標(biāo)可執(zhí)行文件、靜態(tài)庫、動態(tài)庫。它通常在項(xiàng)目的頂層CMakeLists.txt中設(shè)置為整個項(xiàng)目定義基礎(chǔ)的編譯環(huán)境。CMAKE_CXX_FLAGS_CONFIG這是針對特定構(gòu)建類型Configuration的全局變量。例如CMAKE_CXX_FLAGS_DEBUG僅在Debug構(gòu)建類型下生效的選項(xiàng)通常包含-g調(diào)試信息。CMAKE_CXX_FLAGS_RELEASE僅在Release構(gòu)建類型下生效的選項(xiàng)通常包含-O3最高級別優(yōu)化。其他常見類型還有RELWITHDEBINFO帶調(diào)試信息的發(fā)布版、MINSIZEREL最小體積發(fā)布版。target_compile_options()這是目標(biāo)屬性命令。它用于為特定的目標(biāo)通過add_executable或add_library創(chuàng)建設(shè)置編譯選項(xiàng)。它的優(yōu)先級高于全局的CMAKE_CXX_FLAGS并且可以更精細(xì)地控制。這是現(xiàn)代CMake3.0推薦的方式。它們的關(guān)系可以這樣理解CMAKE_CXX_FLAGS和CMAKE_CXX_FLAGS_CONFIG像是公司層面的統(tǒng)一規(guī)定比如全員必須穿工服。而target_compile_options()像是給某個特定項(xiàng)目組目標(biāo)的額外要求比如這個組還需要戴安全帽。最終編譯器看到的命令行是所有這些規(guī)定的疊加。2.2 設(shè)置方式與優(yōu)先級陷阱設(shè)置這些變量有多種方式不同的方式可能導(dǎo)致不同的結(jié)果set()命令最直接的方式。set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -Wall”)。這里有一個關(guān)鍵細(xì)節(jié)直接set會覆蓋該變量在當(dāng)前作用域目錄的值。通常我們使用${CMAKE_CXX_FLAGS}來追加而不是覆蓋。add_compile_options()命令這個命令添加的選項(xiàng)會作用于當(dāng)前目錄及所有子目錄下的所有語言C和C的目標(biāo)。它比set(CMAKE_CXX_FLAGS)更“現(xiàn)代”一些但依然不夠精確。target_compile_options()命令如前所述這是最推薦的方式。它使用PRIVATE、PUBLIC、INTERFACE關(guān)鍵字來控制選項(xiàng)的傳播完美契合現(xiàn)代CMake的目標(biāo)Target為中心的設(shè)計(jì)哲學(xué)。實(shí)操心得優(yōu)先級與作用域?qū)崙?zhàn)假設(shè)你在頂層CMakeLists.txt中set(CMAKE_CXX_FLAGS “-Wall”)然后在子目錄的CMakeLists.txt中為某個庫使用target_compile_options(my_lib PRIVATE “-Werror”)。最終編譯my_lib時(shí)命令行會是-Wall -Werror。但如果你在子目錄中又寫了一句set(CMAKE_CXX_FLAGS “-Wextra”)那么-Wall就被覆蓋了my_lib的命令行會變成-Wextra -Werror。這種隱蔽的覆蓋是新手常踩的坑。最佳實(shí)踐是在項(xiàng)目頂層統(tǒng)一設(shè)置基礎(chǔ)全局標(biāo)志然后使用target_compile_options進(jìn)行目標(biāo)級定制。2.3 與CMAKE_C_FLAGS的區(qū)別顧名思義CMAKE_C_FLAGS用于C編譯器CMAKE_CXX_FLAGS用于C編譯器。對于純C項(xiàng)目或C/C混合項(xiàng)目需要分別設(shè)置。有時(shí)一些選項(xiàng)是共通的比如優(yōu)化級別-O2你可以這樣設(shè)置來保持同步set(CMAKE_C_FLAGS “${CMAKE_C_FLAGS} -Wall”) set(CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -Wall”)或者更優(yōu)雅地使用add_compile_options(-Wall)它會影響所有語言。3. 核心編譯選項(xiàng)分類詳解與實(shí)戰(zhàn)配置理解了機(jī)制我們來填充血肉。CMAKE_CXX_FLAGS的值是一串由空格分隔的編譯器參數(shù)。我們可以將這些參數(shù)分為幾大類每一類都對應(yīng)著項(xiàng)目構(gòu)建的一個關(guān)鍵維度。3.1 優(yōu)化選項(xiàng)在速度、體積與調(diào)試間權(quán)衡優(yōu)化選項(xiàng)直接決定生成代碼的性能和大小是Release構(gòu)建的核心。-O0(默認(rèn))不優(yōu)化。編譯最快生成的代碼最易于調(diào)試因?yàn)樽兞亢痛a順序與源代碼幾乎一一對應(yīng)。純開發(fā)調(diào)試階段必備。-O1/-O基礎(chǔ)優(yōu)化。編譯器會嘗試減少代碼體積和執(zhí)行時(shí)間但不進(jìn)行耗時(shí)很長的優(yōu)化。-O2推薦優(yōu)化級別。在-O1基礎(chǔ)上進(jìn)行幾乎所有不涉及空間/時(shí)間權(quán)衡的優(yōu)化。通常這是對執(zhí)行速度提升最明顯的級別也是大多數(shù)發(fā)布版本的選擇。-O3激進(jìn)優(yōu)化。在-O2基礎(chǔ)上開啟一些可能增加代碼體積、甚至在某些邊緣情況下降低性能的優(yōu)化如函數(shù)內(nèi)聯(lián)更激進(jìn)、循環(huán)展開。需要針對熱點(diǎn)代碼進(jìn)行性能剖析后謹(jǐn)慎使用。-Os優(yōu)化代碼大小。在-O2的基礎(chǔ)上禁用那些通常會增加代碼體積的優(yōu)化選項(xiàng)。適用于嵌入式或?qū)ΧM(jìn)制體積敏感的場景。-Og為調(diào)試體驗(yàn)優(yōu)化。在保持-O0級別良好調(diào)試性的同時(shí)開啟一些不會影響調(diào)試的優(yōu)化。是開發(fā)階段希望有一點(diǎn)性能又不犧牲調(diào)試性的折中選擇。實(shí)戰(zhàn)配置示例通常在CMake中我們不會直接寫死-O2而是利用CMAKE_BUILD_TYPE和對應(yīng)的CMAKE_CXX_FLAGS_CONFIG變量。# 在頂層CMakeLists.txt中 if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE “Release”) # 設(shè)置默認(rèn)構(gòu)建類型 endif() set(CMAKE_CXX_FLAGS_DEBUG “${CMAKE_CXX_FLAGS_DEBUG} -g -O0”) set(CMAKE_CXX_FLAGS_RELEASE “${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG”) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO “${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O2 -g”) set(CMAKE_CXX_FLAGS_MINSIZEREL “${CMAKE_CXX_FLAGS_MINSIZEREL} -Os -DNDEBUG”)注意-DNDEBUG宏定義它會影響assert()函數(shù)在發(fā)布版本中將其禁用。3.2 警告與診斷選項(xiàng)將潛在錯誤扼殺在編譯期警告是免費(fèi)的代碼審查。開啟并嚴(yán)肅對待警告能極大提升代碼質(zhì)量。-Wall開啟“所有”常見警告。注意這里的“所有”是歷史遺留說法實(shí)際上只是一組常用的警告。-Wextra開啟額外警告。與-Wall互補(bǔ)能捕捉更多問題如未使用的參數(shù)、比較有符號和無符號數(shù)。-Wpedantic/-pedantic要求嚴(yán)格遵循ISO C標(biāo)準(zhǔn)禁用編譯器擴(kuò)展。有助于保持代碼的可移植性。-Werror將警告視為錯誤。這是保證代碼質(zhì)量的“大殺器”。任何警告都會導(dǎo)致編譯失敗迫使開發(fā)者立即修復(fù)??梢栽贑I/CD流水線中啟用但在日常開發(fā)中可能過于嚴(yán)格。-Wshadow警告變量遮蔽。當(dāng)局部變量遮蔽了外層作用域的同名變量時(shí)發(fā)出警告有助于避免邏輯錯誤。-Wunused警告未使用的變量、參數(shù)等。特定警告控制-Wno-warning用于禁用特定警告。例如在第三方庫頭文件會產(chǎn)生大量警告時(shí)可以使用-isystem指定其包含路徑編譯器會將其視為系統(tǒng)頭文件抑制警告或者局部禁用target_compile_options(my_app PRIVATE -Wno-deprecated-declarations)。實(shí)戰(zhàn)配置示例# 基礎(chǔ)警告配置適用于所有構(gòu)建類型 add_compile_options(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wunused) # 僅在開發(fā)人員的本地Debug構(gòu)建中可以不加-Werror方便快速迭代 # 但在CI或準(zhǔn)備發(fā)布的分支上應(yīng)該啟用 if(CMAKE_BUILD_TYPE STREQUAL “Release” OR DEFINED ENV{CI}) add_compile_options(-Werror) endif()3.3 調(diào)試信息選項(xiàng)讓崩潰和調(diào)試有跡可循調(diào)試信息是連接二進(jìn)制機(jī)器碼和源代碼的橋梁。-g生成操作系統(tǒng)的原生調(diào)試格式如DWARF on Linux, PDB on Windows。-ggdb生成GDB優(yōu)化過的調(diào)試信息更豐富。-g3比-g包含更多調(diào)試信息比如宏定義。-s剝離調(diào)試信息。在發(fā)布最終版本時(shí)使用此選項(xiàng)可以顯著減小二進(jìn)制文件體積但同時(shí)也意味著無法調(diào)試。通常與-O3一起使用。注意事項(xiàng)-g會增加二進(jìn)制體積但通常不影響運(yùn)行時(shí)性能。Release版本如果需要在現(xiàn)場診斷問題可以使用RelWithDebInfo-O2 -g構(gòu)建。絕對不要在最終交付的Release版本中同時(shí)使用-g和-s它們是互斥的。3.4 語言標(biāo)準(zhǔn)與特性選項(xiàng)明確你的C版本這是確保代碼在不同編譯器上行為一致的關(guān)鍵。-stdc11/-stdc14/-stdc17/-stdc20/-stdc23指定使用的C語言標(biāo)準(zhǔn)版本。強(qiáng)烈建議在項(xiàng)目中顯式指定。-stdliblibc(Clang)指定使用LLVM的libc標(biāo)準(zhǔn)庫而不是GNU的libstdc。-fPIC(Position Independent Code)生成位置無關(guān)代碼。這是編譯動態(tài)鏈接庫.so,.dll的必要條件。如果你在構(gòu)建共享庫必須加上這個標(biāo)志。在現(xiàn)代CMake中更推薦使用target_compile_features或設(shè)置CMAKE_CXX_STANDARD屬性來指定語言標(biāo)準(zhǔn)這比直接傳遞-std更便攜。# 現(xiàn)代CMake推薦方式 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 必須支持該標(biāo)準(zhǔn) set(CMAKE_CXX_EXTENSIONS OFF) # 禁用編譯器擴(kuò)展相當(dāng)于 -stdc17 而非 -stdgnu17 # 或者針對特定目標(biāo) target_compile_features(my_target PUBLIC cxx_std_17)3.5 包含路徑與宏定義雖然包含路徑通常由target_include_directories()管理宏定義由target_compile_definitions()管理但它們最終也會轉(zhuǎn)化為編譯器標(biāo)志-I,-D。理解它們有助于調(diào)試。-Idir添加頭文件搜索路徑。CMake的target_include_directories()會自動生成這些。-Dmacro[value]定義預(yù)處理器宏。例如-DDEBUG1。target_compile_definitions()會生成這些。-Umacro取消宏定義。一個常見技巧如果你想在命令行臨時(shí)覆蓋CMake中的某個定義可以在調(diào)用cmake --build時(shí)傳遞額外的標(biāo)志但更通用的做法是使用CMake變量。例如通過-DUSE_FEATURE_XON傳遞給CMake然后在CMakeLists.txt中根據(jù)這個變量決定是否添加-DUSE_FEATURE_X編譯定義。4. 跨平臺與編譯器兼容性實(shí)戰(zhàn)CMAKE_CXX_FLAGS在不同平臺和編譯器下寫法可能不同。CMake提供了抽象機(jī)制來處理這些差異。4.1 編譯器檢測與條件設(shè)置絕對不要在你的CMakeLists.txt里寫死-Wall因?yàn)镸SVC不認(rèn)識這個。應(yīng)該先檢測編譯器。if(CMAKE_CXX_COMPILER_ID STREQUAL “GNU”) # GCC add_compile_options(-Wall -Wextra -Wpedantic) if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) add_compile_options(-Wmisleading-indentation) # GCC 6 特有的警告 endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL “Clang”) # Clang add_compile_options(-Wall -Wextra -Wpedantic) add_compile_options(-Wthread-safety) # Clang 特有的線程安全警告 elseif(CMAKE_CXX_COMPILER_ID STREQUAL “MSVC”) # Visual Studio # MSVC的警告標(biāo)志完全不同 add_compile_options(/W4) # 相當(dāng)于GCC的 -Wall # 將特定警告視為錯誤 add_compile_options(/WX) # 禁用一些過于煩人或常見的MSVC特定警告 add_compile_options(/wd4251) # 關(guān)于dll接口的警告 endif()4.2 使用生成器表達(dá)式進(jìn)行精細(xì)控制生成器表達(dá)式Generator Expressions是CMake中非常強(qiáng)大的功能它允許你在生成構(gòu)建系統(tǒng)如Makefile時(shí)進(jìn)行條件判斷。# 為不同的構(gòu)建類型設(shè)置不同的優(yōu)化級別 target_compile_options(my_target PRIVATE “$$CONFIG:Release:-O3” “$$CONFIG:Debug:-O0 -g” “$$CONFIG:RelWithDebInfo:-O2 -g” ) # 為不同的編譯器設(shè)置不同的標(biāo)志 target_compile_options(my_target PRIVATE “$$CXX_COMPILER_ID:GNU:-fno-strict-aliasing” “$$CXX_COMPILER_ID:MSVC:/fp:fast” ) # 組合條件只在Release構(gòu)建且是GCC編譯器時(shí)啟用鏈接時(shí)優(yōu)化(LTO)標(biāo)志 target_compile_options(my_target PRIVATE “$$AND:$CONFIG:Release,$CXX_COMPILER_ID:GNU:-flto” )生成器表達(dá)式語法初看復(fù)雜但它提供了無與倫比的靈活性是實(shí)現(xiàn)復(fù)雜、條件化編譯選項(xiàng)配置的終極工具。5. 高級技巧與最佳實(shí)踐5.1 管理編譯選項(xiàng)的推薦模式分層設(shè)置項(xiàng)目級頂層CMakeLists.txt使用add_compile_options()或設(shè)置CMAKE_CXX_FLAGS來定義所有目標(biāo)共享的、最基礎(chǔ)的選項(xiàng)如基本警告級別、語言標(biāo)準(zhǔn)。目標(biāo)級優(yōu)先使用target_compile_options()。用PRIVATE關(guān)鍵字添加僅該目標(biāo)需要的特殊選項(xiàng)如某個庫需要特定的架構(gòu)指令集-msse4.2。用PUBLIC或INTERFACE關(guān)鍵字傳遞依賴要求如一個接口庫要求所有使用者必須開啟RTTI-frtti。使用CMake預(yù)設(shè)或Toolchain文件對于復(fù)雜的、需要分發(fā)給團(tuán)隊(duì)或CI系統(tǒng)的編譯選項(xiàng)集合特別是交叉編譯時(shí)的-march、-mtune等不要把它們硬編碼在CMakeLists.txt里。應(yīng)該使用CMake預(yù)設(shè)CMake Presets或編寫?yīng)毩⒌腡oolchain文件-DCMAKE_TOOLCHAIN_FILE…將工具鏈、路徑、標(biāo)志等配置與項(xiàng)目邏輯分離。提供用戶可配置選項(xiàng)使用option()命令讓用戶決定是否開啟某些特性。option(MYPROJECT_WARNINGS_AS_ERRORS “Treat compiler warnings as errors” OFF) if(MYPROJECT_WARNINGS_AS_ERRORS) add_compile_options($$OR:$CXX_COMPILER_ID:GNU,$CXX_COMPILER_ID:Clang:-Werror) add_compile_options($$CXX_COMPILER_ID:MSVC:/WX) endif()5.2 調(diào)試與檢查生成的標(biāo)志你設(shè)置了半天怎么知道最終傳給編譯器的命令到底是什么有幾種方法查看構(gòu)建輸出在make或ninja構(gòu)建時(shí)使用VERBOSE1環(huán)境變量。make VERBOSE1 # 或 cmake –build build_dir –verbose使用CMake的–trace或–trace-expand這可以追蹤C(jī)Make腳本的執(zhí)行但輸出非常詳細(xì)主要用于調(diào)試CMake腳本本身。直接檢查構(gòu)建系統(tǒng)文件對于Makefile生成器可以查看build/CMakeFiles/target_name.dir/flags.make文件里面列出了所有編譯標(biāo)志。5.3 常見陷阱與避坑指南標(biāo)志沖突與覆蓋如前所述不同作用域的set命令可能意外覆蓋選項(xiàng)。堅(jiān)持使用target_compile_options并明確PRIVATE/PUBLIC/INTERFACE。字符串引號與空格在CMake中編譯標(biāo)志是字符串列表。add_compile_options(-Wall -Wextra)添加的是兩個獨(dú)立的選項(xiàng)。而add_compile_options(“-Wall -Wextra”)添加的是一個包含空格的選項(xiàng)這會導(dǎo)致編譯器錯誤。永遠(yuǎn)將每個獨(dú)立的編譯器標(biāo)志作為單獨(dú)的字符串參數(shù)傳遞。緩存變量Cache VariableCMAKE_CXX_FLAGS等變量經(jīng)常被緩存。如果你在CMake GUI或ccmake中修改了它們或者通過-D在命令行傳遞這些值會被緩存下次配置時(shí)即使你修改了CMakeLists.txt中的set命令也可能不生效。此時(shí)需要手動刪除CMakeCache.txt或使用-U選項(xiàng)清除緩存。第三方庫的污染通過find_package()或add_subdirectory()引入的第三方庫可能會設(shè)置它們自己的CMAKE_CXX_FLAGS有時(shí)會污染你的全局選項(xiàng)。如果出現(xiàn)問題可以在引入它們之前保存當(dāng)前的標(biāo)志引入之后再恢復(fù)或者使用target_compile_options為你的目標(biāo)顯式覆蓋不想要的選項(xiàng)。6. 完整配置案例一個現(xiàn)代C項(xiàng)目的CMakeLists.txt片段讓我們看一個綜合性的例子它展示了如何組織一個中型C項(xiàng)目的編譯選項(xiàng)。cmake_minimum_required(VERSION 3.15) project(MyAwesomeProject LANGUAGES CXX) # 1. 設(shè)置默認(rèn)構(gòu)建類型 if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE “RelWithDebInfo” CACHE STRING “Build type” FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS “Debug” “Release” “RelWithDebInfo” “MinSizeRel”) endif() # 2. 設(shè)置C標(biāo)準(zhǔn)現(xiàn)代方式 set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 3. 全局編譯選項(xiàng)所有目標(biāo)所有構(gòu)建類型 add_compile_options( # 通用警告 $$OR:$CXX_COMPILER_ID:GNU,$CXX_COMPILER_ID:Clang:-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast # MSVC警告 $$CXX_COMPILER_ID:MSVC:/W4 /permissive- ) # 4. 按構(gòu)建類型設(shè)置的選項(xiàng) set(CMAKE_CXX_FLAGS_DEBUG “${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -DDEBUG”) set(CMAKE_CXX_FLAGS_RELEASE “${CMAKE_CXX_FLAGS_RELEASE} -O3 -DNDEBUG”) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO “${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O2 -g -DNDEBUG”) set(CMAKE_CXX_FLAGS_MINSIZEREL “${CMAKE_CXX_FLAGS_MINSIZEREL} -Os -DNDEBUG”) # 5. 可選在CI或嚴(yán)格構(gòu)建中開啟Werror option(PROJECT_TREAT_WARNINGS_AS_ERRORS “Treat compiler warnings as errors in CI builds” OFF) if(PROJECT_TREAT_WARNINGS_AS_ERRORS) add_compile_options( $$OR:$CXX_COMPILER_ID:GNU,$CXX_COMPILER_ID:Clang:-Werror $$CXX_COMPILER_ID:MSVC:/WX ) endif() # 6. 添加可執(zhí)行文件目標(biāo) add_executable(my_app main.cpp) # 7. 為目標(biāo)添加特定的編譯選項(xiàng) target_compile_options(my_app PRIVATE # 這個應(yīng)用需要浮點(diǎn)快速模式 $$CXX_COMPILER_ID:GNU:-ffast-math $$CXX_COMPILER_ID:MSVC:/fp:fast # 以及一些特定的定義 -DMY_APP_VERSION“1.0.0” ) # 8. 添加一個庫并設(shè)置接口選項(xiàng)要求使用者也必須開啟RTTI add_library(my_core STATIC core.cpp) target_compile_options(my_core INTERFACE $$OR:$CXX_COMPILER_ID:GNU,$CXX_COMPILER_ID:Clang:-frtti $$CXX_COMPILER_ID:MSVC:/GR ) target_link_libraries(my_app PRIVATE my_core)這個配置體現(xiàn)了幾點(diǎn)最佳實(shí)踐默認(rèn)構(gòu)建類型設(shè)置、使用現(xiàn)代C標(biāo)準(zhǔn)設(shè)置、跨平臺警告配置、構(gòu)建類型差異化選項(xiàng)、用戶可配置的嚴(yán)格模式、以及目標(biāo)級精細(xì)控制。掌握CMAKE_CXX_FLAGS及其相關(guān)機(jī)制你就能真正駕馭CMake的構(gòu)建過程讓編譯行為完全符合你的預(yù)期為打造高質(zhì)量、高性能的C軟件打下堅(jiān)實(shí)基礎(chǔ)。