mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-25 04:09:36 +03:00
605 lines
20 KiB
C++
605 lines
20 KiB
C++
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
|
file LICENSE.rst or https://cmake.org/licensing for details. */
|
|
#include "cmRule.h"
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
|
|
#include <cm/string_view>
|
|
#include <cmext/algorithm>
|
|
#include <cmext/string_view>
|
|
|
|
#include "cmsys/RegularExpression.hxx"
|
|
|
|
#include "cmExecutionStatus.h"
|
|
#include "cmFileSet.h"
|
|
#include "cmFileSetMetadata.h"
|
|
#include "cmGlobalGenerator.h"
|
|
#include "cmList.h"
|
|
#include "cmListFileCache.h"
|
|
#include "cmMakefile.h"
|
|
#include "cmMessageType.h"
|
|
#include "cmPlaceholderExpander.h"
|
|
#include "cmRange.h"
|
|
#include "cmSourceFile.h"
|
|
#include "cmStringAlgorithms.h"
|
|
#include "cmTarget.h"
|
|
#include "cmValue.h"
|
|
|
|
namespace {
|
|
cm::string_view const NAME = "NAME"_s;
|
|
cm::string_view const OUTPUT = "OUTPUT"_s;
|
|
cm::string_view const COMMAND = "COMMAND"_s;
|
|
cm::string_view const COMMAND_COUNT = "COMMAND_COUNT"_s;
|
|
cm::string_view const COMMAND_EXPAND_LISTS = "COMMAND_EXPAND_LISTS"_s;
|
|
cm::string_view const COMMENT = "COMMENT"_s;
|
|
cm::string_view const COMPILE_DEFINITIONS = "COMPILE_DEFINITIONS"_s;
|
|
cm::string_view const COMPILE_OPTIONS = "COMPILE_OPTIONS"_s;
|
|
cm::string_view const DEPENDS = "DEPENDS"_s;
|
|
cm::string_view const DEPENDS_EXPLICIT_ONLY = "DEPENDS_EXPLICIT_ONLY"_s;
|
|
cm::string_view const BYPRODUCTS = "BYPRODUCTS"_s;
|
|
cm::string_view const DEPFILE = "DEPFILE"_s;
|
|
cm::string_view const GLOBAL = "GLOBAL"_s;
|
|
cm::string_view const INCLUDE_DIRECTORIES = "INCLUDE_DIRECTORIES"_s;
|
|
cm::string_view const JOB_POOL_COMPILE = "JOB_POOL_COMPILE"_s;
|
|
cm::string_view const JOB_SERVER_AWARE = "JOB_SERVER_AWARE"_s;
|
|
cm::string_view const OUTPUT_FILE_SET = "OUTPUT_FILE_SET"_s;
|
|
cm::string_view const PARENT_RULE = "PARENT_RULE"_s;
|
|
cm::string_view const FILE_SET_CONFIGURATORS = "FILE_SET_CONFIGURATORS"_s;
|
|
cm::string_view const SOURCE_CONFIGURATORS = "SOURCE_CONFIGURATORS"_s;
|
|
cm::string_view const USES_TERMINAL = "USES_TERMINAL"_s;
|
|
cm::string_view const VERBATIM = "VERBATIM"_s;
|
|
cm::string_view const WORKING_DIRECTORY = "WORKING_DIRECTORY"_s;
|
|
|
|
cmsys::RegularExpression commandIndex("^COMMAND_[0-9]+$");
|
|
|
|
enum class ReadOnlyCondition
|
|
{
|
|
All,
|
|
Configuration,
|
|
Generation,
|
|
};
|
|
|
|
struct ReadOnlyProperty
|
|
{
|
|
ReadOnlyProperty(ReadOnlyCondition cond)
|
|
: Condition{ cond }
|
|
{
|
|
}
|
|
|
|
ReadOnlyCondition Condition;
|
|
|
|
std::string Message(cm::string_view prop, cmRule const* rule) const
|
|
{
|
|
std::string msg;
|
|
switch (this->Condition) {
|
|
case ReadOnlyCondition::All:
|
|
msg = " property is read-only for rules (\"";
|
|
break;
|
|
case ReadOnlyCondition::Configuration:
|
|
msg = " property can't be set during configuration for rules (\"";
|
|
break;
|
|
case ReadOnlyCondition::Generation:
|
|
msg = " property can't be set during generation for rules (\"";
|
|
break;
|
|
}
|
|
return cmStrCat('"', prop, "\" ", msg, rule->GetName(), "\")\n");
|
|
}
|
|
|
|
bool IsReadOnly(cm::string_view prop, cmRule const* rule) const
|
|
{
|
|
if ((rule->InGeneration() &&
|
|
this->Condition == ReadOnlyCondition::Configuration) ||
|
|
(!rule->InGeneration() &&
|
|
this->Condition == ReadOnlyCondition::Generation)) {
|
|
return false;
|
|
}
|
|
|
|
rule->GetMakefile().IssueMessage(MessageType::FATAL_ERROR,
|
|
this->Message(prop, rule));
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
bool IsSettableProperty(cm::string_view prop, cmRule const* rule)
|
|
{
|
|
using ROC = ReadOnlyCondition;
|
|
static std::unordered_map<cm::string_view, ReadOnlyProperty> const
|
|
readOnlyProps{ { NAME, { ROC::All } },
|
|
{ OUTPUT, { ROC::All } },
|
|
{ COMMAND, { ROC::All } },
|
|
{ COMMAND_COUNT, { ROC::All } },
|
|
{ COMMAND_EXPAND_LISTS, { ROC::Generation } },
|
|
{ COMMENT, { ROC::Generation } },
|
|
{ COMPILE_DEFINITIONS, { ROC::Generation } },
|
|
{ COMPILE_OPTIONS, { ROC::Generation } },
|
|
{ DEPENDS, { ROC::All } },
|
|
{ DEPENDS_EXPLICIT_ONLY, { ROC::Generation } },
|
|
{ BYPRODUCTS, { ROC::All } },
|
|
{ DEPFILE, { ROC::All } },
|
|
{ GLOBAL, { ROC::Generation } },
|
|
{ INCLUDE_DIRECTORIES, { ROC::Generation } },
|
|
{ JOB_POOL_COMPILE, { ROC::Generation } },
|
|
{ JOB_SERVER_AWARE, { ROC::Generation } },
|
|
{ OUTPUT_FILE_SET, { ROC::Generation } },
|
|
{ PARENT_RULE, { ROC::All } },
|
|
{ FILE_SET_CONFIGURATORS, { ROC::All } },
|
|
{ SOURCE_CONFIGURATORS, { ROC::All } },
|
|
{ USES_TERMINAL, { ROC::Generation } },
|
|
{ VERBATIM, { ROC::Generation } },
|
|
{ WORKING_DIRECTORY, { ROC::Generation } } };
|
|
|
|
auto it =
|
|
readOnlyProps.find(commandIndex.find(prop.data()) ? COMMAND : prop);
|
|
|
|
if (it != readOnlyProps.end()) {
|
|
return !(it->second.IsReadOnly(prop, rule));
|
|
}
|
|
|
|
if (rule->InGeneration()) {
|
|
rule->GetMakefile().IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
cmStrCat("rule properties cannot be changed during generation (\"",
|
|
rule->GetName(), "\")\n"));
|
|
return false;
|
|
}
|
|
|
|
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)
|
|
: Makefile(&makefile)
|
|
, Name(std::move(name))
|
|
, Scope(scope)
|
|
{
|
|
// set some useful properties
|
|
this->SetProperty("VERBATIM", cmValue::True);
|
|
this->SetProperty("COMMAND_EXPAND_LISTS", cmValue::True);
|
|
this->SetProperty("OUTPUT_FILE_SET",
|
|
"__cmake_rule_<RULE>_<TARGET>_<FILE_SET>_outputs;SOURCES");
|
|
}
|
|
|
|
cmRule::cmRule(cmRule const& parent, cmMakefile& makefile, std::string name,
|
|
cm::RuleScope scope)
|
|
: Makefile(&makefile)
|
|
, Name(std::move(name))
|
|
, Scope(scope)
|
|
, ConfiguratorsChain(parent.ConfiguratorsChain)
|
|
, Properties(parent.Properties)
|
|
, IncludeDirectories(parent.IncludeDirectories)
|
|
, CompileOptions(parent.CompileOptions)
|
|
, CompileDefinitions(parent.CompileDefinitions)
|
|
, Generation(parent.Generation)
|
|
{
|
|
}
|
|
std::string const& cmRule::GetParentName() const
|
|
{
|
|
static std::string empty;
|
|
|
|
return empty;
|
|
}
|
|
|
|
void cmRule::SetConfigurator(ConfiguratorType type, std::string configurator,
|
|
ChainConfigurators chain)
|
|
{
|
|
this->Configurators[type] = std::move(configurator);
|
|
if (chain == ChainConfigurators::Yes) {
|
|
this->ConfiguratorsChain[type].emplace_back(&this->GetName(),
|
|
&this->Configurators[type]);
|
|
} else {
|
|
this->ConfiguratorsChain[type].assign(
|
|
1,
|
|
ConfiguratorSet::value_type{ &this->GetName(),
|
|
&this->Configurators[type] });
|
|
}
|
|
}
|
|
cmRule::ConfiguratorSet const& cmRule::GetConfigurators(
|
|
ConfiguratorType type) const
|
|
{
|
|
static ConfiguratorSet emptySet;
|
|
|
|
if (this->HasConfigurators(type)) {
|
|
return this->ConfiguratorsChain.at(type);
|
|
}
|
|
return emptySet;
|
|
}
|
|
|
|
bool cmRule::HasConfigurators(ConfiguratorType type) const
|
|
{
|
|
return cm::contains(this->ConfiguratorsChain, type);
|
|
}
|
|
|
|
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();
|
|
|
|
std::string fsName{ outputFileSet[0] };
|
|
expander.ExpandVariables(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, "\"."));
|
|
return nullptr;
|
|
}
|
|
|
|
auto result = target->GetOrCreateFileSet(fsName, 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 \"",
|
|
target->GetName(), "\", has the type \"",
|
|
result.first->GetType(), "\" instead of \"", outputFileSet[1],
|
|
"\", as specified by the rule \"", this->GetName(), "\"."));
|
|
return nullptr;
|
|
}
|
|
|
|
return result.first;
|
|
}
|
|
|
|
cmBTStringRange cmRule::GetIncludeDirectories() const
|
|
{
|
|
return cmMakeRange(this->IncludeDirectories);
|
|
}
|
|
|
|
cmBTStringRange cmRule::GetCompileOptions() const
|
|
{
|
|
return cmMakeRange(this->CompileOptions);
|
|
}
|
|
|
|
cmBTStringRange cmRule::GetCompileDefinitions() const
|
|
{
|
|
return cmMakeRange(this->CompileDefinitions);
|
|
}
|
|
|
|
void cmRule::SetProperty(std::string const& prop, cmValue value)
|
|
{
|
|
if (!IsSettableProperty(prop, this)) {
|
|
return;
|
|
}
|
|
|
|
if (prop == GLOBAL) {
|
|
if (!value.IsOn()) {
|
|
this->GetMakefile().IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
cmStrCat("GLOBAL property can't be set to FALSE on rules (\"",
|
|
this->GetName(), "\")"));
|
|
return;
|
|
}
|
|
/* no need to change anything if value does not change */
|
|
if (!this->IsGloballyVisible()) {
|
|
this->Scope = cm::RuleScope::Global;
|
|
this->GetMakefile().GetGlobalGenerator()->IndexRule(this);
|
|
}
|
|
} else if (prop == OUTPUT_FILE_SET) {
|
|
cmList fileSet{ value };
|
|
if (fileSet.size() != 2) {
|
|
this->GetMakefile().IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
"OUTPUT_FILE_SET property require a list of 2 elements:\n "
|
|
"\"name;type\"");
|
|
return;
|
|
}
|
|
if (!cm::FileSetMetadata::IsKnownType(fileSet[1])) {
|
|
this->GetMakefile().IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
cmStrCat(
|
|
"specified file set type is erroneous. The supported types are: ",
|
|
cmJoin(cm::FileSetMetadata::GetKnownTypes(), ", "), '.'));
|
|
return;
|
|
}
|
|
this->Properties.SetProperty(prop, value);
|
|
} else if (prop == INCLUDE_DIRECTORIES) {
|
|
this->IncludeDirectories.clear();
|
|
if (value) {
|
|
cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
|
|
this->IncludeDirectories.emplace_back(value, lfbt);
|
|
}
|
|
} else if (prop == COMPILE_OPTIONS) {
|
|
this->CompileOptions.clear();
|
|
if (value) {
|
|
cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
|
|
this->CompileOptions.emplace_back(value, lfbt);
|
|
}
|
|
} else if (prop == COMPILE_DEFINITIONS) {
|
|
this->CompileDefinitions.clear();
|
|
if (value) {
|
|
cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
|
|
this->CompileDefinitions.emplace_back(value, lfbt);
|
|
}
|
|
} else {
|
|
this->Properties.SetProperty(prop, value);
|
|
}
|
|
}
|
|
|
|
void cmRule::AppendProperty(std::string const& prop, std::string const& value,
|
|
bool asString)
|
|
{
|
|
if (!IsSettableProperty(prop, this)) {
|
|
return;
|
|
}
|
|
|
|
if (prop == GLOBAL) {
|
|
this->GetMakefile().IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
cmStrCat("GLOBAL property can't be appended, only set on rules (\"",
|
|
this->GetName(), "\")\n"));
|
|
return;
|
|
}
|
|
|
|
if (prop == INCLUDE_DIRECTORIES) {
|
|
if (!value.empty()) {
|
|
cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
|
|
this->IncludeDirectories.emplace_back(value, lfbt);
|
|
}
|
|
} else if (prop == COMPILE_OPTIONS) {
|
|
if (!value.empty()) {
|
|
cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
|
|
this->CompileOptions.emplace_back(value, lfbt);
|
|
}
|
|
} else if (prop == COMPILE_DEFINITIONS) {
|
|
if (!value.empty()) {
|
|
cmListFileBacktrace lfbt = this->GetMakefile().GetBacktrace();
|
|
this->CompileDefinitions.emplace_back(value, lfbt);
|
|
}
|
|
} else {
|
|
this->Properties.AppendProperty(prop, value, asString);
|
|
}
|
|
}
|
|
|
|
cmValue cmRule::GetProperty(std::string const& prop) const
|
|
{
|
|
static std::string value;
|
|
|
|
if (prop == NAME) {
|
|
return cmValue{ this->GetName() };
|
|
}
|
|
if (prop == OUTPUT) {
|
|
value = cmList::to_string(this->GetOutputs());
|
|
return cmValue{ value };
|
|
}
|
|
if (prop == COMMAND) {
|
|
value = cmList::to_string(this->GetCommands()[0]);
|
|
return cmValue{ value };
|
|
}
|
|
if (prop == COMMAND_COUNT) {
|
|
value = std::to_string(this->GetCommands().size());
|
|
return cmValue{ value };
|
|
}
|
|
if (commandIndex.find(prop)) {
|
|
auto index = std::stoul(prop.substr(8));
|
|
value = index >= this->GetCommands().size()
|
|
? "NOTFOUND"
|
|
: cmList::to_string(this->GetCommands()[index]);
|
|
return cmValue{ value };
|
|
}
|
|
if (prop == DEPENDS) {
|
|
value = cmList::to_string(this->GetDepends());
|
|
return cmValue{ value };
|
|
}
|
|
if (prop == BYPRODUCTS) {
|
|
value = cmList::to_string(this->GetByproducts());
|
|
return cmValue{ value };
|
|
}
|
|
if (prop == DEPFILE) {
|
|
return cmValue{ this->GetDepfile() };
|
|
}
|
|
if (prop == GLOBAL) {
|
|
return this->IsGloballyVisible() ? cmValue::True : cmValue::False;
|
|
}
|
|
if (prop == PARENT_RULE) {
|
|
return cmValue{ this->GetParentName() };
|
|
}
|
|
if (prop == FILE_SET_CONFIGURATORS || prop == SOURCE_CONFIGURATORS) {
|
|
ConfiguratorType type = prop == FILE_SET_CONFIGURATORS
|
|
? ConfiguratorType::FileSet
|
|
: ConfiguratorType::Source;
|
|
|
|
if (this->HasConfigurators(type)) {
|
|
auto cfgs_set = this->GetConfigurators(type);
|
|
std::vector<std::string> cfgs;
|
|
cfgs.reserve(cfgs_set.size());
|
|
|
|
std::transform(cfgs_set.cbegin(), cfgs_set.cend(),
|
|
std::back_inserter(cfgs),
|
|
[](ConfiguratorSet::value_type cfg) -> std::string {
|
|
return *cfg.second;
|
|
});
|
|
|
|
value = cmList::to_string(cfgs);
|
|
return cmValue{ value };
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
// Check for the properties with backtraces.
|
|
if (prop == INCLUDE_DIRECTORIES) {
|
|
if (this->IncludeDirectories.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
value = cmList::to_string(this->IncludeDirectories);
|
|
return cmValue{ value };
|
|
}
|
|
|
|
if (prop == COMPILE_OPTIONS) {
|
|
if (this->CompileOptions.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
value = cmList::to_string(this->CompileOptions);
|
|
return cmValue{ value };
|
|
}
|
|
|
|
if (prop == COMPILE_DEFINITIONS) {
|
|
if (this->CompileDefinitions.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
value = cmList::to_string(this->CompileDefinitions);
|
|
return cmValue{ value };
|
|
}
|
|
|
|
return this->Properties.GetPropertyValue(prop);
|
|
}
|
|
|
|
void cmRule::CheckProperty(std::string const& prop, cmMakefile& context) const
|
|
{
|
|
// Certain properties need checking.
|
|
if (prop == GLOBAL) {
|
|
auto const& rules = context.GetOwnedRules();
|
|
auto it = std::find_if(rules.begin(), rules.end(),
|
|
[&](std::unique_ptr<cmRule> const& rule) -> bool {
|
|
return this == rule.get();
|
|
});
|
|
if (it == rules.end()) {
|
|
context.IssueMessage(
|
|
MessageType::FATAL_ERROR,
|
|
cmStrCat("Attempt to promote rule \"", this->GetName(),
|
|
"\" to global scope (by setting GLOBAL) "
|
|
"which is not created in this directory."));
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
cmsys::RegularExpression PatternRegex{ "(^[A-Z][A-Z0-9_]+)=(.*)$" };
|
|
|
|
void UpdatePatterns(cmRule::PatternSet& 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));
|
|
} else {
|
|
it->Value = PatternRegex.match(2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ConfigureRule(cmRule::ConfiguratorSet const& configurators,
|
|
cmMakefile* mf, cmRule::PatternSet& 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 };
|
|
|
|
for (auto const& item : configurators) {
|
|
// The validator command will be executed in an isolated scope.
|
|
cmMakefile::ScopePushPop varScope(mf);
|
|
cmMakefile::PolicyPushPop polScope(mf);
|
|
static_cast<void>(varScope);
|
|
static_cast<void>(polScope);
|
|
|
|
std::vector<cmListFileArgument> args{
|
|
cmListFileArgument{ rule, cmListFileArgument::Unquoted, 0 },
|
|
cmListFileArgument{ target, cmListFileArgument::Unquoted, 0 },
|
|
cmListFileArgument{ fileSet, cmListFileArgument::Unquoted, 0 },
|
|
cmListFileArgument{ outputFileSet, cmListFileArgument::Unquoted, 0 }
|
|
};
|
|
if (!source.empty()) {
|
|
args.emplace_back(source, cmListFileArgument::Quoted, 0);
|
|
}
|
|
args.emplace_back(patternsVariable, cmListFileArgument::Unquoted, 0);
|
|
|
|
cmListFileFunction command(*item.second, 0, 0, args);
|
|
cmExecutionStatus status(*mf);
|
|
if (!mf->ExecuteCommand(command, status)) {
|
|
mf->IssueMessage(MessageType::FATAL_ERROR,
|
|
cmStrCat("Erroneous execution of the CONFIGURATOR \"",
|
|
*item.second, "\", from the RULE \"",
|
|
*item.first, "\", for the FILE_SET \"",
|
|
fileSet, "\" of TARGET \"", target, "\"."));
|
|
return false;
|
|
}
|
|
UpdatePatterns(
|
|
patterns, cmList{ mf->GetDefinition(std::string{ patternsVariable }) });
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
|
cmFileSet const* outputFileSet,
|
|
PatternSet& patterns) const
|
|
{
|
|
this->SwitchMode();
|
|
|
|
// First, take patterns from RULE_PATTERNS file set property, if any
|
|
if (cmValue fsPatterns = fileSet->GetProperty("RULE_PATTERNS")) {
|
|
UpdatePatterns(patterns, cmList{ fsPatterns, cmList::EmptyElements::No });
|
|
}
|
|
|
|
if (this->HasConfigurators(ConfiguratorType::FileSet)) {
|
|
// Finalize file set level configuration by calling user's commands
|
|
return ConfigureRule(this->GetConfigurators(ConfiguratorType::FileSet),
|
|
fileSet->GetMakefile(), patterns, this->GetName(),
|
|
target->GetName(), fileSet->GetName(),
|
|
outputFileSet->GetName());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cmRule::Instantiate(cmTarget const* target, cmFileSet const* fileSet,
|
|
cmFileSet const* outputFileSet, cmSourceFile* source,
|
|
PatternSet& patterns) const
|
|
{
|
|
// First, take patterns from <RULE>_PATTERNS source file property, if any
|
|
if (cmValue sfPatterns =
|
|
source->GetProperty(cmStrCat(this->GetName(), "_PATTERNS"))) {
|
|
UpdatePatterns(patterns, cmList{ sfPatterns, cmList::EmptyElements::No });
|
|
}
|
|
|
|
if (this->HasConfigurators(ConfiguratorType::Source)) {
|
|
// Before custom commands generation, finalize source level
|
|
// configuration by calling user's commands
|
|
return ConfigureRule(this->GetConfigurators(ConfiguratorType::Source),
|
|
fileSet->GetMakefile(), patterns, this->GetName(),
|
|
target->GetName(), fileSet->GetName(),
|
|
outputFileSet->GetName(), source->GetFullPath());
|
|
}
|
|
|
|
return true;
|
|
}
|