<> 翻譯 2. CMake 基礎

<<Modern CMake>> 翻譯 2. CMake 基礎

最低版本

這是每一個 CMakeLists.txt 文件的第一行。CMakeLists.txt 是 CMake 所需的配置文件名稱:html

cmake_minimum_required(VERSION 3.1) 

咱們來了解一點 CMake 語法。 命令名稱 cmake_minimum_required 不區分大小寫,所以一般的作法是使用小寫。1 這裏 VERSION 是該命令所需的特殊關鍵字。 版本號緊跟在 VERSION 關鍵字以後。 與本書中的任何其餘地方同樣,你只需單擊命令名稱便可連接到官方文檔,而後可使用下拉列表切換不一樣版本的 CMake 文檔。git

這一行很特別!2 版本號也同時指明瞭 CMake 的行爲變化。 所以,若是你設置 minimum_required 爲 VERSION 2.8,在macOS上你就會得到錯誤的連接行爲, 例如,在最新的 CMake 版本中也是如此。 若是你把版本設置爲 3.3 或更低,你會獲得錯誤的符號隱藏行爲,等等。 在 policies 有一個策略和版本列表。github

在 CMake 3.12 中,能夠這樣寫來指定支持的 CMake 版本範圍,例如 VERSION 3.1...3.12; 這意味着您最低支持 3.1,同時也測試過並支持到 3.12 的新策略。 這對於須要更好設置的用戶來講很不錯,而且因爲語法上的技巧,它向後兼容舊版本的 CMake(儘管實際運行 CMake 3.2-3.11 只會在此示例中設置 3.1 版本的策略)。 新版本的策略對於 macOS 和 Windows 用戶來講每每是最重要的,他們一般也有最新版本的 CMake。服務器

新項目應該這樣寫:app

cmake_minimum_required(VERSION 3.1...3.15) if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) endif() 

若是 CMake 版本小於 3.12,則 if 塊將爲 true,而且策略將設置爲當前 CMake 版本。 若是 CMake 爲 3.12 或更高,if 塊將爲 false,此時新語法 cmake_minimum_required 將起做用,這將可以正常工做!測試

警告:MSVC 的 CMake 服務器模式最初在讀取此格式時有一個 bug, 所以若是您須要支持舊版 MSVC 的非命令行 Windows 版本,則須要執行如下操做:ui

cmake_minimum_required(VERSION 3.1) if(${CMAKE_VERSION} VERSION_LESS 3.15) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) else() cmake_policy(VERSION 3.15) endif() 

 

 

若是您確實須要在此處設置較低的版本,則可使用 cmake_policy 有條件地增長策略級別或設置特定策略。 請至少爲您的 macOS 用戶執行此操做!spa

 

設置項目

如今,每一個頂級 CMake 文件(CMakeLists.txt)都有下面這一行:命令行

project(MyProject VERSION 1.0 DESCRIPTION "很是出色的項目" LANGUAGES CXX) 

如今咱們看到了更多的新語法。 字符串被引號包圍起來,空格可多可少,項目名稱是第一個參數(位置參數)。 這裏的全部的關鍵字參數都是可選的。 經過 VERSION 參數,這會設置了一堆變量,好比 MyProject_VERSION 和 PROJECT_VERSION。 LANGUAGE 能夠是 C,CXX,Fortran 和 CUDA(CMake 3.7+)。 C CXX 是默認值。 在 CMake 3.9 中,DESCRIPTION 添加進來設置對項目的描述。 你能夠參考 project 這個文檔。翻譯

 

 

你能夠經過使用 # 開頭來添加 註釋。 CMake 也有註釋的內聯語法,但不多須要,由於空格並不重要。

 

項目名稱沒什麼特別之處。此時不添加任何目標。

生成可執行文件

雖然連接庫更有趣,一般咱們大部分時間都在生成連接庫,但這裏咱們要從一個簡單的可執行文件開始。

add_executable(one two.cpp three.h) 

這裏有幾件要說明的事情。 one 是生成的可執行文件的名稱,同時也是建立的 CMake 目標的名稱(我保證你會很快聽到不少關於目標的信息)。 可執行文件名稱後緊接的是源文件列表,您能夠根據須要列出任意數量的源文件列表。 CMake 很聰明,會根據文件擴展名正確識別源文件,因此列表中的頭文件會被 CMake 理解並忽略。 大多數時候,咱們在源文件列表中列出頭文件的惟一緣由是讓它們出如今 IDE 中。 有關通用構建系統和目標的更多信息,請參見 buildsystem

生成連接庫

使用 add_library 生成連接庫, 也是很是簡單:

add_library(one STATIC two.cpp three.h) 

您能夠選擇連接庫類型:STATIC,SHARED 或 MODULE。 若是沒有設置,CMake 會根據變量 BUILD_SHARED_LIBS 的值在 STATIC 和 SHARED 之間選擇。

正如您將在下一節中看到的那樣,一般您須要建立一個僞目標,也就是一個不須要編譯任何文件的目標,例如,對於僅包含頭文件的庫。這也能夠稱爲 INTERFACE 庫; 惟一的區別是接口庫不能跟文件名。

您還能夠用一個現有的連接庫生成一個 ALIAS 連接庫,該庫簡單地爲您提供目標的新名稱。這樣作的一個好處是你能夠生成一個名稱中帶 :: 的連接庫(稍後會看到)。3

配置構建目標

如今咱們已經指定了目標,而後咱們怎麼給它添加相關信息呢?例如,它可能須要一個 include 目錄:

target_include_directories(one PUBLIC include) 

target_include_directories 將 include 目錄添加到目標. PUBLIC 對可執行文件來講意義不大; 對於一個連接庫,它讓 CMake 知道連接到這個目標的任何目標也必須包含該目錄。 其餘選項是 PRIVATE(僅影響當前目標,而不影響依賴項)和 INTERFACE(僅限依賴項所需)。

如今,咱們能夠把目標串聯起來:

add_library(another STATIC another.cpp another.h) target_link_libraries(another PUBLIC one) 

target_link_libraries 多是 CMake 中最有用也最使人困惑的命令。 它須要一個target(another)並添加依賴目標項。 若是名爲 one 的目標不存在,則它會添加指向路徑上的一個叫作 one 連接庫(即命令的名稱)。 或者你能夠給它一個完整的連接庫路徑。或連接器標誌。 最後還有一點容易混淆的東西,那就是經典的 CMake 容許你忽略關鍵字 PUBLIC,等等。 若是目標已經連接完成,嘗試在鏈中進一步混合樣式,你會收到錯誤。

主要關注在任何地方使用目標和關鍵字,這就對了。

目標能夠包含目錄,連接庫(或連接目標),編譯選項,編譯定義,編譯特徵(參見 C++11 章節)等。 正如您將在兩個包括項目章節中看到的那樣,您一般可使用目標(並始終制做目標)來表示全部你使用的連接庫。 即便那不是真正的連接庫的,好比 OpenMP,也能夠用目標來表示。 這就是現代 CMake 很棒的緣由!

開始動手實踐

看看您是否能夠理解如下文件操做。 它建立了一個簡單的 C++11 連接庫和一個使用它的程序。 沒有依賴。 我稍後將使用 CMake 3.8 系統討論更多 C++ 標準選項。

cmake_minimum_required(VERSION 3.8) project(Calculator LANGUAGES CXX) add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp) target_include_directories(calclib PUBLIC include) target_compile_features(calclib PUBLIC cxx_std_11) add_executable(calc apps/calc.cpp) target_link_libraries(calc PUBLIC calclib) 
1. 在這本書中,我將盡量避免向你展現錯誤的作事方式; 你能夠在網上找到不少這方面的例子。我偶爾會提到替代作法,但除非絕對必要,不然不推薦這些。一般它們只是幫助您閱讀較老的 CMake 代碼。  ↩
2. 你有時會看到  FATAL_ERROR, 在 CMake <2.6 版本中,須要使用它來支持失敗,如今已經不須要了。
3.  :: 語法最初用來生成  INTERFACE IMPORTED 連接庫, 可是,正由於如此,大多數  target_* 命令都不適用於  IMPORTED 連接庫。這使得它們很難自行設置。因此如今不要使用  IMPORTED 關鍵字,請使用  ALIAS 構件目標; 這在你導出目標前都能正常工做。此限制已經在 CMake 3.11 中修復。  ↩
相關文章
相關標籤/搜索