【寫在前面】
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
選項,字串將作為字串附加到任何現有屬性值,即它會產生更長的字串而不是字串列表。當使用APPEND
或APPEND_STRING
以及定義為支援INHERITED
行為的屬性時(請參閱:command:define_property
),在找到要附加到的初始值時不會發生繼承。如果該屬性尚未在指定範圍內直接設定,則該命令的行為就好像沒有給出APPEND
或APPEND_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_DOCS
或FULL_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 輸出如下:
【結語】
最後,屬性在 CMake 中是可繼承的。這意味著,如果一個目標繼承了另一個目標的屬性,那麼它將自動獲得父目標的屬性值。這種繼承關係在構建大型專案時非常有用,因為它減少了重複的配置。
CMake 的屬性系統是一個強大的工具,它提供了細粒度的控制,允許我們定製構建過程。透過合理使用屬性,我們可以建立更加靈活和可維護的構建系統。掌握屬性的使用,是每個 CMake 使用者進階的必經之路,希望這篇文章能夠幫助你更好地理解和使用 CMake 的屬性系統。
專案連結(多多star呀..⭐_⭐):
Github 地址:https://github.com/mengps/LearnCMake