)
構(gòu)建工具開(kāi)發(fā)工具CLI【免費(fèi)下載鏈接】CMakeMirror of CMake upstream repository項(xiàng)目地址https://gitcode.com/gh_mirrors/cm/CMake點(diǎn)擊查看免費(fèi)下載導(dǎo)讀CMP0047 是 CMake 自 3.0 起引入的一項(xiàng)兼容性策略它解決了一個(gè)在 QNX 嵌入式開(kāi)發(fā)中非常具體的問(wèn)題當(dāng)使用 QNX 的qcc編譯器驅(qū)動(dòng)時(shí)CMake 應(yīng)當(dāng)把CMAKE_LANG_COMPILER_ID報(bào)告為QCC還是舊有的GNU。本文以 CMP0047.rst 文檔為主體結(jié)合本倉(cāng)庫(kù)中 cmPolicies.h 的策略注冊(cè)與 Modules/Compiler/QCC-*.cmake 的編譯器實(shí)現(xiàn)完整講解該策略的 OLD/NEW 行為、設(shè)置時(shí)機(jī)、遷移方式以及 QNX 工具鏈的底層細(xì)節(jié)。讀完本文你將掌握如何在舊項(xiàng)目與現(xiàn)代 CMake 之間正確對(duì)齊 QNX 交叉編譯的 Compiler ID并理解這一變更對(duì)特性檢測(cè)、編譯旗標(biāo)選擇的影響。一、策略背景為什么 qcc 需要自己的 Compiler IDQNX 實(shí)時(shí)操作系統(tǒng)RTOS的官方編譯器驅(qū)動(dòng)名為qcc針對(duì) C/C其底層通常封裝了 GCC 兼容的代碼生成后端。在 CMake 3.0 之前CMake 只把qcc當(dāng)作 GNU 編譯器家族的一員處理CMAKE_LANG_COMPILER_ID一律報(bào)告為GNU。這種簡(jiǎn)化在早期可行但存在隱患qcc驅(qū)動(dòng)在命令行語(yǔ)義上與裸gcc有明顯差異例如 C 語(yǔ)言模式需要顯式傳入-lang-c或-x c這樣的驅(qū)動(dòng)級(jí)旗標(biāo)而不是由 gcc 默認(rèn)推斷項(xiàng)目無(wú)法通過(guò) Compiler ID 精確區(qū)分真正的 GCC和QNX 的 qcc 封裝導(dǎo)致針對(duì)性的工具鏈適配邏輯無(wú)從下手。CMake 3.0 起CMake 正式承認(rèn) QNXqcc驅(qū)動(dòng)與 GNU 編譯器是兩回事并引入獨(dú)立編譯器 IDQCC參見(jiàn)CMAKE_ _COMPILER_ID變量文檔中QCC— QNX C/C compiler 這一取值。但考慮到存量項(xiàng)目可能依然假設(shè) qcc 的 ID 是GNU直接改默認(rèn)值會(huì)破壞這些項(xiàng)目的條件判斷于是通過(guò)策略 CMP0047 讓新舊行為平滑過(guò)渡。二、策略定義CMP0047 的 OLD 與 NEW 行為根據(jù) CMP0047.rst該策略的語(yǔ)義如下行為效果OLD舊行為對(duì) qcc 與 QCC 兩類(lèi)編譯器驅(qū)動(dòng)CMAKE_LANG_COMPILER_ID報(bào)告為GNUNEW新行為對(duì) qcc 與 QCC 兩類(lèi)編譯器驅(qū)動(dòng)CMAKE_LANG_COMPILER_ID報(bào)告為QCC該策略在語(yǔ)言LANG被 project() 或 enable_language() 命令啟用之后決定CMAKE_LANG_COMPILER_ID變量中報(bào)告哪一個(gè) Compiler ID。在 CMake 源碼中該策略注冊(cè)于 cmPolicies.h注冊(cè)摘要字符串即為Use QCC compiler id for the qcc drivers on QNX.與文檔標(biāo)題完全一致。策略注冊(cè)位于cmPolicies.h的策略表中意味著它在 CMake 的cmake_minimum_required版本判定體系內(nèi)是標(biāo)準(zhǔn)策略之一可通過(guò)常規(guī)的 cmake_policy() 機(jī)制被讀取與設(shè)置。關(guān)鍵約束必須在使用前設(shè)置文檔明確指出該策略必須在project()或enable_language()被調(diào)用之前設(shè)置因?yàn)檎Z(yǔ)言啟用過(guò)程會(huì)讀取編譯器信息、寫(xiě)入CMAKE_LANG_COMPILER_ID策略在那一刻才決定用哪個(gè) ID。錯(cuò)過(guò)時(shí)機(jī)再調(diào)用cmake_policy(SET CMP0047 ...)將不會(huì)對(duì)已啟用的語(yǔ)言生效。推薦的設(shè)置方式cmake_minimum_required(VERSION 3.0) cmake_policy(SET CMP0047 NEW) # 顯式選擇 QCC 編譯器 ID project(MyQnxProject C CXX) # 語(yǔ)言啟用發(fā)生在策略設(shè)置之后或直接依賴(lài)版本聲明隱式啟用cmake_minimum_required(VERSION 3.5) # 3.0 的策略默認(rèn)即 NEW需要說(shuō)明在 CMake 3.0 至 4.0 之前的版本中若項(xiàng)目沒(méi)有顯式設(shè)置該策略CMake 會(huì)按默認(rèn)策略行為處理并可通過(guò)CMAKE_POLICY_WARNING_CMP0047變量參見(jiàn) CMAKE_POLICY_WARNING_CMP 控制是否輸出策略警告。默認(rèn)情況下該策略在 3.0 引入時(shí)不主動(dòng)告警文檔中WARNED_OR_DID_NOT_WARN替換為 didnotwarn by default。三、策略生命周期CMake 4.0 起 OLD 行為被移除文檔開(kāi)頭的序言include 自 REMOVED_PROLOGUE.rst表明該策略的OLD行為已在CMake 4.0中被移除策略必須通過(guò)cmake_minimum_required或cmake_policy設(shè)置為NEW。這帶來(lái)兩個(gè)直接影響最低版本 ≥ 4.0 的項(xiàng)目cmake_minimum_required(VERSION 4.0)會(huì)讓 CMP0047 自動(dòng)處于NEW狀態(tài)QNX 下 Compiler ID 必然是QCC無(wú)需額外處理最低版本 4.0 的存量項(xiàng)目若代碼中仍存在針對(duì)GNUID 的 QNX 分支例如if(CMAKE_C_COMPILER_ID STREQUAL GNU)在升級(jí) CMake 到 4.0 后該分支將不再命中需要遷移為檢查QCC。這正是該策略與其他已移除 OLD 行為策略如 CMP0001–CMP00xx 系列中同樣標(biāo)注 REMOVED 的策略一致的演進(jìn)路徑先以默認(rèn)舊行為兼容存量再通過(guò)警告提醒最終在新大版本中強(qiáng)制新行為。四、源碼縱深QCC 編譯器模塊在倉(cāng)庫(kù)中的真實(shí)實(shí)現(xiàn)策略 CMP0047 的落地不止于cmPolicies.h中的一條注冊(cè)記錄還配套了一整套以QCC命名的編譯器模塊。在 Modules/Compiler 目錄下可以看到QCC-C.cmake、QCC-CXX.cmake、QCC-ASM.cmake各語(yǔ)言的編譯/鏈接規(guī)則入口QCC-C-FeatureTests.cmake、QCC-CXX-FeatureTests.cmake語(yǔ)言特性探測(cè)QCC.cmake公共宏__compiler_qcc的定義以 QCC-C.cmake 為例其實(shí)現(xiàn)非常精簡(jiǎn)# To include compiler feature detection include(Compiler/GNU-C) include(Compiler/QCC) __compiler_qcc(C)注意第一行QCC 的 C 語(yǔ)言特性檢測(cè)直接復(fù)用了Compiler/GNU-C。這一點(diǎn)與策略背景相互印證——qcc 的代碼生成后端與 GCC 兼容因此絕大多數(shù) GNU 編譯旗標(biāo)與特性宏依然適用但 Compiler ID 卻獨(dú)立為QCC使項(xiàng)目既能復(fù)用 GCC 特性語(yǔ)義又能識(shí)別出驅(qū)動(dòng)差異。QCC-CXX.cmake 則展示了更實(shí)質(zhì)的驅(qū)動(dòng)差異——C 語(yǔ)言模式旗標(biāo)隨 qcc 版本變化# If the toolchain uses qcc for CMAKE_CXX_COMPILER instead of QCC, the # default for the driver is not c. if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.2.0) # QNX 8.0 toolchain set(_cmake_qcc_cxx_lang_compile_flag -lang-c) set(_cmake_qcc_cxx_lang_link_flag -lang-c) else () set(_cmake_qcc_cxx_lang_compile_flag -x c) set(_cmake_qcc_cxx_lang_link_flag ) endif () set(CMAKE_CXX_COMPILE_OBJECT CMAKE_CXX_COMPILER ${_cmake_qcc_cxx_lang_compile_flag} DEFINES INCLUDES FLAGS -o OBJECT -c SOURCE) set(CMAKE_CXX_LINK_EXECUTABLE CMAKE_CXX_COMPILER ${_cmake_qcc_cxx_lang_link_flag} FLAGS LINK_FLAGS OBJECTS -o TARGET LINK_LIBRARIES)從中可以讀出兩個(gè)關(guān)鍵事實(shí)驅(qū)動(dòng)不是 gccqcc 驅(qū)動(dòng)默認(rèn)并不自動(dòng)選擇 C 語(yǔ)言模式CMake 必須顯式傳入語(yǔ)言旗標(biāo)這正是 Compiler ID 必須區(qū)別于GNU的底層原因版本分支qcc 12.2.0QNX 8.0 工具鏈之前的版本使用-lang-c之后的版本使用-x c且鏈接階段無(wú)需語(yǔ)言旗標(biāo)。這說(shuō)明CMAKE_CXX_COMPILER_VERSION在 QNX 工具鏈上同樣可用項(xiàng)目可以安全地用它做版本判斷。此外QCC-ASM.cmake 僅包含include(Compiler/QCC)與__compiler_qcc(ASM)兩行表明 QCC 編譯器 ID 同樣適用于 ASM 語(yǔ)言而 Modules/Platform/QNX-Initialize.cmake 則負(fù)責(zé) QNX 平臺(tái)層的初始化與編譯器層的 QCC 模塊協(xié)同完成整套 QNX 交叉編譯支持。五、實(shí)戰(zhàn)遷移舊項(xiàng)目到 QCC Compiler ID假設(shè)你有一個(gè)面向 QNX 的存量 CMake 工程其配置文件中曾有如下分支if(CMAKE_CXX_COMPILER_ID STREQUAL GNU) # 誤把 qcc 當(dāng)成 GNU 處理的舊邏輯 add_compile_options(-fno-exceptions) endif()在 CMake 3.0 中若項(xiàng)目仍隱式處于 CMP0047 的 OLD 行為上述分支在 qcc 下依然命中但語(yǔ)義是碰巧的一旦切到 NEW 行為或升級(jí)到 CMake 4.0該分支將失效。正確遷移步驟聲明策略在project()之前顯式cmake_policy(SET CMP0047 NEW)或?qū)make_minimum_required提升到 3.0 以上推薦直接顯式 SET明確意圖改寫(xiě)條件將所有針對(duì) QNX 工具鏈的GNU判斷改為QCCif(CMAKE_CXX_COMPILER_ID STREQUAL QCC) # QNX qcc 專(zhuān)用邏輯例如 add_compile_options(-fno-exceptions) elseif(CMAKE_CXX_COMPILER_ID STREQUAL GNU) # 真正的桌面/嵌入式 GCC 邏輯 endif()驗(yàn)證 Compiler ID在配置階段打印確認(rèn)message(STATUS QNX Compiler ID ${CMAKE_CXX_COMPILER_ID}) message(STATUS QNX Compiler Version ${CMAKE_CXX_COMPILER_VERSION})回歸測(cè)試特性檢測(cè)由于 QCC-C/CXX 模塊復(fù)用了 GNU 的特性測(cè)試見(jiàn) QCC-C-FeatureTests.cmakecheck_cxx_compiler_flag、write_compiler_detection_header等依賴(lài) Compiler ID 的機(jī)制會(huì)以QCC作為 ID 前綴生成檢測(cè)頭請(qǐng)同步檢查任何硬編碼了GNU的檢測(cè)頭消費(fèi)代碼。常見(jiàn)問(wèn)題Q不設(shè)置該策略會(huì)怎樣在 CMake 3.x–3.27 等版本中默認(rèn)沿用舊行為報(bào)告GNU策略本身默認(rèn)不告警因此存量項(xiàng)目不會(huì)立即報(bào)錯(cuò)但跨過(guò) CMake 4.0 后舊行為被移除編譯器 ID 會(huì)突然變?yōu)镼CC提前遷移可避免升級(jí)沖擊。QCMAKE_CXX_COMPILER_ID為QCC與CMAKE_CXX_COMPILER指向qcc/QCC有區(qū)別嗎Compiler ID 是 CMake 通過(guò)編譯探測(cè)CompilerId 工程識(shí)別出的廠商標(biāo)識(shí)qcc與QCC兩個(gè)驅(qū)動(dòng)都會(huì)得到QCC這個(gè) ID而QCC-CXX.cmake中的版本分支正是為了兼容驅(qū)動(dòng)名為 qcc 但版本口徑不同的兩種工具鏈形態(tài)。Q策略設(shè)置時(shí)機(jī)為什么如此嚴(yán)格因?yàn)閜roject()/enable_language()在啟用語(yǔ)言的同時(shí)完成編譯器探測(cè)并固化CMAKE_LANG_COMPILER_IDCMP0047 正是這一探測(cè)結(jié)果的顯示器自然必須先行設(shè)置。這一約束在 CMP0047.rst 文檔中已明確強(qiáng)調(diào)。六、與其他 QNX 相關(guān)機(jī)制的關(guān)系CMP0047 只是 CMake QNX 支持的一部分。從倉(cāng)庫(kù)結(jié)構(gòu)看QNX 支持由多層協(xié)同構(gòu)成策略層CMP0047.rst 決定 Compiler ID 的取值口徑編譯器層Modules/Compiler/QCC-*.cmake 系列模塊按 IDQCC提供各語(yǔ)言的編譯/鏈接規(guī)則與特性檢測(cè)平臺(tái)層Modules/Platform/QNX-Initialize.cmake 完成系統(tǒng)級(jí)初始化變量層CMAKE_ _COMPILER_ID文檔中QCC被登記為 QNX C/C compiler 的官方取值可供所有項(xiàng)目在條件判斷中引用。理解這一層次關(guān)系后遇到 QNX 工具鏈問(wèn)題時(shí)可以按ID 是否對(duì) → 規(guī)則是否生效 → 平臺(tái)初始化是否正確的順序排查而 CMP0047 正是第一環(huán)。總結(jié)CMP0047 是 CMake 3.0 引入、并在 CMake 4.0 中強(qiáng)制收口的 QNX 編譯器識(shí)別策略O(shè)LDqcc/QCC 驅(qū)動(dòng)報(bào)告GNU編譯器 IDNEWqcc/QCC 驅(qū)動(dòng)報(bào)告獨(dú)立的QCC編譯器 ID必須在project()/enable_language()之前設(shè)置配套實(shí)現(xiàn)見(jiàn) cmPolicies.h 與 Modules/Compiler/QCC-*.cmake其中 QCC-CXX 的版本分支qcc 12.2.0 前后使用不同的 C 語(yǔ)言旗標(biāo)說(shuō)明了 ID 獨(dú)立化的根本動(dòng)機(jī)——qcc 并非 GNU 編譯器只是與其兼容的 QNX 驅(qū)動(dòng)。對(duì)于維護(hù) QNX 交叉編譯工程的開(kāi)發(fā)者建議在 CMake 4.0 落地前完成 Compiler ID 的顯式對(duì)齊把所有針對(duì) qcc 的GNU判斷遷移為QCC從而讓工具鏈識(shí)別更精確、升級(jí)路徑更平滑。贊分享構(gòu)建工具開(kāi)發(fā)工具CLI【免費(fèi)下載鏈接】CMakeMirror of CMake upstream repository項(xiàng)目地址https://gitcode.com/gh_mirrors/cm/CMake點(diǎn)擊查看免費(fèi)下載相關(guān)推薦Meson 對(duì) QNX qcc/q 編譯器驅(qū)動(dòng)的支持交叉編譯配置、實(shí)現(xiàn)原理與已知限制Meson 對(duì) QNX qcc/q 編譯器驅(qū)動(dòng)的支持交叉編譯配置、實(shí)現(xiàn)原理與已知限制 Meson Build System 自本版本起正式支持 QNX S構(gòu)建工具CMake 策略 CMP0025 深度解析Apple Clang 編譯器標(biāo)識(shí)從 Clang 到 AppleClang 的演進(jìn)CMake 策略 CMP0025 深度解析Apple Clang 編譯器標(biāo)識(shí)從 Clang 到 AppleClang 的演進(jìn) 本指南以 CMake 官方策略文構(gòu)建工具開(kāi)發(fā)工具CLICMake CMP0129 政策解析MCST LCC 編譯器識(shí)別從 GNU 到 LCC 的遷移指南CMake CMP0129 政策解析MCST LCC 編譯器識(shí)別從 GNU 到 LCC 的遷移指南 導(dǎo)讀 本文深入剖析 CMake 3.23 引入的策略 CM構(gòu)建工具開(kāi)發(fā)工具CLI上一篇終極Ventoy指南如何制作一個(gè)永久可用的多系統(tǒng)啟動(dòng)U盤(pán)下一篇Mermaid Live Editor終極指南零代碼創(chuàng)建專(zhuān)業(yè)圖表的免費(fèi)神器創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考