cmake:cmake_policy命令
引入原因
當我們使用 CMake 工具編譯項目的 CMakeLists.txt 存在兩個問題。
- 第一個問題是 CMake 工具版本太舊,
- 第二個問題是 CMake 工具版本太新。
CMake 工具版本太舊的話,可能 CMakeLists.txt 使用了新的語法,就會不兼容;
CMake 工具版本太新的話,也會出現不兼容問題,因為 CMake 新版本在更新時 不一定向后兼容,CMake 老版本的一些功能可能刪除、更改。
為了解決這些差異,保證我們的cmake代碼始終可用,cmake 從版本2.0開始提出了policy這個概念。
使用
隱式的設置策略
使用語法:
- 每個新發布版本一般都會引入一些新的策略,每個策略都會有一個標識號,格式CMP< NNNN >的標識符,<NNNN>對應四個0到9的整數。每個策略都在文檔中描述了OLD和NEW的行為,以及引入的原因。
- 可以通過如下命令來設置使用哪個版本的策略
- < min>:最小版本,至少為2.4,至多為當前安裝的版本號
- < max>:最大版本,至少為< min>
使用場景:
- 如果我們使用了 CMake 新的語法,那么需要通過 cmake_minimum_required() 命令限制 CMake 最低版本需求。
- 如果 CMake 運行的版本 不在<min>...<max>版本 之間,會報錯。
關于cmake_minimum_required和cmake_policy:
-
調用cmake_minimum_required會隱式調用cmake_policy(VERSION),指定版本引入的所有策略都將設置為 NEW 行為。
-
如果沒有特別的策略要指定,可以直接通過調用cmake_minimum_required即可,無需調用cmake_policy。
使用示例:
- CMake 版本 最低為 3.0。
- CMake 版本 最低為 3.0,最高位3.7。
- 如果需要運行 的 CMake 版本 高于 3.0,但是引入的策略為 CMake 版本 在 3.0 和 3.5 之間。
顯式的設置策略
也可以直接使用cmake_policy顯示設置策略的行為,為OLD或為NEW。如下:
// 使用 NEW 來聲明后續代碼依賴于此policy。 cmake_policy(SET CMP<NNNN> NEW) // 使用OLD來向使用此policy的配置過程發出警告信息。 cmake_policy(SET CMP<NNNN> OLD)告訴CMake對給定的策略使用舊的或新的行為。
- 依賴于給定策略的舊行為的項目可以通過將策略狀態設置為“舊”來消除策略警告。
- 或者,可以修復項目以使用新行為,并將策略狀態設置為new。
注意:策略的OLD行為一般不可取,因為在未來的版本中可能被拋棄。
獲取當前設置了什么策略
// 使用GET來獲取當前支持的policy。 cmake_policy(GET CMP<NNNN> <variable>)檢查策略是否設置為 OLD 或 NEW 行為,值存放到< variable >中。如果沒有設置,那么< variable >為空
if (POLICY CMP< CMAKE_POLICY>)
使用此條件來判斷當前的cmake是否支持某條policy。
臨時設置policy
- CMake 將策略設置保存在一個棧結構中,當進入一個項目的子目錄時,就會在策略棧中入棧新的一層元素,離開子目錄時就會出棧這層元素。因此在一個項目的子目錄中設置策略并不會影響父目錄以及同層路徑,但會影響子目錄。
- 這在一個項目包含了多個分別維護的子目錄但在一起編譯時非常有用,它可以讓不同的子目錄使用不同的策略版本。
- 用戶可以使用 cmake_policy 命令來入棧出棧自己的臨時策略層,只要入棧和出棧是成對出現的,這對于臨時對一小段代碼改變策略設置時比較有用。
說明:
- 對cmake_minimum_required(VERSION)、cmake_policy(VERSION)或cmake_policy(SET)命令的調用只影響策略堆棧的當前頂部,影響全局
- cmake_policy(PUSH)、cmake_policy(POP)是臨時的,只影響當前子目錄
實驗
實驗一
向一個CMakeLists.txt中添加以下內容(new表示后繼代碼必須支持此策略):
cmake_policy(SET CMP9999 NEW) # CMP9999 is not defined yet會發現報錯:
> [CMake] CMake Error at CMakeLists.txt:14 (cmake_policy): 1> [CMake] Policy "CMP9999" is not known to this version of CMake.實驗二:策略中 NEW 與 OLD 的區別
例如,我們在 CMake 3.0 版本中,引入策略 CMP0048。表示在 CMake 3.0 版本中,引入 project() 命令使用 VERSION 設定版本。
默認情況下,cmake-3.19.2 會啟用策略 CMP0048。如果不想使用該策略,通過 cmake_policy 命令設置為 OLD。一般設置該策略為 OLD,如果在 project() 命令使用 VERSION 會報錯。
if(POLICY CMP0048)cmake_policy(SET CMP0048 OLD) endif()報錯如下:
可以通過 cmake_policy 命令設置為 NEW,使用該策略,這樣就不會報錯了
if(POLICY CMP0048)cmake_policy(SET CMP0048 NEW) endif()- OLD相當于強制設置某個策略過期
- NEW相當于強制指定使用某個策略
注意,如果你想要查詢CMP0048 之類的是什么行為,去官網找吧
實驗三:
當前場景:
- 假設當前系統上cmake的運行版本為3.0,但是我們cmake_minimum_required(VERSION 2.6) 指定策略版本為 2.6,但是我們要使用cmake 3.0版本引入的CMP0048 怎么辦?
也就是說:
- 我們雖然指定了 CMake 最低運行版本,但是源文件使用了高于 CMake 版本的語法,但是我們不想為了使用了新的語法,而更改 cmake_minimum_required() 命令,那么怎么做?
解決方法:
cmake_minimum_required(VERSION 2.6) if(POLICY CMP0048)cmake_policy(SET CMP0048NEW) endif()說明:
- 對于一些不重要的策略,可以使用一種兼容的手段。
- 如果運行的 CMake 版本 足夠,支持該策略,那么設置為 NEW 行為,因為使用 cmake_minimum_required() 命令通過隱式設置的最新策略為 OLD 行為;
- 如果運行的 CMake 版本不足夠,不支持該策略,那么什么都不做。
實驗三
cmake_policy(PUSH) cmake_policy(SET CMP0057 NEW) ... if (SOME_ITEM IN_LIST SOME_LIST) # IN_LIST needs CMP0057 ... cmake_policy(POP)當使用不支持此policy的cmake版本configure時,cmake會報錯并終止configure流程:
1> [CMake] CMake Error at CMakeProject1/CMakeLists.txt:15 (cmake_policy): 1> [CMake] Policy "CMP0057" is not known to this version of CMake.我們可以使用此方式來聲明該段代碼必須使用支持此policy的cmake版本。注意作用域僅限于此段代碼。
實驗四
cmake_policy(PUSH) cmake_policy(VERSION 3.15) list(PREPEND SOME_LIST ${SOME_ITEM}) # PREPEND needs cmake 3.15 cmake_policy(POP)當使用低于此version的cmake版本configure時,cmake會報錯并終止configure流程:
1> [CMake] CMake Error at CMakeProject1/CMakeLists.txt:15 (cmake_policy): 1> [CMake] An attempt was made to set the policy version of CMake to "3.15" which is 1> [CMake] greater than this version of CMake. This is not allowed because the 1> [CMake] greater version may have new policies not known to this CMake. You may 1> [CMake] need a newer CMake version to build this project.當某個cmake feature沒有設置特定的policy時,我們可以使用此方式來聲明該段代碼必須使用不低于這個版本的cmake。注意作用域僅限于此段代碼。
參考
- cmake教程
- cmake教程
總結
以上是生活随笔為你收集整理的cmake:cmake_policy命令的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 别了dvorak!-----论qwert
- 下一篇: 网页换肤,模块换肤,jQuery的Coo