CMake 屬性之目標屬性

梦起丶發表於2024-10-08

【寫在前面】

CMake 可以透過屬性來儲存資訊。它就像是一個變數,但它被附加到一些其他的實體上,像是一個目錄或者是一個目標。例如一個全域性的屬性可以是一個有用的非快取的全域性變數。

在 CMake 的眾多屬性中,目標屬性 ( Target Properties ) 扮演著尤為重要的角色,它們直接關聯到最終生成的可執行檔案、庫檔案等構建產物。

更直觀一點,如果把目標類比為 類 ( Class ),那麼目標屬性則類似 類成員 ( Class Member )

class Target {
    string target_property;
};

【正文開始】

生成目標的方式有三種:

#生成可執行檔案目標test
add_executable(test test.cpp)
#生成共享庫目標test_lib
add_library(test_lib SHARED test.cpp)
#生成靜態庫目標test_lib
add_library(test_lib STATIC test.cpp)

定義目標屬性:

給目標定義屬性的命令為:

define_property(<GLOBAL | DIRECTORY | TARGET | SOURCE |
                 TEST | VARIABLE | CACHED_VARIABLE>
                 PROPERTY <name> [INHERITED]
                 [BRIEF_DOCS <brief-doc> [docs...]]
                 [FULL_DOCS <full-doc> [docs...]]
                 [INITIALIZE_FROM_VARIABLE <variable>])

在範圍內定義一個屬性,用於 set_property()get_property() 命令。它主要用於定義屬性的初始化或繼承方式。從歷史上看,該命令還將文件與屬性相關聯,但這不再被視為主要用例。

示例:

# 定義一個目標屬性 TEST_TARGET,帶有簡短和詳細描述 
define_property(TARGET PROPERTY TEST_TARGET 
    BRIEF_DOCS "A test property"
    FULL_DOCS "A long description of this test property"
)

設定目標屬性:

給目標設定屬性的命令為:

set_property(<GLOBAL                      |
              DIRECTORY [<dir>]           |
              TARGET    [<target1> ...]   |
              SOURCE    [<src1> ...]
                        [DIRECTORY <dirs> ...]
                        [TARGET_DIRECTORY <targets> ...] |
              INSTALL   [<file1> ...]     |
              TEST      [<test1> ...]     |
              CACHE     [<entry1> ...]    >
             [APPEND] [APPEND_STRING]
             PROPERTY <name> [<value1> ...])

在範圍的零個或多個物件上設定一個屬性。

如果給出 APPEND 選項,列表將附加到任何現有的屬性值(除了忽略和不附加空值)。如果給出 APPEND_STRING 選項,字串將作為字串附加到任何現有屬性值,即它會產生更長的字串而不是字串列表。當使用 APPENDAPPEND_STRING 以及定義為支援 INHERITED 行為的屬性時(請參閱 :command:define_property),在找到要附加到的初始值時不會發生繼承。如果該屬性尚未在指定範圍內直接設定,則該命令的行為就好像沒有給出 APPENDAPPEND_STRING 一樣。

其中,有一個專用於設定目標屬性命令:

set_target_properties(target1 target2 ...
                      PROPERTIES prop1 value1
                      prop2 value2 ...)

設定目標的屬性。該命令的語法是列出您要更改的所有目標,然後提供您接下來要設定的值。您可以使用任何您想要的 prop 值對,稍後使用 get_property()get_target_property() 命令提取它。

示例:

# 設定目標 TEST_TARGET 的屬性 P_1 和 P_2 的值
set_target_properties(TEST_TARGET PROPERTIES
    P_1 "這是屬性P_1的值"
    P_2 "這是屬性P_2的值" 
)

獲取目標屬性:

獲取目標的屬性的命令為:

get_property(<variable>
             <GLOBAL             |
              DIRECTORY [<dir>]  |
              TARGET    <target> |
              SOURCE    <source>
                        [DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
              INSTALL   <file>   |
              TEST      <test>   |
              CACHE     <entry>  |
              VARIABLE           >
             PROPERTY <name>
             [SET | DEFINED | BRIEF_DOCS | FULL_DOCS])

從範圍內的一個物件獲取一個屬性。

如果給出了 SET 選項,變數將被設定為一個布林值,指示該屬性是否已被設定。如果給出了 DEFINED 選項,變數將被設定為一個布林值,指示該屬性是否已被定義,例如使用 define_property 命令。 如果給出了BRIEF_DOCSFULL_DOCS,那麼該變數將被設定為一個字串,其中包含所請求屬性的文件。如果為尚未定義的屬性請求文件,則返回 “NOTFOUND”。

其中,有一個專用於獲取目標屬性命令:

get_target_property(<VAR> target property)

從目標獲取屬性。屬性的值儲存在變數“”中。如果未找到目標屬性,則行為取決於它是否已被定義為 INHERITED 屬性(請參閱:command:define_property)。非繼承屬性會將<VAR>設定為<VAR>-NOTFOUND,而繼承屬性將搜尋相關的父範圍,如 define_property() 命令所述,如果仍然找不到屬性 <VAR> 將被設定為空字串。

使用 set_target_properties() 設定目標屬性值。屬性通常用於控制目標的構建方式,但有些屬性會查詢目標。此命令可以獲得迄今為止建立的任何目標的屬性。目標不需要位於當前的 CMakeLists.txt 檔案中。

示例:

# 獲取目標 TEST_TARGET 的屬性 P_1 的值,並將其儲存在變數 TEST_TARGET_P1 中
get_target_property(TEST_TARGET_P1 TEST_TARGET P_1) 

最後完整測試一遍:

# 要求 CMake 最低版本為 3.16
cmake_minimum_required(VERSION 3.16)

# 定義專案名稱為 PROPERTY_TEST,版本號為 1.0,使用 C++ 語言
project(PROPERTY_TEST VERSION 1.0 LANGUAGES CXX)

# 新增一個名為 TEST_TARGET 的可執行檔案,其原始檔為 test.cpp
add_executable(TEST_TARGET test.cpp)

# 定義一個目標屬性 TEST_TARGET,帶有簡短和詳細描述 
define_property(TARGET PROPERTY TEST_TARGET 
    BRIEF_DOCS "A test property"
    FULL_DOCS "A long description of this test property"
)

# 設定目標 TEST_TARGET 的屬性 P_1 和 P_2 的值
set_target_properties(TEST_TARGET PROPERTIES
    P_1 "這是屬性P_1的值"
    P_2 "這是屬性P_2的值" 
)

# 獲取目標 TEST_TARGET 的屬性 P_1 的值,並將其儲存在變數 TEST_TARGET_P1 中
get_target_property(TEST_TARGET_P1 TEST_TARGET P_1) 

# 列印變數 TEST_TARGET_P1 的值
message("TEST_TARGET_P1: ${TEST_TARGET_P1}") 

CMake 輸出如下:

image


【結語】

最後,屬性在 CMake 中是可繼承的。這意味著,如果一個目標繼承了另一個目標的屬性,那麼它將自動獲得父目標的屬性值。這種繼承關係在構建大型專案時非常有用,因為它減少了重複的配置。

CMake 的屬性系統是一個強大的工具,它提供了細粒度的控制,允許我們定製構建過程。透過合理使用屬性,我們可以建立更加靈活和可維護的構建系統。掌握屬性的使用,是每個 CMake 使用者進階的必經之路,希望這篇文章能夠幫助你更好地理解和使用 CMake 的屬性系統。

專案連結(多多star呀..⭐_⭐):

Github 地址:https://github.com/mengps/LearnCMake