mirror of
https://github.com/Kitware/CMake.git
synced 2026-11-06 05:16:58 +00:00
Custom rule: enhance patterns management
This commit is contained in:
1 parent
ba258369af
commit
1259cd4fc8
22 files changed
+461
-231
No files matched your search
@@ -68,6 +68,10 @@ Generating Files
|
||||
The instantiation of the patterns are done in the context of the directory
|
||||
where the file set was created.
|
||||
|
||||
.. versionchanged:: 4.6
|
||||
The expansion of patterns is done recursively at generation time so the
|
||||
value of a pattern can refer any other pattern.
|
||||
|
||||
These patterns cannot be changed by the functions specified by the
|
||||
``CONFIGURATOR`` option.
|
||||
|
||||
@@ -202,7 +206,7 @@ Generating Files
|
||||
used to enrich the list of patterns. The expected value is a
|
||||
:ref:`semicolon-separated list <CMake Language Lists>` of items having
|
||||
the syntax ``PATTERN=VALUE`` or ``PATTERN=``. More precisely, each item
|
||||
must match the regular expression ``(^[A-Z][A-Z0-9_]+)=(.*)$``. Items
|
||||
must match the regular expression ``(^[A-Z][A-Z0-9_]*)=(.*)$``. Items
|
||||
which do not match this regular expression will be ignored.
|
||||
|
||||
``FOR_SOURCE``
|
||||
@@ -219,7 +223,7 @@ Generating Files
|
||||
used to enrich the list of patterns. The expected value is a
|
||||
:ref:`semicolon-separated list <CMake Language Lists>` of items having
|
||||
the syntax ``PATTERN=VALUE`` or ``PATTERN=``. More precisely, each item
|
||||
must match the regular expression ``(^[A-Z][A-Z0-9_]+)=(.*)$``. Items
|
||||
must match the regular expression ``(^[A-Z][A-Z0-9_]*)=(.*)$``. Items
|
||||
which do not match this regular expression will be ignored.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -8,15 +8,14 @@ Patterns specification for instantiating a rule.
|
||||
The ``RULE_PATTERNS`` property may be set to a
|
||||
:ref:`semicolon-separated list <CMake Language Lists>` of patterns using the
|
||||
syntax ``PATTERN=VALUE`` or ``PATTERN=``. More precisely, each item must match
|
||||
the regular expression ``(^[A-Z][A-Z0-9_]+)=(.*)$``.
|
||||
the regular expression ``(^[A-Z][A-Z0-9_]*)=(.*)$``.
|
||||
|
||||
CMake will automatically drop any patterns which do not match against this
|
||||
regular expression.
|
||||
|
||||
The list is ordered, so a pattern can use in its definition a previously
|
||||
defined pattern. In the following example,
|
||||
``OUTPUT_DIR=/some/path;OUTPUT_FILE=<OUTPUT_DIR>/my_file``, when the pattern
|
||||
``<OUTPUT_FILE>`` is expanded, the pattern ``<OUTPUT_DIR>`` is already known.
|
||||
.. versionchanged:: 4.6
|
||||
The expansion of patterns is done recursively at generation time so the value
|
||||
of a pattern can refer any other pattern.
|
||||
|
||||
Related properties:
|
||||
|
||||
|
||||
@@ -13,10 +13,9 @@ the regular expression ``(^[A-Z][A-Z0-9_]+)=(.*)$``.
|
||||
CMake will automatically drop any patterns which do not match against this
|
||||
regular expression.
|
||||
|
||||
The list is ordered, so a pattern can use in its definition a previously
|
||||
defined pattern. In the following example,
|
||||
``OUTPUT_DIR=/some/path;OUTPUT_FILE=<OUTPUT_DIR>/my_file``, when the pattern
|
||||
``<OUTPUT_FILE>`` is expanded, the pattern ``<OUTPUT_DIR>`` is already known.
|
||||
.. versionchanged:: 4.6
|
||||
The expansion of patterns is done recursively at generation time so the value
|
||||
of a pattern can refer any other pattern.
|
||||
|
||||
Related properties:
|
||||
|
||||
|
||||
@@ -163,6 +163,8 @@ add_library(
|
||||
cmCryptoHash.h
|
||||
cmCurl.cxx
|
||||
cmCurl.h
|
||||
cmRuleHelper.cxx
|
||||
cmRuleHelper.h
|
||||
cmRule.cxx
|
||||
cmRule.h
|
||||
cmCustomRule.cxx
|
||||
|
||||
+140
-127
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -23,12 +25,22 @@
|
||||
#include "cmList.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTarget.h"
|
||||
|
||||
namespace {
|
||||
class rule_pattern_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
rule_pattern_error(std::string const& msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<cm::string_view> ReservedPatterns{ "RULE"_s,
|
||||
"TARGET"_s,
|
||||
"FILE_SET"_s,
|
||||
@@ -47,101 +59,86 @@ std::vector<cm::string_view> ReservedPatterns{ "RULE"_s,
|
||||
"COMPILE_DEFINITIONS"_s };
|
||||
}
|
||||
|
||||
std::string cmGeneratorRule::RulePlaceholderExpander::ExpandVariable(
|
||||
std::string const& variable)
|
||||
{
|
||||
if (cm::contains(this->Values, variable)) {
|
||||
return this->Values[variable];
|
||||
}
|
||||
// If there is no variable defined, mark unresolved variable by '{' and '}'
|
||||
return cmStrCat('{', variable, '}');
|
||||
}
|
||||
|
||||
cmGeneratorRule::RulePlaceholderExpander::VariableMap const
|
||||
cmGeneratorRule::DefaultProperties{
|
||||
{ "INCLUDE_DIRECTORIES",
|
||||
"$<LIST:FILTER,$<FILE_SET_PROPERTY:<FILE_SET>,TARGET:<TARGET>,INCLUDE_"
|
||||
"DIRECTORIES>;$<SOURCE_PROPERTY:<SOURCE>,TARGET_DIRECTORY:<TARGET>,"
|
||||
"INCLUDE_DIRECTORIES>;$<RULE_PROPERTY:<RULE>,INCLUDE_DIRECTORIES>,"
|
||||
"EXCLUDE,^$>" },
|
||||
{ "COMPILE_OPTIONS",
|
||||
"$<LIST:FILTER,$<RULE_PROPERTY:<RULE>,COMPILE_OPTIONS>;$<SOURCE_"
|
||||
"PROPERTY:<SOURCE>,"
|
||||
"TARGET_DIRECTORY:<TARGET>,COMPILE_OPTIONS>;$<FILE_SET_PROPERTY:<FILE_"
|
||||
"SET>,TARGET:<TARGET>,COMPILE_OPTIONS>,EXCLUDE,^$>" },
|
||||
{ "COMPILE_DEFINITIONS",
|
||||
"$<LIST:FILTER,$<RULE_PROPERTY:<RULE>,COMPILE_DEFINITIONS>;$<SOURCE_"
|
||||
"PROPERTY:<"
|
||||
"SOURCE>,"
|
||||
"TARGET_DIRECTORY:<TARGET>,COMPILE_DEFINITIONS>;$<FILE_SET_PROPERTY:<"
|
||||
"FILE_SET>,TARGET:<TARGET>,COMPILE_DEFINITIONS>,EXCLUDE,^$>" }
|
||||
};
|
||||
cm::RulePatternSet const cmGeneratorRule::DefaultProperties{
|
||||
{ "INCLUDE_DIRECTORIES",
|
||||
"$<LIST:FILTER,$<FILE_SET_PROPERTY:<FILE_SET>,TARGET:<TARGET>,INCLUDE_"
|
||||
"DIRECTORIES>;$<SOURCE_PROPERTY:<SOURCE>,TARGET_DIRECTORY:<TARGET>,"
|
||||
"INCLUDE_DIRECTORIES>;$<RULE_PROPERTY:<RULE>,INCLUDE_DIRECTORIES>,"
|
||||
"EXCLUDE,^$>" },
|
||||
{ "COMPILE_OPTIONS",
|
||||
"$<LIST:FILTER,$<RULE_PROPERTY:<RULE>,COMPILE_OPTIONS>;$<SOURCE_"
|
||||
"PROPERTY:<SOURCE>,"
|
||||
"TARGET_DIRECTORY:<TARGET>,COMPILE_OPTIONS>;$<FILE_SET_PROPERTY:<FILE_"
|
||||
"SET>,TARGET:<TARGET>,COMPILE_OPTIONS>,EXCLUDE,^$>" },
|
||||
{ "COMPILE_DEFINITIONS",
|
||||
"$<LIST:FILTER,$<RULE_PROPERTY:<RULE>,COMPILE_DEFINITIONS>;$<SOURCE_"
|
||||
"PROPERTY:<"
|
||||
"SOURCE>,"
|
||||
"TARGET_DIRECTORY:<TARGET>,COMPILE_DEFINITIONS>;$<FILE_SET_PROPERTY:<"
|
||||
"FILE_SET>,TARGET:<TARGET>,COMPILE_DEFINITIONS>,EXCLUDE,^$>" }
|
||||
};
|
||||
|
||||
cmGeneratorRule::cmGeneratorRule(cmRule const* rule, cmTarget const* target,
|
||||
cmFileSet const* fileSet,
|
||||
cmFileSet const* outputFileSet,
|
||||
cmSourceFile const* source,
|
||||
cmRule::PatternSet const& patterns)
|
||||
cm::RulePatternSet const& patterns)
|
||||
: Rule(rule)
|
||||
, Target(target)
|
||||
, FileSet(fileSet)
|
||||
, OutputFileSet(outputFileSet)
|
||||
, Source(source)
|
||||
, Makefile(*fileSet->GetMakefile())
|
||||
, RuleExpander(this->GetMakefile(), this->Rule->GetName(), this->Patterns)
|
||||
{
|
||||
this->Name = cmStrCat(rule->GetName(), '_',
|
||||
std::hash<std::string>{}(cmStrCat(
|
||||
rule->GetName(), '-', target->GetName(), '-',
|
||||
fileSet->GetName(), '-', source->GetFullPath())));
|
||||
|
||||
auto& values = this->RuleExpander.Values;
|
||||
|
||||
cmCMakePath file = cmCMakePath{ this->Source->GetFullPath() }.Normal();
|
||||
cmCMakePath sourceDir = file.IsAbsolute()
|
||||
? file.GetParentPath()
|
||||
: this->GetMakefile().GetCurrentSourceDirectory();
|
||||
|
||||
/* clang-format off */
|
||||
values.insert({ "RULE", this->GetName() });
|
||||
values.insert({ "TARGET", this->Target->GetName() });
|
||||
values.insert({ "FILE_SET", this->FileSet->GetName() });
|
||||
values.insert({ "SOURCE_DIR", this->GetMakefile().GetHomeDirectory() });
|
||||
values.insert({ "BINARY_DIR", this->GetMakefile().GetHomeOutputDirectory() });
|
||||
values.insert({ "CURRENT_SOURCE_DIR", this->GetMakefile().GetCurrentSourceDirectory() });
|
||||
values.insert({ "CURRENT_BINARY_DIR", this->GetMakefile().GetCurrentBinaryDirectory() });
|
||||
values.insert({ "OUTPUT_CURRENT_SOURCE_DIR", outputFileSet->GetMakefile()->GetCurrentSourceDirectory() });
|
||||
values.insert({ "OUTPUT_CURRENT_BINARY_DIR", outputFileSet->GetMakefile()->GetCurrentBinaryDirectory() });
|
||||
values.insert({ "SOURCE", file.GenericString() });
|
||||
values.insert({ "INPUT_DIR", file.GetParentPath().GenericString() });
|
||||
values.insert({ "FILE_NAME", file.GetFileName().GenericString() });
|
||||
values.insert({ "BASE_NAME", file.GetFileName().RemoveWideExtension().GenericString() });
|
||||
this->Patterns.insert({ "RULE", this->GetName() });
|
||||
this->Patterns.insert({ "TARGET", this->Target->GetName() });
|
||||
this->Patterns.insert({ "FILE_SET", this->FileSet->GetName() });
|
||||
this->Patterns.insert({ "SOURCE_DIR", this->GetMakefile().GetHomeDirectory() });
|
||||
this->Patterns.insert({ "BINARY_DIR", this->GetMakefile().GetHomeOutputDirectory() });
|
||||
this->Patterns.insert({ "CURRENT_SOURCE_DIR", this->GetMakefile().GetCurrentSourceDirectory() });
|
||||
this->Patterns.insert({ "CURRENT_BINARY_DIR", this->GetMakefile().GetCurrentBinaryDirectory() });
|
||||
this->Patterns.insert({ "OUTPUT_CURRENT_SOURCE_DIR", outputFileSet->GetMakefile()->GetCurrentSourceDirectory() });
|
||||
this->Patterns.insert({ "OUTPUT_CURRENT_BINARY_DIR", outputFileSet->GetMakefile()->GetCurrentBinaryDirectory() });
|
||||
this->Patterns.insert({ "SOURCE", file.GenericString() });
|
||||
this->Patterns.insert({ "INPUT_DIR", file.GetParentPath().GenericString() });
|
||||
this->Patterns.insert({ "FILE_NAME", file.GetFileName().GenericString() });
|
||||
this->Patterns.insert({ "BASE_NAME", file.GetFileName().RemoveWideExtension().GenericString() });
|
||||
/* clang-format on */
|
||||
|
||||
// instantiate default properties pattern
|
||||
for (auto const& item : DefaultProperties) {
|
||||
values.insert(
|
||||
this->Patterns.insert(
|
||||
{ item.first, this->RuleExpander.ExpandVariables(item.second) });
|
||||
}
|
||||
|
||||
this->UpdateRuleExpander(patterns);
|
||||
}
|
||||
|
||||
void cmGeneratorRule::UpdateRuleExpander(cmRule::PatternSet const& patterns)
|
||||
void cmGeneratorRule::UpdateRuleExpander(cm::RulePatternSet const& patterns)
|
||||
{
|
||||
if (patterns.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& values = this->RuleExpander.Values;
|
||||
|
||||
for (cmRule::Pattern const& pattern : patterns) {
|
||||
if (cm::contains(ReservedPatterns, pattern.Name)) {
|
||||
for (auto const& pattern : patterns) {
|
||||
if (cm::contains(ReservedPatterns, pattern.first)) {
|
||||
// overwriting a reserved pattern is not allowed
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string data{ pattern.Value };
|
||||
values[pattern.Name] = this->RuleExpander.ExpandVariables(data);
|
||||
this->Patterns[pattern.first] = pattern.second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +179,15 @@ cmValue cmGeneratorRule::GetProperty(std::string const& property) const
|
||||
std::unique_ptr<cmCustomCommand> cmGeneratorRule::CreateCustomCommand() const
|
||||
{
|
||||
auto expandVariables = [this](std::string const& item) -> std::string {
|
||||
return this->RuleExpander.ExpandVariables(item);
|
||||
auto result = this->RuleExpander.ExpandPatterns(item);
|
||||
if (this->RuleExpander.InError) {
|
||||
throw rule_pattern_error{ cmStrCat(
|
||||
"Pattern expression\n ", item, "\nfrom rule \"",
|
||||
this->GetRule()->GetName(), "\", used by the fileset \"",
|
||||
this->FileSet->GetName(), "\" of the target \"",
|
||||
this->Target->GetName(), "\", did not expand correctly.") };
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
auto expandVector =
|
||||
@@ -225,87 +230,95 @@ std::unique_ptr<cmCustomCommand> cmGeneratorRule::CreateCustomCommand() const
|
||||
return result;
|
||||
};
|
||||
|
||||
auto cc = cm::make_unique<cmCustomCommand>();
|
||||
try {
|
||||
auto cc = cm::make_unique<cmCustomCommand>();
|
||||
|
||||
cmCustomCommandLines commandLines;
|
||||
for (cmRule::CustomCommand const& line : this->Rule->GetCommands()) {
|
||||
cmCustomCommandLine command;
|
||||
command.reserve(line.size());
|
||||
std::transform(line.begin(), line.end(), std::back_inserter(command),
|
||||
expandVariables);
|
||||
commandLines.push_back(command);
|
||||
cmCustomCommandLines commandLines;
|
||||
for (cmRule::CustomCommand const& line : this->Rule->GetCommands()) {
|
||||
cmCustomCommandLine command;
|
||||
command.reserve(line.size());
|
||||
std::transform(line.begin(), line.end(), std::back_inserter(command),
|
||||
expandVariables);
|
||||
commandLines.push_back(command);
|
||||
}
|
||||
cc->SetCommandLines(std::move(commandLines));
|
||||
|
||||
cc->SetOutputs(expandPaths(this->GetMakefile().GetCurrentBinaryDirectory(),
|
||||
this->Rule->GetOutputs()));
|
||||
|
||||
if (!this->Rule->GetByproducts().empty()) {
|
||||
cc->SetByproducts(expandVector(this->Rule->GetByproducts()));
|
||||
}
|
||||
|
||||
if (!this->Rule->GetDepfile().empty()) {
|
||||
// store normalized path as property
|
||||
this->Properties.SetProperty(
|
||||
"DEPFILE",
|
||||
expandPath(this->GetMakefile().GetCurrentBinaryDirectory(),
|
||||
this->Rule->GetDepfile()));
|
||||
cc->SetDepfile(expandVariables(this->Rule->GetDepfile()));
|
||||
}
|
||||
std::vector<std::string> depends{ 1, this->Source->GetFullPath() };
|
||||
if (!this->Rule->GetDepends().empty()) {
|
||||
depends.insert(depends.end(), this->Rule->GetDepends().begin(),
|
||||
this->Rule->GetDepends().end());
|
||||
}
|
||||
cc->SetDepends(expandVector(depends));
|
||||
if (cmValue deps_explicit =
|
||||
this->Rule->GetProperty("DEPENDS_EXPLICIT_ONLY")) {
|
||||
cc->SetDependsExplicitOnly(deps_explicit.IsOn());
|
||||
} else {
|
||||
cc->SetDependsExplicitOnly(this->GetMakefile().IsOn(
|
||||
"CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY"));
|
||||
}
|
||||
|
||||
if (cmValue wd = this->Rule->GetProperty("WORKING_DIRECTORY")) {
|
||||
// store normalized path as property
|
||||
this->Properties.SetProperty(
|
||||
"WORKING_DIRECTORY",
|
||||
expandPath(this->GetMakefile().GetCurrentBinaryDirectory(), *wd));
|
||||
cc->SetWorkingDirectory(expandVariables(*wd));
|
||||
}
|
||||
|
||||
if (this->Rule->GetProperty("USES_TERMINAL").IsOn() &&
|
||||
!this->Rule->GetProperty("JOB_POOL_COMPILE")->empty()) {
|
||||
this->GetMakefile().IssueDiagnostic(
|
||||
cmDiagnostics::CMD_AUTHOR,
|
||||
cmStrCat("RULE \"", this->GetName(), "\": JOB_POOL \"",
|
||||
expandVariables(this->Rule->GetProperty("JOB_POOL_COMPILE")),
|
||||
"\" is shadowed by USES_TERMINAL."));
|
||||
}
|
||||
if (!this->Rule->GetProperty("JOB_POOL_COMPILE")->empty()) {
|
||||
cc->SetJobPool(
|
||||
expandVariables(*this->Rule->GetProperty("JOB_POOL_COMPILE")));
|
||||
} else if (this->Rule->GetProperty("USES_TERMINAL").IsOn()) {
|
||||
cc->SetUsesTerminal(true);
|
||||
}
|
||||
|
||||
cc->SetJobserverAware(this->Rule->GetProperty("JOB_SERVER_AWARE").IsOn());
|
||||
|
||||
cc->SetEscapeOldStyle(!this->Rule->GetProperty("VERBATIM").IsOn());
|
||||
cc->SetCommandExpandLists(
|
||||
this->Rule->GetProperty("COMMAND_EXPAND_LISTS").IsOn());
|
||||
|
||||
if (cmValue comment = this->Rule->GetProperty("COMMENT")) {
|
||||
cc->SetComment(expandVariables(*comment));
|
||||
}
|
||||
|
||||
return cc;
|
||||
} catch (rule_pattern_error const& error) {
|
||||
this->GetMakefile().IssueMessage(MessageType::FATAL_ERROR, error.what());
|
||||
return nullptr;
|
||||
}
|
||||
cc->SetCommandLines(std::move(commandLines));
|
||||
|
||||
cc->SetOutputs(expandPaths(this->GetMakefile().GetCurrentBinaryDirectory(),
|
||||
this->Rule->GetOutputs()));
|
||||
|
||||
if (!this->Rule->GetByproducts().empty()) {
|
||||
cc->SetByproducts(expandVector(this->Rule->GetByproducts()));
|
||||
}
|
||||
|
||||
if (!this->Rule->GetDepfile().empty()) {
|
||||
// store normalized path as property
|
||||
this->Properties.SetProperty(
|
||||
"DEPFILE",
|
||||
expandPath(this->GetMakefile().GetCurrentBinaryDirectory(),
|
||||
this->Rule->GetDepfile()));
|
||||
cc->SetDepfile(expandVariables(this->Rule->GetDepfile()));
|
||||
}
|
||||
std::vector<std::string> depends{ 1, this->Source->GetFullPath() };
|
||||
if (!this->Rule->GetDepends().empty()) {
|
||||
depends.insert(depends.end(), this->Rule->GetDepends().begin(),
|
||||
this->Rule->GetDepends().end());
|
||||
}
|
||||
cc->SetDepends(expandVector(depends));
|
||||
if (cmValue deps_explicit =
|
||||
this->Rule->GetProperty("DEPENDS_EXPLICIT_ONLY")) {
|
||||
cc->SetDependsExplicitOnly(deps_explicit.IsOn());
|
||||
} else {
|
||||
cc->SetDependsExplicitOnly(this->GetMakefile().IsOn(
|
||||
"CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY"));
|
||||
}
|
||||
|
||||
if (cmValue wd = this->Rule->GetProperty("WORKING_DIRECTORY")) {
|
||||
// store normalized path as property
|
||||
this->Properties.SetProperty(
|
||||
"WORKING_DIRECTORY",
|
||||
expandPath(this->GetMakefile().GetCurrentBinaryDirectory(), *wd));
|
||||
cc->SetWorkingDirectory(expandVariables(*wd));
|
||||
}
|
||||
|
||||
if (this->Rule->GetProperty("USES_TERMINAL").IsOn() &&
|
||||
!this->Rule->GetProperty("JOB_POOL_COMPILE")->empty()) {
|
||||
this->GetMakefile().IssueDiagnostic(
|
||||
cmDiagnostics::CMD_AUTHOR,
|
||||
cmStrCat("RULE \"", this->GetName(), "\": JOB_POOL \"",
|
||||
expandVariables(this->Rule->GetProperty("JOB_POOL_COMPILE")),
|
||||
"\" is shadowed by USES_TERMINAL."));
|
||||
}
|
||||
if (!this->Rule->GetProperty("JOB_POOL_COMPILE")->empty()) {
|
||||
cc->SetJobPool(
|
||||
expandVariables(*this->Rule->GetProperty("JOB_POOL_COMPILE")));
|
||||
} else if (this->Rule->GetProperty("USES_TERMINAL").IsOn()) {
|
||||
cc->SetUsesTerminal(true);
|
||||
}
|
||||
|
||||
cc->SetJobserverAware(this->Rule->GetProperty("JOB_SERVER_AWARE").IsOn());
|
||||
|
||||
cc->SetEscapeOldStyle(!this->Rule->GetProperty("VERBATIM").IsOn());
|
||||
cc->SetCommandExpandLists(
|
||||
this->Rule->GetProperty("COMMAND_EXPAND_LISTS").IsOn());
|
||||
|
||||
if (cmValue comment = this->Rule->GetProperty("COMMENT")) {
|
||||
cc->SetComment(expandVariables(*comment));
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
std::unique_ptr<cmCustomCommand> cmGeneratorRule::Generate(
|
||||
cmFileSet* outFileSet) const
|
||||
{
|
||||
auto cc = this->CreateCustomCommand();
|
||||
if (!cc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// populate file set with outputs from custom command
|
||||
for (auto const& output : cc->GetOutputs()) {
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cmPlaceholderExpander.h"
|
||||
#include "cmPropertyMap.h"
|
||||
#include "cmRule.h"
|
||||
#include "cmRuleHelper.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
class cmMakefile;
|
||||
@@ -25,7 +24,7 @@ public:
|
||||
cmGeneratorRule(cmRule const* rule, cmTarget const* target,
|
||||
cmFileSet const* fileSet, cmFileSet const* outputFileSet,
|
||||
cmSourceFile const* source,
|
||||
cmRule::PatternSet const& patterns);
|
||||
cm::RulePatternSet const& patterns);
|
||||
|
||||
cmGeneratorRule(cmGeneratorRule const&) = delete;
|
||||
cmGeneratorRule& operator=(cmGeneratorRule const&) = delete;
|
||||
@@ -45,7 +44,7 @@ public:
|
||||
std::unique_ptr<cmCustomCommand> Generate(cmFileSet* outFileSet) const;
|
||||
|
||||
private:
|
||||
void UpdateRuleExpander(cmRule::PatternSet const& patterns);
|
||||
void UpdateRuleExpander(cm::RulePatternSet const& patterns);
|
||||
|
||||
std::unique_ptr<cmCustomCommand> CreateCustomCommand() const;
|
||||
|
||||
@@ -58,24 +57,8 @@ private:
|
||||
cmMakefile& Makefile;
|
||||
mutable cmPropertyMap Properties;
|
||||
|
||||
class RulePlaceholderExpander : public cmPlaceholderExpander
|
||||
{
|
||||
public:
|
||||
using VariableMap = std::unordered_map<std::string, std::string>;
|
||||
VariableMap Values;
|
||||
static cm::RulePatternSet const DefaultProperties;
|
||||
|
||||
std::string ExpandVariables(std::string const& string)
|
||||
{
|
||||
std::string value{ string };
|
||||
return cmPlaceholderExpander::ExpandVariables(
|
||||
value, cmPlaceholderExpander::HandleGenex::Yes);
|
||||
}
|
||||
|
||||
private:
|
||||
std::string ExpandVariable(std::string const& variable) override;
|
||||
};
|
||||
|
||||
static RulePlaceholderExpander::VariableMap const DefaultProperties;
|
||||
|
||||
mutable RulePlaceholderExpander RuleExpander;
|
||||
cm::RulePatternSet Patterns;
|
||||
mutable cm::RulePatternPlaceholderExpander RuleExpander;
|
||||
};
|
||||
@@ -64,6 +64,7 @@
|
||||
#include "cmPolicies.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmRule.h"
|
||||
#include "cmRuleHelper.h"
|
||||
#include "cmSbomArguments.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmState.h"
|
||||
@@ -3883,7 +3884,7 @@ void cmGlobalGenerator::ConfigureRules()
|
||||
continue;
|
||||
}
|
||||
|
||||
cmRule::PatternSet fileSetPatterns;
|
||||
cm::RulePatternSet fileSetPatterns;
|
||||
if (!rule->Instantiate(&target, fileSet, outFileSet,
|
||||
fileSetPatterns)) {
|
||||
continue;
|
||||
@@ -3895,7 +3896,7 @@ void cmGlobalGenerator::ConfigureRules()
|
||||
cmSourceFile* source = mf->GetOrCreateSource(file);
|
||||
source->ResolveFullPath();
|
||||
|
||||
cmRule::PatternSet sourcePatterns{ fileSetPatterns };
|
||||
cm::RulePatternSet sourcePatterns{ fileSetPatterns };
|
||||
if (!rule->Instantiate(&target, fileSet, outFileSet, source,
|
||||
sourcePatterns)) {
|
||||
continue;
|
||||
@@ -3907,9 +3908,11 @@ void cmGlobalGenerator::ConfigureRules()
|
||||
auto genRule = cm::make_unique<cmGeneratorRule>(
|
||||
rule, &target, fileSet, outFileSet, source, sourcePatterns);
|
||||
auto cc = genRule->Generate(outFileSet);
|
||||
lg.AddGeneratorRule(std::move(genRule));
|
||||
detail::AddCustomCommandToOutput(
|
||||
lg, cmCommandOrigin::Generator, std::move(cc), false);
|
||||
if (cc) {
|
||||
lg.AddGeneratorRule(std::move(genRule));
|
||||
detail::AddCustomCommandToOutput(
|
||||
lg, cmCommandOrigin::Generator, std::move(cc), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+37
-49
@@ -22,8 +22,8 @@
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmPlaceholderExpander.h"
|
||||
#include "cmRange.h"
|
||||
#include "cmRuleHelper.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmTarget.h"
|
||||
@@ -153,26 +153,6 @@ bool IsSettableProperty(cm::string_view prop, cmRule const* rule)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class FileSetNamePlaceholderExpander : public cmPlaceholderExpander
|
||||
{
|
||||
public:
|
||||
using VariableMap = std::unordered_map<std::string, std::string>;
|
||||
VariableMap Values;
|
||||
|
||||
bool InError = false;
|
||||
|
||||
private:
|
||||
std::string ExpandVariable(std::string const& variable) override
|
||||
{
|
||||
if (cm::contains(this->Values, variable)) {
|
||||
return this->Values[variable];
|
||||
}
|
||||
this->InError = true;
|
||||
// If there is no variable defined, mark unresolved variable by '<' and '>'
|
||||
return cmStrCat('<', variable, '>');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cmRule::cmRule(cmMakefile& makefile, std::string name, cm::RuleScope scope)
|
||||
@@ -242,27 +222,31 @@ cmFileSet* cmRule::GetOutputFileSet(cmTarget* target,
|
||||
cmFileSet const* fileSet) const
|
||||
{
|
||||
cmList outputFileSet{ this->GetProperty(std::string{ OUTPUT_FILE_SET }) };
|
||||
FileSetNamePlaceholderExpander expander;
|
||||
expander.Values["RULE"] = this->GetName();
|
||||
expander.Values["TARGET"] = target->GetName();
|
||||
expander.Values["FILE_SET"] = fileSet->GetName();
|
||||
cm::RulePatternSet patterns{
|
||||
{ "RULE", this->GetName() },
|
||||
{ "TARGET", target->GetName() },
|
||||
{ "FILE_SET", fileSet->GetName() },
|
||||
};
|
||||
|
||||
std::string fsName{ outputFileSet[0] };
|
||||
expander.ExpandVariables(fsName);
|
||||
cm::RulePatternPlaceholderExpander expander{ this->GetMakefile(),
|
||||
this->GetName(), patterns };
|
||||
|
||||
std::string const& fsName = outputFileSet[0];
|
||||
std::string outputName = expander.ExpandPatterns(fsName);
|
||||
if (expander.InError) {
|
||||
this->GetMakefile().IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Output File Set name, for rule \"", this->GetName(),
|
||||
"\", did not expand correctly:\n \"", fsName, "\"."));
|
||||
cmStrCat("Output File Set name, for the rule \"", this->GetName(),
|
||||
"\", did not expand correctly:\n \"", outputName, "\"."));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto result = target->GetOrCreateFileSet(fsName, outputFileSet[1],
|
||||
auto result = target->GetOrCreateFileSet(outputName, outputFileSet[1],
|
||||
fileSet->GetVisibility());
|
||||
if (!result.second && result.first->GetType() != outputFileSet[1]) {
|
||||
this->GetMakefile().IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The output file set \"", fsName, "\", for the target \"",
|
||||
cmStrCat("The output file set \"", outputName, "\", for the target \"",
|
||||
target->GetName(), "\", has the type \"",
|
||||
result.first->GetType(), "\" instead of \"", outputFileSet[1],
|
||||
"\", as specified by the rule \"", this->GetName(), "\"."));
|
||||
@@ -272,16 +256,23 @@ cmFileSet* cmRule::GetOutputFileSet(cmTarget* target,
|
||||
if (result.first->GetDirectoryEntries().empty()) {
|
||||
if (cmValue baseDirs =
|
||||
this->GetProperty(std::string{ OUTPUT_FILE_SET_BASE_DIRS })) {
|
||||
expander.Values["CURRENT_SOURCE_DIR"] =
|
||||
patterns["CURRENT_SOURCE_DIR"] =
|
||||
fileSet->GetMakefile()->GetCurrentSourceDirectory();
|
||||
expander.Values["CURRENT_BINARY_DIR"] =
|
||||
patterns["CURRENT_BINARY_DIR"] =
|
||||
fileSet->GetMakefile()->GetCurrentBinaryDirectory();
|
||||
expander.Values["OUTPUT_CURRENT_SOURCE_DIR"] =
|
||||
patterns["OUTPUT_CURRENT_SOURCE_DIR"] =
|
||||
result.first->GetMakefile()->GetCurrentSourceDirectory();
|
||||
expander.Values["OUTPUT_CURRENT_BINARY_DIR"] =
|
||||
patterns["OUTPUT_CURRENT_BINARY_DIR"] =
|
||||
result.first->GetMakefile()->GetCurrentBinaryDirectory();
|
||||
std::string dirs{ baseDirs };
|
||||
expander.ExpandVariables(dirs);
|
||||
|
||||
std::string dirs = expander.ExpandPatterns(*baseDirs);
|
||||
if (expander.InError) {
|
||||
this->GetMakefile().IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("Base directories, for the rule \"", this->GetName(),
|
||||
"\", did not expand correctly."));
|
||||
return nullptr;
|
||||
}
|
||||
result.first->AddDirectoryEntry(BT<std::string>{ dirs });
|
||||
} else {
|
||||
// Add default base directory if none are specified
|
||||
@@ -520,33 +511,30 @@ void cmRule::CheckProperty(std::string const& prop, cmMakefile& context) const
|
||||
}
|
||||
|
||||
namespace {
|
||||
cmsys::RegularExpression PatternRegex{ "(^[A-Z][A-Z0-9_]+)=(.*)$" };
|
||||
cmsys::RegularExpression PatternRegex{ "(^[A-Z][A-Z0-9_]*)=(.*)$" };
|
||||
|
||||
void UpdatePatterns(cmRule::PatternSet& patterns, cmList const& newPatterns)
|
||||
void UpdatePatterns(cm::RulePatternSet& patterns, cmList const& newPatterns)
|
||||
{
|
||||
for (auto const& pattern : newPatterns) {
|
||||
if (PatternRegex.find(pattern)) {
|
||||
auto it = std::find_if(patterns.begin(), patterns.end(),
|
||||
[](cmRule::Pattern const& item) {
|
||||
return item.Name == PatternRegex.match(1);
|
||||
});
|
||||
if (it == patterns.end()) {
|
||||
patterns.emplace_back(PatternRegex.match(1), PatternRegex.match(2));
|
||||
if (cm::contains(patterns, PatternRegex.match(1))) {
|
||||
patterns[PatternRegex.match(1)] = PatternRegex.match(2);
|
||||
} else {
|
||||
it->Value = PatternRegex.match(2);
|
||||
patterns.emplace(PatternRegex.match(1), PatternRegex.match(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ConfigureRule(cmRule::ConfiguratorSet const& configurators,
|
||||
cmMakefile* mf, cmRule::PatternSet& patterns,
|
||||
cmMakefile* mf, cm::RulePatternSet& patterns,
|
||||
std::string const& rule, std::string const& target,
|
||||
std::string const& fileSet,
|
||||
std::string const& outputFileSet,
|
||||
std::string const& source = {})
|
||||
{
|
||||
cm::string_view patternsVariable{ "_CMAKE_RULE_PATTERNS"_s };
|
||||
cm::RulePatternPlaceholderExpander expander{ *mf, rule, patterns };
|
||||
|
||||
for (auto const& item : configurators) {
|
||||
// The validator command will be executed in an isolated scope.
|
||||
@@ -586,7 +574,7 @@ bool ConfigureRule(cmRule::ConfiguratorSet const& configurators,
|
||||
|
||||
bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
||||
cmFileSet const* outputFileSet,
|
||||
PatternSet& patterns) const
|
||||
cm::RulePatternSet& patterns) const
|
||||
{
|
||||
this->SwitchMode();
|
||||
|
||||
@@ -608,7 +596,7 @@ bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
||||
|
||||
bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
||||
cmFileSet const* outputFileSet, cmSourceFile* source,
|
||||
PatternSet& patterns) const
|
||||
cm::RulePatternSet& patterns) const
|
||||
{
|
||||
// First, take patterns from <RULE>_PATTERNS source file property, if any
|
||||
if (cmValue sfPatterns =
|
||||
|
||||
+4
-14
@@ -14,6 +14,7 @@
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmListFileCache.h"
|
||||
#include "cmPropertyMap.h"
|
||||
#include "cmRuleHelper.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
class cmMakefile;
|
||||
@@ -127,23 +128,12 @@ public:
|
||||
|
||||
bool InGeneration() const { return this->Generation; }
|
||||
|
||||
struct Pattern
|
||||
{
|
||||
Pattern(std::string name, std::string value)
|
||||
: Name(std::move(name))
|
||||
, Value(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
std::string Name;
|
||||
std::string Value;
|
||||
};
|
||||
using PatternSet = std::vector<Pattern>;
|
||||
bool Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
||||
cmFileSet const* outputFileSet, PatternSet& patterns) const;
|
||||
cmFileSet const* outputFileSet,
|
||||
cm::RulePatternSet& patterns) const;
|
||||
bool Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
||||
cmFileSet const* outputFileSet, cmSourceFile* source,
|
||||
PatternSet& patterns) const;
|
||||
cm::RulePatternSet& patterns) const;
|
||||
|
||||
protected:
|
||||
cmRule(cmMakefile& makefile, std::string name, cm::RuleScope scope);
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmRuleHelper.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <cmext/algorithm>
|
||||
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessageType.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
|
||||
namespace cm {
|
||||
class RulePatternDAGChecker
|
||||
{
|
||||
public:
|
||||
RulePatternDAGChecker(std::string pattern, RulePatternDAGChecker* parent)
|
||||
: Parent(parent)
|
||||
, Top(parent ? parent->Top : this)
|
||||
, Pattern(std::move(pattern))
|
||||
{
|
||||
this->CheckResult = this->CheckGraph();
|
||||
}
|
||||
|
||||
enum Result
|
||||
{
|
||||
DAG,
|
||||
SELF_REFERENCE,
|
||||
CYCLIC_REFERENCE
|
||||
};
|
||||
|
||||
Result Check() const { return this->CheckResult; }
|
||||
|
||||
void ReportError(cmMakefile& makefile, std ::string const& rule,
|
||||
std::string const& expression)
|
||||
{
|
||||
if (this->CheckResult == DAG) {
|
||||
return;
|
||||
}
|
||||
|
||||
RulePatternDAGChecker const* parent = this->Parent;
|
||||
|
||||
if (parent && !parent->Parent) {
|
||||
makefile.IssueMessage(MessageType::FATAL_ERROR,
|
||||
cmStrCat("Error evaluating the pattern \"",
|
||||
this->Pattern,
|
||||
"\" in the expression:\n"
|
||||
" ",
|
||||
expression,
|
||||
"\n"
|
||||
"Self reference on rule \"",
|
||||
rule, "\".\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
makefile.IssueMessage(MessageType::FATAL_ERROR,
|
||||
cmStrCat("Error evaluating the pattern \"",
|
||||
this->Pattern,
|
||||
"\" in the expression:\n"
|
||||
" ",
|
||||
expression,
|
||||
"\n"
|
||||
"Dependency loop found."));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Result CheckGraph() const
|
||||
{
|
||||
RulePatternDAGChecker const* parent = this->Parent;
|
||||
while (parent) {
|
||||
if (this->Pattern == parent->Pattern) {
|
||||
return (parent == this->Parent) ? SELF_REFERENCE : CYCLIC_REFERENCE;
|
||||
}
|
||||
parent = parent->Parent;
|
||||
}
|
||||
return DAG;
|
||||
}
|
||||
|
||||
RulePatternDAGChecker const* const Parent;
|
||||
RulePatternDAGChecker const* const Top;
|
||||
std::string const Pattern;
|
||||
Result CheckResult;
|
||||
};
|
||||
|
||||
std::string RulePatternPlaceholderExpander::ExpandVariables(
|
||||
std::string const& string)
|
||||
{
|
||||
std::string value{ string };
|
||||
return cmPlaceholderExpander::ExpandVariables(
|
||||
value, cmPlaceholderExpander::HandleGenex::Yes);
|
||||
}
|
||||
|
||||
std::string RulePatternPlaceholderExpander::ExpandVariable(
|
||||
std::string const& variable)
|
||||
{
|
||||
if (cm::contains(this->Patterns, variable)) {
|
||||
RulePatternDAGChecker dagChecker{
|
||||
variable, this->DAGStack.empty() ? nullptr : this->DAGStack.top()
|
||||
};
|
||||
|
||||
switch (dagChecker.Check()) {
|
||||
case RulePatternDAGChecker::SELF_REFERENCE:
|
||||
case RulePatternDAGChecker::CYCLIC_REFERENCE: {
|
||||
dagChecker.ReportError(this->Makefile, this->Rule, this->Expression);
|
||||
this->InError = true;
|
||||
return cmStrCat('<', variable, '>');
|
||||
}
|
||||
case RulePatternDAGChecker::DAG:
|
||||
break;
|
||||
}
|
||||
|
||||
this->DAGStack.push(&dagChecker);
|
||||
auto result = this->ExpandVariables(this->Patterns.at(variable));
|
||||
this->DAGStack.pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
this->InError = true;
|
||||
this->Makefile.IssueMessage(
|
||||
MessageType::FATAL_ERROR,
|
||||
cmStrCat("The pattern \"", variable, "\" is not defined."));
|
||||
// If there is no variable defined, mark unresolved variable by '<' and
|
||||
// '>'
|
||||
return cmStrCat('<', variable, '>');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
#pragma once
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "cmPlaceholderExpander.h"
|
||||
|
||||
class cmMakefile;
|
||||
|
||||
namespace cm {
|
||||
using RulePatternSet = std::unordered_map<std::string, std::string>;
|
||||
|
||||
class RulePatternDAGChecker;
|
||||
|
||||
class RulePatternPlaceholderExpander : public cmPlaceholderExpander
|
||||
{
|
||||
public:
|
||||
RulePatternPlaceholderExpander(cmMakefile& makefile, std::string const& rule,
|
||||
RulePatternSet const& patterns)
|
||||
: Makefile(makefile)
|
||||
, Rule(rule)
|
||||
, Patterns(patterns)
|
||||
{
|
||||
}
|
||||
|
||||
std::string ExpandPatterns(std::string const& string)
|
||||
{
|
||||
this->Expression = string;
|
||||
this->InError = false;
|
||||
return this->ExpandVariables(string);
|
||||
}
|
||||
|
||||
std::string ExpandVariables(std::string const& string);
|
||||
|
||||
bool InError = false;
|
||||
|
||||
private:
|
||||
cmMakefile& Makefile;
|
||||
std::string const& Rule;
|
||||
std::string Expression;
|
||||
RulePatternSet const& Patterns;
|
||||
std::stack<RulePatternDAGChecker*> DAGStack;
|
||||
|
||||
std::string ExpandVariable(std::string const& variable) override;
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
CMake Error in CMakeLists\.txt:
|
||||
Output File Set name, for rule "foo", did not expand correctly:
|
||||
The pattern "PATTERN" is not defined.
|
||||
|
||||
|
||||
CMake Error in CMakeLists\.txt:
|
||||
Output File Set name, for the rule "foo", did not expand correctly:
|
||||
|
||||
"bad_<PATTERN>_foo_bar_fs"
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,15 @@
|
||||
CMake Error in CMakeLists.txt:
|
||||
Error evaluating the pattern "OUTPUT_FILE" in the expression:
|
||||
|
||||
<OUTPUT_FILE>
|
||||
|
||||
Dependency loop found.
|
||||
|
||||
|
||||
CMake Error in CMakeLists.txt:
|
||||
Pattern expression
|
||||
|
||||
<OUTPUT_FILE>
|
||||
|
||||
from rule "simple", used by the fileset "fs" of the target "foo", did not
|
||||
expand correctly.
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_custom_rule(simple OUTPUT <OUTPUT_FILE>
|
||||
COMMAND cmd)
|
||||
|
||||
add_library(foo STATIC)
|
||||
|
||||
target_sources(foo PRIVATE FILE_SET fs TYPE simple FILES file.i)
|
||||
set_property(FILE_SET fs TARGET foo PROPERTY RULE_PATTERNS "OUTPUT_FILE=<OUTPUT2>;OUTPUT2=<OUTPUT_FILE>")
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,16 @@
|
||||
CMake Error in CMakeLists.txt:
|
||||
Error evaluating the pattern "OUTPUT_FILE" in the expression:
|
||||
|
||||
<OUTPUT_FILE>
|
||||
|
||||
Self reference on rule "simple".
|
||||
|
||||
|
||||
|
||||
CMake Error in CMakeLists.txt:
|
||||
Pattern expression
|
||||
|
||||
<OUTPUT_FILE>
|
||||
|
||||
from rule "simple", used by the fileset "fs" of the target "foo", did not
|
||||
expand correctly.
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
enable_language(C)
|
||||
|
||||
add_custom_rule(simple OUTPUT <OUTPUT_FILE>
|
||||
COMMAND cmd)
|
||||
|
||||
add_library(foo STATIC)
|
||||
|
||||
target_sources(foo PRIVATE FILE_SET fs TYPE simple FILES file.i)
|
||||
set_property(FILE_SET fs TARGET foo PROPERTY RULE_PATTERNS "OUTPUT_FILE=<OUTPUT_FILE>")
|
||||
@@ -45,3 +45,12 @@ target_sources(foo3 PRIVATE FILE_SET fs TYPE preprocess FILES file1.c)
|
||||
|
||||
set_property(FILE_SET fs TARGET foo3 PROPERTY RULE_PATTERNS
|
||||
"DEFINES=${CMAKE_C_DEFINE_FLAG}WRONG=1")
|
||||
|
||||
|
||||
# Define complex multi-level pattern
|
||||
add_library(foo4 STATIC)
|
||||
|
||||
target_sources(foo4 PRIVATE FILE_SET fs TYPE preprocess FILES file1.c)
|
||||
|
||||
set_property(FILE_SET fs TARGET foo4 PROPERTY RULE_PATTERNS
|
||||
"INPUT=$<PATH:NATIVE_PATH,<SOURCE>>;OUTPUT_DIR=<CURRENT_BINARY_DIR>/<TARGET>;CMAKE_C_COMPILER=${CMAKE_C_COMPILER};PREPROCESSED_SOURCE=$<PATH:NATIVE_PATH,<OUTPUT_DIR>/<BASE_NAME>.c>;INCLUDES=;DEFINES=<DEFINE_FLAG><VALUE>;DEFINE_FLAG=${CMAKE_C_DEFINE_FLAG};VALUE=RULE_PATTERN=<DATA>;DATA=1;FLAGS=")
|
||||
@@ -12,6 +12,9 @@ run_cmake(OUTPUT_FILE_SET-BadPattern)
|
||||
run_cmake(OUTPUT_FILE_SET-BadType)
|
||||
run_cmake(OUTPUT_FILE_SET-TypeMismatch)
|
||||
|
||||
run_cmake(PatternSelfReference)
|
||||
run_cmake(PatternCyclicReference)
|
||||
|
||||
run_cmake(RuleProperties1)
|
||||
run_cmake(RuleProperties2)
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <cm/ranges>
|
||||
#include <cm/type_traits>
|
||||
@@ -18,7 +19,6 @@
|
||||
#if defined(__SUNPRO_CC) && defined(__sparc)
|
||||
# include <list>
|
||||
# include <string>
|
||||
# include <vector>
|
||||
#endif
|
||||
|
||||
namespace cm {
|
||||
|
||||
Reference in new issue
Block a user