[Writing in front]
CMake can store information through attributes. It's like a variable, but it's attached to some other entity, like a directory or a target. For example a global property can be a useful non-cached global variable.
Among CMake's many attributes, the target attribute (Target Properties ) play a particularly important role, and they are directly related to the final build products such as executables and libraries.
More intuitively, if the goal is analogous to theClass, then the target attribute is similarClass Member。
class Target {
string target_property;
};
[Text Begins]
There are three ways to generate goals:
# Generate executable target test
add_executable(test )
# Generate shared library target test_lib
add_library(test_lib SHARED )
# Generate static library target test_lib
add_library(test_lib STATIC )
Define the target attributes:
The command to define properties for the target is:
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>])
Define an attribute in the scope forset_property() respond in singingget_property() command. It is primarily used to define how attributes are initialized or inherited. Historically, the command also associated documents with attributes, but this is no longer considered the primary use case.
Example:
# Define a target property TEST_TARGET with a short and detailed description
define_property(TARGET PROPERTY TEST_TARGET
BRIEF_DOCS "A test property"
FULL_DOCS "A long description of this test property"
)
Set the target properties:
The command to set properties for the target is:
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> ...])
Sets an attribute on zero or more objects in the range.
One of them is dedicated to the Set Target Properties command:
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
Sets the properties of the target. The syntax of this command is to list all the targets you want to change and then provide the values you want to set next. You can use any prop value pairs you want, and later use theget_property() maybeget_target_property() command to extract it.
Example:
# Set the values of the properties P_1 and P_2 of the target TEST_TARGET
set_target_properties(TEST_TARGET PROPERTIES
P_1 "This is the value of property P_1"
P_2 "This is the value of property P_2"
)
Get target attributes:
The command to get the properties of the target is:
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])
Gets an attribute from an object in scope.
One of them is dedicated to the Get Target Attributes command:
get_target_property(<VAR> target property)
Get attributes from the target. The value of the attribute is stored in the variable "" in. If the target attribute is not found, the behavior depends on whether it has been defined as a
INHERITED
properties (see :command:define_property). Non-inherited properties will set the<VAR>
set to<VAR>-NOTFOUND
, while inherited properties will search for related parent scopes such asdefine_property() command, if the attribute is still not found<VAR>
will be set to the empty string.utilizationset_target_properties() Sets the value of a target attribute. Attributes are usually used to control how the target is built, but some attributes query the target. This command gets the properties of any target created so far. The target does not need to be located in the current file.
Example:
# Get the value of property P_1 of the target TEST_TARGET and store it in the variable TEST_TARGET_P1
get_target_property(TEST_TARGET_P1 TEST_TARGET P_1)
Test it all over again in its entirety at the end:
# Require a minimum CMake version of 3.16.
cmake_minimum_required(VERSION 3.16)
# Define the project name as PROPERTY_TEST, version 1.0, in C++.
project(PROPERTY_TEST VERSION 1.0 LANGUAGES CXX)
# Add an executable named TEST_TARGET with the following source file
add_executable(TEST_TARGET )
# Define a target property TEST_TARGET with a short and detailed description
define_property(TARGET PROPERTY TEST_TARGET
BRIEF_DOCS "A test property"
FULL_DOCS "A long description of this test property"
)
# Set the values of properties P_1 and P_2 of the target TEST_TARGET
set_target_properties(TEST_TARGET PROPERTIES
P_1 "This is the value of property P_1"
P_2 "This is the value of property P_2"
)
# Get the value of property P_1 of the target TEST_TARGET and store it in the variable TEST_TARGET_P1
get_target_property(TEST_TARGET_P1 TEST_TARGET P_1)
# Print the value of the variable TEST_TARGET_P1
message("TEST_TARGET_P1: ${TEST_TARGET_P1}")
CMake output is as follows:
[Conclusion]
Finally, properties are inheritable in CMake. This means that if a target inherits a property from another target, it will automatically get the value of the parent target's property. This inheritance relationship is useful when building large projects because it reduces duplicate configurations.
CMake's property system is a powerful tool that provides fine-grained control and allows us to customize the build process. By using properties wisely, we can create a more flexible and maintainable build system. Mastering the use of properties is a must for every CMake user, and I hope this article will help you better understand and use CMake's property system.
Link to the project (more star ah.... ⭐_⭐):
Github Address:/mengps/LearnCMake