這是每一個 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 中修復。 ↩