mirror of
https://github.com/Kitware/CMake.git
synced 2026-05-01 03:29:18 -05:00
@@ -9,7 +9,8 @@ Define and document custom properties.
|
|||||||
TEST | VARIABLE | CACHED_VARIABLE>
|
TEST | VARIABLE | CACHED_VARIABLE>
|
||||||
PROPERTY <name> [INHERITED]
|
PROPERTY <name> [INHERITED]
|
||||||
[BRIEF_DOCS <brief-doc> [docs...]]
|
[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
|
Defines one property in a scope for use with the :command:`set_property` and
|
||||||
:command:`get_property` commands. This is primarily useful to associate
|
: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.
|
associated with the property as its brief and full documentation.
|
||||||
Corresponding options to the :command:`get_property` command will retrieve
|
Corresponding options to the :command:`get_property` command will retrieve
|
||||||
the documentation.
|
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_``.
|
||||||
|
|||||||
@@ -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. */
|
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||||
#include "cmDefinePropertyCommand.h"
|
#include "cmDefinePropertyCommand.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
#include <cmext/string_view>
|
#include <cmext/string_view>
|
||||||
|
|
||||||
#include "cmArgumentParser.h"
|
#include "cmArgumentParser.h"
|
||||||
@@ -50,12 +53,14 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args,
|
|||||||
std::string PropertyName;
|
std::string PropertyName;
|
||||||
std::vector<std::string> BriefDocs;
|
std::vector<std::string> BriefDocs;
|
||||||
std::vector<std::string> FullDocs;
|
std::vector<std::string> FullDocs;
|
||||||
|
std::string initializeFromVariable;
|
||||||
|
|
||||||
cmArgumentParser<void> parser;
|
cmArgumentParser<void> parser;
|
||||||
parser.Bind("PROPERTY"_s, PropertyName);
|
parser.Bind("PROPERTY"_s, PropertyName);
|
||||||
parser.Bind("BRIEF_DOCS"_s, BriefDocs);
|
parser.Bind("BRIEF_DOCS"_s, BriefDocs);
|
||||||
parser.Bind("FULL_DOCS"_s, FullDocs);
|
parser.Bind("FULL_DOCS"_s, FullDocs);
|
||||||
parser.Bind("INHERITED"_s, inherited);
|
parser.Bind("INHERITED"_s, inherited);
|
||||||
|
parser.Bind("INITIALIZE_FROM_VARIABLE"_s, initializeFromVariable);
|
||||||
std::vector<std::string> invalidArgs;
|
std::vector<std::string> invalidArgs;
|
||||||
|
|
||||||
parser.Parse(cmMakeRange(args).advance(1), &invalidArgs);
|
parser.Parse(cmMakeRange(args).advance(1), &invalidArgs);
|
||||||
@@ -71,10 +76,47 @@ bool cmDefinePropertyCommand(std::vector<std::string> const& args,
|
|||||||
return false;
|
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.
|
// Actually define the property.
|
||||||
status.GetMakefile().GetState()->DefineProperty(
|
status.GetMakefile().GetState()->DefineProperty(
|
||||||
PropertyName, scope, cmJoin(BriefDocs, ""), cmJoin(FullDocs, ""),
|
PropertyName, scope, cmJoin(BriefDocs, ""), cmJoin(FullDocs, ""),
|
||||||
inherited);
|
inherited, initializeFromVariable);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,31 +6,34 @@
|
|||||||
|
|
||||||
cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription,
|
cmPropertyDefinition::cmPropertyDefinition(std::string shortDescription,
|
||||||
std::string fullDescription,
|
std::string fullDescription,
|
||||||
bool chained)
|
bool chained,
|
||||||
|
std::string initializeFromVariable)
|
||||||
: ShortDescription(std::move(shortDescription))
|
: ShortDescription(std::move(shortDescription))
|
||||||
, FullDescription(std::move(fullDescription))
|
, FullDescription(std::move(fullDescription))
|
||||||
, Chained(chained)
|
, Chained(chained)
|
||||||
|
, InitializeFromVariable(std::move(initializeFromVariable))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmPropertyDefinitionMap::DefineProperty(
|
void cmPropertyDefinitionMap::DefineProperty(
|
||||||
const std::string& name, cmProperty::ScopeType scope,
|
const std::string& name, cmProperty::ScopeType scope,
|
||||||
const std::string& ShortDescription, const std::string& FullDescription,
|
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()) {
|
if (it == this->Map_.end()) {
|
||||||
// try_emplace() since C++17
|
// try_emplace() since C++17
|
||||||
this->Map_.emplace(
|
this->Map_.emplace(std::piecewise_construct,
|
||||||
std::piecewise_construct, std::forward_as_tuple(name, scope),
|
std::forward_as_tuple(name, scope),
|
||||||
std::forward_as_tuple(ShortDescription, FullDescription, chain));
|
std::forward_as_tuple(ShortDescription, FullDescription,
|
||||||
|
chain, initializeFromVariable));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition(
|
cmPropertyDefinition const* cmPropertyDefinitionMap::GetPropertyDefinition(
|
||||||
const std::string& name, cmProperty::ScopeType scope) const
|
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()) {
|
if (it != this->Map_.end()) {
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ class cmPropertyDefinition
|
|||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
cmPropertyDefinition(std::string shortDescription,
|
cmPropertyDefinition(std::string shortDescription,
|
||||||
std::string fullDescription, bool chained);
|
std::string fullDescription, bool chained,
|
||||||
|
std::string initializeFromVariable);
|
||||||
|
|
||||||
/// Is the property chained?
|
/// Is the property chained?
|
||||||
bool IsChained() const { return this->Chained; }
|
bool IsChained() const { return this->Chained; }
|
||||||
@@ -39,10 +40,17 @@ public:
|
|||||||
return this->FullDescription;
|
return this->FullDescription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the variable the property is initialized from
|
||||||
|
const std::string& GetInitializeFromVariable() const
|
||||||
|
{
|
||||||
|
return this->InitializeFromVariable;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string ShortDescription;
|
std::string ShortDescription;
|
||||||
std::string FullDescription;
|
std::string FullDescription;
|
||||||
bool Chained;
|
bool Chained;
|
||||||
|
std::string InitializeFromVariable;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** \class cmPropertyDefinitionMap
|
/** \class cmPropertyDefinitionMap
|
||||||
@@ -54,13 +62,19 @@ public:
|
|||||||
// define the property
|
// define the property
|
||||||
void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
|
void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
|
||||||
const std::string& ShortDescription,
|
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
|
// get the property definition if present, otherwise nullptr
|
||||||
cmPropertyDefinition const* GetPropertyDefinition(
|
cmPropertyDefinition const* GetPropertyDefinition(
|
||||||
const std::string& name, cmProperty::ScopeType scope) const;
|
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:
|
private:
|
||||||
using key_type = std::pair<std::string, cmProperty::ScopeType>;
|
std::map<KeyType, cmPropertyDefinition> Map_;
|
||||||
std::map<key_type, cmPropertyDefinition> Map_;
|
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-2
@@ -327,10 +327,12 @@ cmStateSnapshot cmState::Reset()
|
|||||||
void cmState::DefineProperty(const std::string& name,
|
void cmState::DefineProperty(const std::string& name,
|
||||||
cmProperty::ScopeType scope,
|
cmProperty::ScopeType scope,
|
||||||
const std::string& ShortDescription,
|
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,
|
this->PropertyDefinitions.DefineProperty(name, scope, ShortDescription,
|
||||||
FullDescription, chained);
|
FullDescription, chained,
|
||||||
|
initializeFromVariable);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmPropertyDefinition const* cmState::GetPropertyDefinition(
|
cmPropertyDefinition const* cmState::GetPropertyDefinition(
|
||||||
|
|||||||
+7
-1
@@ -133,12 +133,18 @@ public:
|
|||||||
// Define a property
|
// Define a property
|
||||||
void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
|
void DefineProperty(const std::string& name, cmProperty::ScopeType scope,
|
||||||
const std::string& ShortDescription,
|
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
|
// get property definition
|
||||||
cmPropertyDefinition const* GetPropertyDefinition(
|
cmPropertyDefinition const* GetPropertyDefinition(
|
||||||
const std::string& name, cmProperty::ScopeType scope) const;
|
const std::string& name, cmProperty::ScopeType scope) const;
|
||||||
|
|
||||||
|
const cmPropertyDefinitionMap& GetPropertyDefinitions() const
|
||||||
|
{
|
||||||
|
return this->PropertyDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsPropertyChained(const std::string& name,
|
bool IsPropertyChained(const std::string& name,
|
||||||
cmProperty::ScopeType scope) const;
|
cmProperty::ScopeType scope) const;
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "cmMakefile.h"
|
#include "cmMakefile.h"
|
||||||
#include "cmMessageType.h"
|
#include "cmMessageType.h"
|
||||||
#include "cmProperty.h"
|
#include "cmProperty.h"
|
||||||
|
#include "cmPropertyDefinition.h"
|
||||||
#include "cmPropertyMap.h"
|
#include "cmPropertyMap.h"
|
||||||
#include "cmRange.h"
|
#include "cmRange.h"
|
||||||
#include "cmSourceFile.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;
|
cmTarget::cmTarget(cmTarget&&) noexcept = default;
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
include(RunCMake)
|
include(RunCMake)
|
||||||
|
|
||||||
run_cmake(define_property)
|
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)
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
+4
@@ -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\)$
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
define_property(TARGET PROPERTY PROP1
|
||||||
|
INITIALIZE_FROM_VARIABLE CMAKE_PROP1
|
||||||
|
)
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
+4
@@ -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\)$
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
define_property(TARGET PROPERTY PROP1
|
||||||
|
INITIALIZE_FROM_VARIABLE _CMAKE_PROP1
|
||||||
|
)
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
+5
@@ -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\)$
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
define_property(TARGET PROPERTY PROP1
|
||||||
|
INITIALIZE_FROM_VARIABLE PROP1
|
||||||
|
)
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
+5
@@ -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\)$
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
define_property(GLOBAL PROPERTY PROP1
|
||||||
|
INITIALIZE_FROM_VARIABLE Test_PROP1
|
||||||
|
)
|
||||||
+11
@@ -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 "!")
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
1
|
||||||
+5
@@ -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\)$
|
||||||
+3
@@ -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 "!")
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user