關鍵概念

本章將介紹 CMake 的關鍵概念。當您開始使用 CMake 時,您會遇到各種概念,例如目標 (targets)、產生器 (generators) 和命令 (commands)。了解這些概念將為您提供建立有效的 CMakeLists 檔案所需的工作知識。許多 CMake 物件,例如目標、目錄和原始碼檔案,都有與它們相關聯的屬性 (properties)。屬性是附加到特定物件的鍵值對 (key-value pair)。存取屬性最常見的方式是透過 set_propertyget_property 命令。這些命令可讓您從 CMake 中任何具有屬性的物件設定或取得屬性。有關支援的屬性列表,請參閱 cmake-properties 手冊。從命令列中,可以透過執行 cmake 並加上 --help-property-list 選項來取得 CMake 中支援的完整屬性列表。

目標 (Targets)

最重要的項目可能是目標。目標代表由 CMake 建置的可執行檔、函式庫和工具。每個 add_libraryadd_executableadd_custom_target 命令都會建立一個目標。例如,以下命令將建立一個名為 “foo” 的目標,它是一個靜態函式庫,並以 foo1.cfoo2.c 作為原始碼檔案。

add_library(foo STATIC foo1.c foo2.c)

現在,“foo” 這個名稱可以在專案中的其他任何地方用作函式庫名稱,並且 CMake 會知道如何在需要時將名稱展開為函式庫。函式庫可以宣告為特定類型,例如 STATICSHAREDMODULE,或是保持未宣告狀態。STATIC 表示該函式庫必須建置為靜態函式庫。SHARED 表示它必須建置為共享函式庫。MODULE 表示該函式庫必須建立為可以動態載入到可執行檔中的形式。模組函式庫在許多平台上都以共享函式庫的形式實作,但並非所有平台都如此。因此,CMake 不允許其他目標連結到模組。如果沒有指定這些選項,則表示該函式庫可以建置為共享或靜態。在這種情況下,CMake 會使用變數 BUILD_SHARED_LIBS 的設定來判斷該函式庫應為 SHAREDSTATIC。如果未設定,則 CMake 預設會建置靜態函式庫。

同樣地,可執行檔也有一些選項。預設情況下,可執行檔將是一個具有主要進入點的傳統主控台應用程式。可以指定 WIN32 選項,要求在 Windows 系統上使用 WinMain 進入點,同時在非 Windows 系統上保留 main。

除了儲存其類型外,目標還會追蹤一般屬性。可以使用 set_target_propertiesget_target_property 命令,或更通用的 set_propertyget_property 命令來設定和檢索這些屬性。一個有用的屬性是 LINK_FLAGS,它用於為特定目標指定額外的連結標誌。目標會儲存它們連結到的函式庫清單,這些函式庫是使用 target_link_libraries 命令設定的。傳遞到此命令中的名稱可以是函式庫、函式庫的完整路徑,或是來自 add_library 命令的函式庫名稱。目標還會儲存連結時要使用的連結目錄,以及建置後要執行的自訂命令。

使用需求 (Usage Requirements)

CMake 還會從連結的函式庫目標傳播「使用需求」。使用需求會影響 <target> 中原始碼的編譯。它們是由連結目標上定義的屬性指定的。

例如,要指定連結到函式庫時需要的 include 目錄,您可以執行以下操作:

add_library(foo foo.cxx)
target_include_directories(foo PUBLIC
                           "${CMAKE_CURRENT_BINARY_DIR}"
                           "${CMAKE_CURRENT_SOURCE_DIR}"
                           )

現在,任何連結到目標 foo 的東西都會自動將 foo 的二進制檔案和原始碼作為 include 目錄。透過「使用需求」引入的 include 目錄的順序將與 target_link_libraries 呼叫中的目標順序相符。

對於 CMake 建立的每個函式庫或可執行檔,它都會使用 target_link_libraries 命令追蹤該目標所依賴的所有函式庫。例如:

add_library(foo foo.cxx)
target_link_libraries(foo bar)

add_executable(foobar foobar.cxx)
target_link_libraries(foobar foo)

即使只為它明確指定了 “foo”,也會將函式庫 “foo” 和 “bar” 連結到可執行檔 “foobar” 中。

使用目標指定最佳化或除錯函式庫

在 Windows 平台上,使用者通常需要將除錯函式庫與除錯函式庫連結,並將最佳化函式庫與最佳化函式庫連結。CMake 使用 target_link_libraries 命令來協助滿足此要求,該命令接受標示為 debugoptimized 的可選標誌。如果函式庫前面有 debugoptimized,則該函式庫只會連結到適當的配置類型。例如:

add_executable(foo foo.c)
target_link_libraries(foo debug libdebug optimized libopt)

在這種情況下,如果選擇了除錯組建,則 foo 將連結到 libdebug,如果選擇了最佳化組建,則連結到 libopt。

物件函式庫 (Object Libraries)

大型專案通常會將其原始碼檔案組織成群組,可能在不同的子目錄中,每個群組都需要不同的 include 目錄和前置處理器定義。對於這種使用情況,CMake 開發了物件函式庫的概念。

物件庫 (Object Library) 是一組編譯成物件檔案的原始程式碼檔案集合,這些物件檔案不會被連結成程式庫檔案或封裝成封存檔。相反地,由 add_libraryadd_executable 建立的其他目標可以使用 $<TARGET_OBJECTS:name> 形式的表示式作為來源來引用這些物件,其中 “name” 是由 add_library 呼叫所建立的目標。例如:

add_library(A OBJECT a.cpp)
add_library(B OBJECT b.cpp)
add_library(Combined $<TARGET_OBJECTS:A> $<TARGET_OBJECTS:B>)

將會在一個名為 Combined 的程式庫中包含 A 和 B 物件檔案。物件庫可能只包含編譯成物件檔案的原始碼(和標頭檔)。

原始程式碼檔案

原始程式碼檔案結構在許多方面都與目標相似。它儲存了檔案名稱、副檔名,以及與原始程式碼檔案相關的許多一般屬性。和目標一樣,您可以使用 set_source_files_propertiesget_source_file_property 或更通用的版本來設定和取得屬性。

目錄、測試和屬性

除了目標和原始程式碼檔案之外,您可能會發現自己偶爾需要使用其他物件,例如目錄和測試。通常這類互動會以設定或取得這些物件的屬性 (例如 set_directory_propertiesset_tests_properties) 的形式進行。