mirror of
https://github.com/Kitware/CMake.git
synced 2025-12-31 19:00:54 -06:00
@@ -9,7 +9,8 @@ Define and document custom properties.
|
||||
TEST | VARIABLE | CACHED_VARIABLE>
|
||||
PROPERTY <name> [INHERITED]
|
||||
[BRIEF_DOCS <brief-doc> [docs...]]
|
||||
[FULL_DOCS <full-doc> [docs...]])
|
||||
[FULL_DOCS <full-doc> [docs...]]
|
||||
[INITIALIZE_FROM_VARIABLE <variable>])
|
||||
|
||||
Defines one property in a scope for use with the :command:`set_property` and
|
||||
:command:`get_property` commands. This is primarily useful to associate
|
||||
@@ -57,3 +58,8 @@ The ``BRIEF_DOCS`` and ``FULL_DOCS`` options are followed by strings to be
|
||||
associated with the property as its brief and full documentation.
|
||||
Corresponding options to the :command:`get_property` command will retrieve
|
||||
the documentation.
|
||||
|
||||
The ``INITIALIZE_FROM_VARIABLE`` option is followed by the name of a variable
|
||||
from which to initialize the property. The variable name must end with the
|
||||
property name, must have a prefix before the property name, and must not begin
|
||||
with ``CMAKE_`` or ``_CMAKE_``.
|
||||
|
||||
5
Help/release/dev/target-properties-from-variables.rst
Normal file
5
Help/release/dev/target-properties-from-variables.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
target-properties-from-variables
|
||||
--------------------------------
|
||||
|
||||
* The :command:`define_property` command gained a new
|
||||
``INITIALIZE_FROM_VARIABLE`` argument.
|
||||
@@ -2,6 +2,9 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmDefinePropertyCommand.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
#include <cmext/string_view>
|
||||
|
||||
#include "cmArgumentParser.h"
|
||||
@@ -50,12 +53,14 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args,
|
||||
std::string PropertyName;
|
||||
std::vector<std::string> BriefDocs;
|
||||
std::vector<std::string> FullDocs;
|
||||
std::string initializeFromVariable;
|
||||
|
||||
cmArgumentParser<void> parser;
|
||||
parser.Bind("PROPERTY"_s, PropertyName);
|
||||
parser.Bind("BRIEF_DOCS"_s, BriefDocs);
|
||||
parser.Bind("FULL_DOCS"_s, FullDocs);
|
||||
parser.Bind("INHERITED"_s, inherited);
|
||||
parser.Bind("INITIALIZE_FROM_VARIABLE"_s, initializeFromVariable);
|
||||
std::vector<std::string> invalidArgs;
|
||||
|
||||
parser.Parse(cmMakeRange(args).advance(1), &invalidArgs);
|
||||
@@ -71,10 +76,47 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!initializeFromVariable.empty()) {
|
||||
// Make sure property scope is TARGET.
|
||||
if (scope != cmProperty::TARGET) {
|
||||
status.SetError(
|
||||
"Scope must be TARGET if INITIALIZE_FROM_VARIABLE is specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure the variable has the property name as a suffix.
|
||||
if (!cmHasSuffix(initializeFromVariable, PropertyName)) {
|
||||
status.SetError(cmStrCat("Variable name \"", initializeFromVariable,
|
||||
"\" does not end with property name \"",
|
||||
PropertyName, "\""));
|
||||
return false;
|
||||
}
|
||||
if (initializeFromVariable == PropertyName) {
|
||||
status.SetError(cmStrCat(
|
||||
"Variable name must have a non-empty prefix before property name \"",
|
||||
PropertyName, "\""));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the variable is not reserved.
|
||||
static constexpr const char* reservedPrefixes[] = {
|
||||
"CMAKE_",
|
||||
"_CMAKE_",
|
||||
};
|
||||
if (std::any_of(std::begin(reservedPrefixes), std::end(reservedPrefixes),
|
||||
[&initializeFromVariable](const char* prefix) {
|
||||
return cmHasPrefix(initializeFromVariable, prefix);
|
||||
})) {
|
||||
status.SetError(
|
||||
cmStrCat("variable name \"", initializeFromVariable, "\" is reserved"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Actually define the property.
|
||||
status.GetMakefile().GetState()->DefineProperty(
|
||||
PropertyName, scope, cmJoin(BriefDocs, ""), cmJoin(FullDocs, ""),
|
||||
inherited);
|
||||
inherited, initializeFromVariable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,31 +6,34 @@
|
||||
|
||||
cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription,
|
||||
std::string fullDescription,
|
||||
bool chained)
|
||||
bool chained,
|
||||
std::string initializeFromVariable)
|
||||
: ShortDescription(std::move(shortDescription))
|
||||
, FullDescription(std::move(fullDescription))
|
||||
, Chained(chained)
|
||||
, InitializeFromVariable(std::move(initializeFromVariable))
|
||||
{
|
||||
}
|
||||
|
||||
void cmPropertyDefinitionMap::DefineProperty(
|
||||
const std::string& name, cmProperty::ScopeType scope,
|
||||
const std::string& ShortDescription, const std::string& FullDescription,
|
||||
bool chain)
|
||||
bool chain, const std::string& initializeFromVariable)
|
||||
{
|
||||
auto it = this->Map_.find(key_type(name, scope));
|
||||
auto it = this->Map_.find(KeyType(name, scope));
|
||||
if (it == this->Map_.end()) {
|
||||
// try_emplace() since C++17
|
||||
this->Map_.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(name, scope),
|
||||
std::forward_as_tuple(ShortDescription, FullDescription, chain));
|
||||
this->Map_.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(name, scope),
|
||||
std::forward_as_tuple(ShortDescription, FullDescription,
|
||||
chain, initializeFromVariable));
|
||||
}
|
||||
}
|
||||
|
||||
cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition(
|
||||
const std::string& name, cmProperty::ScopeType scope) const
|
||||
{
|
||||
auto it = this->Map_.find(key_type(name, scope));
|
||||
auto it = this->Map_.find(KeyType(name, scope));
|
||||
if (it != this->Map_.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ class cmPropertyDefinition
|
||||
public:
|
||||
/// Constructor
|
||||
cmPropertyDefinition(std::string shortDescription,
|
||||
std::string fullDescription, bool chained);
|
||||
std::string fullDescription, bool chained,
|
||||
std::string initializeFromVariable);
|
||||
|
||||
/// Is the property chained?
|
||||
bool IsChained() const { return this->Chained; }
|
||||
@@ -39,10 +40,17 @@ public:
|
||||
return this->FullDescription;
|
||||
}
|
||||
|
||||
/// Get the variable the property is initialized from
|
||||
const std::string& GetInitializeFromVariable() const
|
||||
{
|
||||
return this->InitializeFromVariable;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string ShortDescription;
|
||||
std::string FullDescription;
|
||||
bool Chained;
|
||||
std::string InitializeFromVariable;
|
||||
};
|
||||
|
||||
/** \class cmPropertyDefinitionMap
|
||||
@@ -54,13 +62,19 @@ public:
|
||||
// define the property
|
||||
void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
|
||||
const std::string& ShortDescription,
|
||||
const std::string& FullDescription, bool chain);
|
||||
const std::string& FullDescription, bool chain,
|
||||
const std::string& initializeFromVariable);
|
||||
|
||||
// get the property definition if present, otherwise nullptr
|
||||
cmPropertyDefinition const* GetPropertyDefinition(
|
||||
const std::string& name, cmProperty::ScopeType scope) const;
|
||||
|
||||
using KeyType = std::pair<std::string, cmProperty::ScopeType>;
|
||||
const std::map<KeyType, cmPropertyDefinition>& GetMap() const
|
||||
{
|
||||
return this->Map_;
|
||||
}
|
||||
|
||||
private:
|
||||
using key_type = std::pair<std::string, cmProperty::ScopeType>;
|
||||
std::map<key_type, cmPropertyDefinition> Map_;
|
||||
std::map<KeyType, cmPropertyDefinition> Map_;
|
||||
};
|
||||
|
||||
@@ -327,10 +327,12 @@ cmStateSnapshot cmState::Reset()
|
||||
void cmState::DefineProperty(const std::string& name,
|
||||
cmProperty::ScopeType scope,
|
||||
const std::string& ShortDescription,
|
||||
const std::string& FullDescription, bool chained)
|
||||
const std::string& FullDescription, bool chained,
|
||||
const std::string& initializeFromVariable)
|
||||
{
|
||||
this->PropertyDefinitions.DefineProperty(name, scope, ShortDescription,
|
||||
FullDescription, chained);
|
||||
FullDescription, chained,
|
||||
initializeFromVariable);
|
||||
}
|
||||
|
||||
cmPropertyDefinition const* cmState::GetPropertyDefinition(
|
||||
|
||||
@@ -133,12 +133,18 @@ public:
|
||||
// Define a property
|
||||
void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
|
||||
const std::string& ShortDescription,
|
||||
const std::string& FullDescription, bool chain = false);
|
||||
const std::string& FullDescription, bool chain = false,
|
||||
const std::string& initializeFromVariable = "");
|
||||
|
||||
// get property definition
|
||||
cmPropertyDefinition const* GetPropertyDefinition(
|
||||
const std::string& name, cmProperty::ScopeType scope) const;
|
||||
|
||||
const cmPropertyDefinitionMap& GetPropertyDefinitions() const
|
||||
{
|
||||
return this->PropertyDefinitions;
|
||||
}
|
||||
|
||||
bool IsPropertyChained(const std::string& name,
|
||||
cmProperty::ScopeType scope) const;
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmProperty.h"
|
||||
#include "cmPropertyDefinition.h"
|
||||
#include "cmPropertyMap.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmSourceFile.h"
|
||||
@@ -557,6 +558,16 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& prop : mf->GetState()->GetPropertyDefinitions().GetMap()) {
|
||||
if (prop.first.second == cmProperty::TARGET &&
|
||||
!prop.second.GetInitializeFromVariable().empty()) {
|
||||
if (auto value =
|
||||
mf->GetDefinition(prop.second.GetInitializeFromVariable())) {
|
||||
this->SetProperty(prop.first.first, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmTarget::cmTarget(cmTarget&&) noexcept = default;
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
include(RunCMake)
|
||||
|
||||
run_cmake(define_property)
|
||||
run_cmake(define_property-INITIALIZE_FROM_VARIABLE)
|
||||
run_cmake(define_property-INITIALIZE_FROM_VARIABLE-invalid_1)
|
||||
run_cmake(define_property-INITIALIZE_FROM_VARIABLE-invalid_2)
|
||||
run_cmake(define_property-INITIALIZE_FROM_VARIABLE-non_target)
|
||||
run_cmake(define_property-INITIALIZE_FROM_VARIABLE-wrong_suffix)
|
||||
run_cmake(define_property-INITIALIZE_FROM_VARIABLE-no_prefix)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at define_property-INITIALIZE_FROM_VARIABLE-invalid_1\.cmake:[0-9]+ \(define_property\):
|
||||
define_property variable name "CMAKE_PROP1" is reserved
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1,3 @@
|
||||
define_property(TARGET PROPERTY PROP1
|
||||
INITIALIZE_FROM_VARIABLE CMAKE_PROP1
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
^CMake Error at define_property-INITIALIZE_FROM_VARIABLE-invalid_2\.cmake:[0-9]+ \(define_property\):
|
||||
define_property variable name "_CMAKE_PROP1" is reserved
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1,3 @@
|
||||
define_property(TARGET PROPERTY PROP1
|
||||
INITIALIZE_FROM_VARIABLE _CMAKE_PROP1
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
^CMake Error at define_property-INITIALIZE_FROM_VARIABLE-no_prefix\.cmake:[0-9]+ \(define_property\):
|
||||
define_property Variable name must have a non-empty prefix before property
|
||||
name "PROP1"
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1,3 @@
|
||||
define_property(TARGET PROPERTY PROP1
|
||||
INITIALIZE_FROM_VARIABLE PROP1
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
^CMake Error at define_property-INITIALIZE_FROM_VARIABLE-non_target\.cmake:[0-9]+ \(define_property\):
|
||||
define_property Scope must be TARGET if INITIALIZE_FROM_VARIABLE is
|
||||
specified
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1,3 @@
|
||||
define_property(GLOBAL PROPERTY PROP1
|
||||
INITIALIZE_FROM_VARIABLE Test_PROP1
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
define_property(TARGET PROPERTY PROP2
|
||||
INITIALIZE_FROM_VARIABLE Test_PROP2
|
||||
)
|
||||
define_property(TARGET PROPERTY PROP3
|
||||
INITIALIZE_FROM_VARIABLE Test_PROP3
|
||||
)
|
||||
|
||||
add_executable(sub_exe ../main.c)
|
||||
assert_prop_eq(sub_exe PROP1 "Hello")
|
||||
assert_prop_eq(sub_exe PROP2 "world")
|
||||
assert_prop_eq(sub_exe PROP3 "!")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
^CMake Error at define_property-INITIALIZE_FROM_VARIABLE-wrong_suffix\.cmake:[0-9]+ \(define_property\):
|
||||
define_property Variable name "Test_PROP2" does not end with property name
|
||||
"PROP1"
|
||||
Call Stack \(most recent call first\):
|
||||
CMakeLists\.txt:[0-9]+ \(include\)$
|
||||
@@ -0,0 +1,3 @@
|
||||
define_property(TARGET PROPERTY PROP1
|
||||
INITIALIZE_FROM_VARIABLE Test_PROP2
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
enable_language(C)
|
||||
|
||||
function(assert_prop_eq tgt name value)
|
||||
get_property(actual_value TARGET ${tgt} PROPERTY ${name})
|
||||
if(NOT actual_value STREQUAL value)
|
||||
message(SEND_ERROR "Expected value of ${name}:\n ${value}\nActual value:\n ${actual_value}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(assert_prop_undef tgt name)
|
||||
get_property(actual_value TARGET ${tgt} PROPERTY ${name})
|
||||
if(DEFINED actual_value)
|
||||
message(SEND_ERROR "Expected ${name} to be undefined, actual value:\n ${actual_value}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(Test_PROP1 "Hello")
|
||||
set(Test_PROP2 "world")
|
||||
set(Test_PROP3 "!")
|
||||
define_property(TARGET PROPERTY PROP1
|
||||
INITIALIZE_FROM_VARIABLE Test_PROP1
|
||||
)
|
||||
|
||||
add_subdirectory(define_property-INITIALIZE_FROM_VARIABLE-subdirectory)
|
||||
|
||||
add_executable(top_exe main.c)
|
||||
assert_prop_eq(top_exe PROP1 "Hello")
|
||||
assert_prop_eq(top_exe PROP2 "world")
|
||||
assert_prop_eq(top_exe PROP3 "!")
|
||||
4
Tests/RunCMake/define_property/main.c
Normal file
4
Tests/RunCMake/define_property/main.c
Normal file
@@ -0,0 +1,4 @@
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user