summaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2020-12-16 11:20:34 (GMT)
committerKitware Robot <kwrobot@kitware.com>2020-12-16 11:20:39 (GMT)
commit34469a4f71c523488682661aafc8d13b054ed5b9 (patch)
treee593b7686cdf94405cfdbc0b47745304a066f4ae /Source
parentd8654c2a0290b30c8684a334652d8876e5ab33f6 (diff)
parent1526ae3abac7c8e8ad61ba92e6a8219aaece7f7a (diff)
downloadCMake-34469a4f71c523488682661aafc8d13b054ed5b9.zip
CMake-34469a4f71c523488682661aafc8d13b054ed5b9.tar.gz
CMake-34469a4f71c523488682661aafc8d13b054ed5b9.tar.bz2
Merge topic 'custom-command-output-genex-nmc'
1526ae3aba Tests: Add cases for Ninja Multi-Config cross-config custom commands dcf9f4d2f7 Ninja Multi-Config: Add support for cross-config custom commands 15467f12f7 cmLocalGenerator: Adopt custom target 'force' output name generation 7b64b0cd5a cmLocalGenerator: Refactor custom command generator construction d29da8ed3e cmMakefile: Simplify custom target 'force' output name generation 2b1cc175ee Help: Clarify version adding add_custom_{command,target} OUTPUT genex support Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !5612
Diffstat (limited to 'Source')
-rw-r--r--Source/cmCustomCommandGenerator.cxx132
-rw-r--r--Source/cmCustomCommandGenerator.h11
-rw-r--r--Source/cmCustomCommandTypes.h7
-rw-r--r--Source/cmGeneratorTarget.cxx17
-rw-r--r--Source/cmGlobalNinjaGenerator.cxx97
-rw-r--r--Source/cmGlobalNinjaGenerator.h45
-rw-r--r--Source/cmLocalGenerator.cxx41
-rw-r--r--Source/cmLocalGenerator.h10
-rw-r--r--Source/cmLocalNinjaGenerator.cxx333
-rw-r--r--Source/cmLocalNinjaGenerator.h14
-rw-r--r--Source/cmMakefile.cxx29
-rw-r--r--Source/cmMakefile.h5
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx53
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.h4
14 files changed, 581 insertions, 217 deletions
diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx
index 64cd88e..c67497a 100644
--- a/Source/cmCustomCommandGenerator.cxx
+++ b/Source/cmCustomCommandGenerator.cxx
@@ -7,7 +7,9 @@
#include <utility>
#include <cm/optional>
+#include <cm/string_view>
#include <cmext/algorithm>
+#include <cmext/string_view>
#include "cmCryptoHash.h"
#include "cmCustomCommand.h"
@@ -24,15 +26,95 @@
#include "cmTransformDepfile.h"
namespace {
+std::string EvaluateSplitConfigGenex(
+ cm::string_view input, cmGeneratorExpression const& ge, cmLocalGenerator* lg,
+ bool useOutputConfig, std::string const& outputConfig,
+ std::string const& commandConfig,
+ std::set<BT<std::pair<std::string, bool>>>* utils = nullptr)
+{
+ std::string result;
+
+ while (!input.empty()) {
+ // Copy non-genex content directly to the result.
+ std::string::size_type pos = input.find("$<");
+ result += input.substr(0, pos);
+ if (pos == std::string::npos) {
+ break;
+ }
+ input = input.substr(pos);
+
+ // Find the balanced end of this regex.
+ size_t nestingLevel = 1;
+ for (pos = 2; pos < input.size(); ++pos) {
+ cm::string_view cur = input.substr(pos);
+ if (cmHasLiteralPrefix(cur, "$<")) {
+ ++nestingLevel;
+ ++pos;
+ continue;
+ }
+ if (cmHasLiteralPrefix(cur, ">")) {
+ --nestingLevel;
+ if (nestingLevel == 0) {
+ ++pos;
+ break;
+ }
+ }
+ }
+
+ // Split this genex from following input.
+ cm::string_view genex = input.substr(0, pos);
+ input = input.substr(pos);
+
+ // Convert an outer COMMAND_CONFIG or OUTPUT_CONFIG to the matching config.
+ std::string const* config =
+ useOutputConfig ? &outputConfig : &commandConfig;
+ if (nestingLevel == 0) {
+ static cm::string_view const COMMAND_CONFIG = "$<COMMAND_CONFIG:"_s;
+ static cm::string_view const OUTPUT_CONFIG = "$<OUTPUT_CONFIG:"_s;
+ if (cmHasPrefix(genex, COMMAND_CONFIG)) {
+ genex.remove_prefix(COMMAND_CONFIG.size());
+ genex.remove_suffix(1);
+ useOutputConfig = false;
+ config = &commandConfig;
+ } else if (cmHasPrefix(genex, OUTPUT_CONFIG)) {
+ genex.remove_prefix(OUTPUT_CONFIG.size());
+ genex.remove_suffix(1);
+ useOutputConfig = true;
+ config = &outputConfig;
+ }
+ }
+
+ // Evaluate this genex in the selected configuration.
+ std::unique_ptr<cmCompiledGeneratorExpression> cge =
+ ge.Parse(std::string(genex));
+ result += cge->Evaluate(lg, *config);
+
+ // Record targets referenced by the genex.
+ if (utils) {
+ // FIXME: What is the proper condition for a cross-dependency?
+ bool const cross = !useOutputConfig;
+ for (cmGeneratorTarget* gt : cge->GetTargets()) {
+ utils->emplace(BT<std::pair<std::string, bool>>(
+ { gt->GetName(), cross }, cge->GetBacktrace()));
+ }
+ }
+ }
+
+ return result;
+}
+
std::vector<std::string> EvaluateDepends(std::vector<std::string> const& paths,
cmGeneratorExpression const& ge,
cmLocalGenerator* lg,
- std::string const& config)
+ std::string const& outputConfig,
+ std::string const& commandConfig)
{
std::vector<std::string> depends;
for (std::string const& p : paths) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
- std::string const& ep = cge->Evaluate(lg, config);
+ std::string const& ep =
+ EvaluateSplitConfigGenex(p, ge, lg, /*useOutputConfig=*/true,
+ /*outputConfig=*/outputConfig,
+ /*commandConfig=*/commandConfig);
cm::append(depends, cmExpandedList(ep));
}
for (std::string& p : depends) {
@@ -59,12 +141,12 @@ std::vector<std::string> EvaluateOutputs(std::vector<std::string> const& paths,
}
}
-cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
- std::string config,
- cmLocalGenerator* lg,
- bool transformDepfile)
+cmCustomCommandGenerator::cmCustomCommandGenerator(
+ cmCustomCommand const& cc, std::string config, cmLocalGenerator* lg,
+ bool transformDepfile, cm::optional<std::string> crossConfig)
: CC(&cc)
- , Config(std::move(config))
+ , OutputConfig(crossConfig ? *crossConfig : config)
+ , CommandConfig(std::move(config))
, LG(lg)
, OldStyle(cc.GetEscapeOldStyle())
, MakeVars(cc.GetEscapeAllowMakeVars())
@@ -75,18 +157,20 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
for (cmCustomCommandLine const& cmdline : cmdlines) {
cmCustomCommandLine argv;
+ // For the command itself, we default to the COMMAND_CONFIG.
+ bool useOutputConfig = false;
for (std::string const& clarg : cmdline) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(clarg);
- std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
- for (cmGeneratorTarget* gt : cge->GetTargets()) {
- this->Utilities.emplace(BT<std::pair<std::string, bool>>(
- { gt->GetName(), true }, cge->GetBacktrace()));
- }
+ std::string parsed_arg = EvaluateSplitConfigGenex(
+ clarg, ge, this->LG, useOutputConfig, this->OutputConfig,
+ this->CommandConfig, &this->Utilities);
if (this->CC->GetCommandExpandLists()) {
cm::append(argv, cmExpandedList(parsed_arg));
} else {
argv.push_back(std::move(parsed_arg));
}
+
+ // For remaining arguments, we default to the OUTPUT_CONFIG.
+ useOutputConfig = true;
}
if (!argv.empty()) {
@@ -94,8 +178,10 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
// collect the target to add a target-level dependency on it.
cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front());
if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) {
+ // FIXME: What is the proper condition for a cross-dependency?
+ bool const cross = true;
this->Utilities.emplace(BT<std::pair<std::string, bool>>(
- { gt->GetName(), true }, cc.GetBacktrace()));
+ { gt->GetName(), cross }, cc.GetBacktrace()));
}
} else {
// Later code assumes at least one entry exists, but expanding
@@ -137,16 +223,18 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
this->CommandLines.push_back(std::move(argv));
}
- this->Outputs = EvaluateOutputs(cc.GetOutputs(), ge, this->LG, this->Config);
+ this->Outputs =
+ EvaluateOutputs(cc.GetOutputs(), ge, this->LG, this->OutputConfig);
this->Byproducts =
- EvaluateOutputs(cc.GetByproducts(), ge, this->LG, this->Config);
- this->Depends = EvaluateDepends(cc.GetDepends(), ge, this->LG, this->Config);
+ EvaluateOutputs(cc.GetByproducts(), ge, this->LG, this->OutputConfig);
+ this->Depends = EvaluateDepends(cc.GetDepends(), ge, this->LG,
+ this->OutputConfig, this->CommandConfig);
const std::string& workingdirectory = this->CC->GetWorkingDirectory();
if (!workingdirectory.empty()) {
- std::unique_ptr<cmCompiledGeneratorExpression> cge =
- ge.Parse(workingdirectory);
- this->WorkingDirectory = cge->Evaluate(this->LG, this->Config);
+ this->WorkingDirectory =
+ EvaluateSplitConfigGenex(workingdirectory, ge, this->LG, true,
+ this->OutputConfig, this->CommandConfig);
// Convert working directory to a full path.
if (!this->WorkingDirectory.empty()) {
std::string const& build_dir = this->LG->GetCurrentBinaryDirectory();
@@ -203,7 +291,7 @@ const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
(target->IsImported() ||
target->GetProperty("CROSSCOMPILING_EMULATOR") ||
!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
- return target->GetLocation(this->Config).c_str();
+ return target->GetLocation(this->CommandConfig).c_str();
}
return nullptr;
}
diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h
index dac3596..4be5b3f 100644
--- a/Source/cmCustomCommandGenerator.h
+++ b/Source/cmCustomCommandGenerator.h
@@ -9,6 +9,8 @@
#include <utility>
#include <vector>
+#include <cm/optional>
+
#include "cmCustomCommandLines.h"
#include "cmListFileCache.h"
@@ -18,7 +20,8 @@ class cmLocalGenerator;
class cmCustomCommandGenerator
{
cmCustomCommand const* CC;
- std::string Config;
+ std::string OutputConfig;
+ std::string CommandConfig;
cmLocalGenerator* LG;
bool OldStyle;
bool MakeVars;
@@ -36,7 +39,8 @@ class cmCustomCommandGenerator
public:
cmCustomCommandGenerator(cmCustomCommand const& cc, std::string config,
- cmLocalGenerator* lg, bool transformDepfile = true);
+ cmLocalGenerator* lg, bool transformDepfile = true,
+ cm::optional<std::string> crossConfig = {});
cmCustomCommandGenerator(const cmCustomCommandGenerator&) = delete;
cmCustomCommandGenerator(cmCustomCommandGenerator&&) = default;
cmCustomCommandGenerator& operator=(const cmCustomCommandGenerator&) =
@@ -55,4 +59,7 @@ public:
bool HasOnlyEmptyCommandLines() const;
std::string GetFullDepfile() const;
std::string GetInternalDepfile() const;
+
+ const std::string& GetOutputConfig() const { return this->OutputConfig; }
+ const std::string& GetCommandConfig() const { return this->CommandConfig; }
};
diff --git a/Source/cmCustomCommandTypes.h b/Source/cmCustomCommandTypes.h
index 5c900ce..324da9e 100644
--- a/Source/cmCustomCommandTypes.h
+++ b/Source/cmCustomCommandTypes.h
@@ -27,10 +27,3 @@ enum class cmObjectLibraryCommands
Reject,
Accept
};
-
-/** Utility target output source file name. */
-struct cmUtilityOutput
-{
- std::string Name;
- std::string NameCMP0049;
-};
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index b444edd..dfeb029 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -3064,7 +3064,7 @@ bool cmTargetTraceDependencies::IsUtility(std::string const& dep)
} else {
// The original name of the dependency was not a full path. It
// must name a target, so add the target-level dependency.
- this->GeneratorTarget->Target->AddUtility(util, false);
+ this->GeneratorTarget->Target->AddUtility(util, true);
return true;
}
}
@@ -3079,15 +3079,16 @@ void cmTargetTraceDependencies::CheckCustomCommand(cmCustomCommand const& cc)
std::set<std::string> depends;
for (std::string const& config :
this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
- cmCustomCommandGenerator ccg(cc, config, this->LocalGenerator);
+ for (cmCustomCommandGenerator const& ccg :
+ this->LocalGenerator->MakeCustomCommandGenerators(cc, config)) {
+ // Collect target-level dependencies referenced in command lines.
+ for (auto const& util : ccg.GetUtilities()) {
+ this->GeneratorTarget->Target->AddUtility(util);
+ }
- // Collect target-level dependencies referenced in command lines.
- for (auto const& util : ccg.GetUtilities()) {
- this->GeneratorTarget->Target->AddUtility(util);
+ // Collect file-level dependencies referenced in DEPENDS.
+ depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end());
}
-
- // Collect file-level dependencies referenced in DEPENDS.
- depends.insert(ccg.GetDepends().begin(), ccg.GetDepends().end());
}
// Queue file-level dependencies.
diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx
index ef80632..a098f81 100644
--- a/Source/cmGlobalNinjaGenerator.cxx
+++ b/Source/cmGlobalNinjaGenerator.cxx
@@ -56,6 +56,52 @@ std::string const cmGlobalNinjaGenerator::SHELL_NOOP = "cd .";
std::string const cmGlobalNinjaGenerator::SHELL_NOOP = ":";
#endif
+bool operator==(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return lhs.Target == rhs.Target && lhs.Config == rhs.Config &&
+ lhs.GenexOutput == rhs.GenexOutput;
+}
+
+bool operator!=(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator<(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return lhs.Target < rhs.Target ||
+ (lhs.Target == rhs.Target &&
+ (lhs.Config < rhs.Config ||
+ (lhs.Config == rhs.Config && lhs.GenexOutput < rhs.GenexOutput)));
+}
+
+bool operator>(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return rhs < lhs;
+}
+
+bool operator<=(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return !(lhs > rhs);
+}
+
+bool operator>=(
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& lhs,
+ const cmGlobalNinjaGenerator::ByConfig::TargetDependsClosureKey& rhs)
+{
+ return rhs <= lhs;
+}
+
void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
{
for (int i = 0; i < count; ++i) {
@@ -1194,23 +1240,30 @@ void cmGlobalNinjaGenerator::AppendTargetDepends(
void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
cmGeneratorTarget const* target, cmNinjaDeps& outputs,
- const std::string& config)
+ const std::string& config, const std::string& fileConfig, bool genexOutput)
{
cmNinjaOuts outs;
- this->AppendTargetDependsClosure(target, outs, config, true);
+ this->AppendTargetDependsClosure(target, outs, config, fileConfig,
+ genexOutput, true);
cm::append(outputs, outs);
}
void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
cmGeneratorTarget const* target, cmNinjaOuts& outputs,
- const std::string& config, bool omit_self)
+ const std::string& config, const std::string& fileConfig, bool genexOutput,
+ bool omit_self)
{
// try to locate the target in the cache
- auto find = this->Configs[config].TargetDependsClosures.lower_bound(target);
+ ByConfig::TargetDependsClosureKey key{
+ target,
+ config,
+ genexOutput,
+ };
+ auto find = this->Configs[fileConfig].TargetDependsClosures.lower_bound(key);
- if (find == this->Configs[config].TargetDependsClosures.end() ||
- find->first != target) {
+ if (find == this->Configs[fileConfig].TargetDependsClosures.end() ||
+ find->first != key) {
// We now calculate the closure outputs by inspecting the dependent
// targets recursively.
// For that we have to distinguish between a local result set that is only
@@ -1220,18 +1273,27 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
cmNinjaOuts this_outs; // this will be the new cache entry
for (auto const& dep_target : this->GetTargetDirectDepends(target)) {
- if (!dep_target->IsInBuildSystem() ||
- (target->GetType() != cmStateEnums::UTILITY &&
- dep_target->GetType() != cmStateEnums::UTILITY &&
- this->EnableCrossConfigBuild() && !dep_target.IsCross())) {
+ if (!dep_target->IsInBuildSystem()) {
+ continue;
+ }
+
+ if (!this->IsSingleConfigUtility(target) &&
+ !this->IsSingleConfigUtility(dep_target) &&
+ this->EnableCrossConfigBuild() && !dep_target.IsCross() &&
+ !genexOutput) {
continue;
}
- // Collect the dependent targets for _this_ target
- this->AppendTargetDependsClosure(dep_target, this_outs, config, false);
+ if (dep_target.IsCross()) {
+ this->AppendTargetDependsClosure(dep_target, this_outs, fileConfig,
+ fileConfig, genexOutput, false);
+ } else {
+ this->AppendTargetDependsClosure(dep_target, this_outs, config,
+ fileConfig, genexOutput, false);
+ }
}
- find = this->Configs[config].TargetDependsClosures.emplace_hint(
- find, target, std::move(this_outs));
+ find = this->Configs[fileConfig].TargetDependsClosures.emplace_hint(
+ find, key, std::move(this_outs));
}
// now fill the outputs of the final result from the newly generated cache
@@ -2478,6 +2540,13 @@ std::set<std::string> cmGlobalNinjaGenerator::GetCrossConfigs(
return result;
}
+bool cmGlobalNinjaGenerator::IsSingleConfigUtility(
+ cmGeneratorTarget const* target) const
+{
+ return target->GetType() == cmStateEnums::UTILITY &&
+ !this->PerConfigUtilityTargets.count(target->GetName());
+}
+
const char* cmGlobalNinjaMultiGenerator::NINJA_COMMON_FILE =
"CMakeFiles/common.ninja";
const char* cmGlobalNinjaMultiGenerator::NINJA_FILE_EXTENSION = ".ninja";
diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h
index 9344c4d..5e9defe 100644
--- a/Source/cmGlobalNinjaGenerator.h
+++ b/Source/cmGlobalNinjaGenerator.h
@@ -330,10 +330,14 @@ public:
cmNinjaTargetDepends depends);
void AppendTargetDependsClosure(cmGeneratorTarget const* target,
cmNinjaDeps& outputs,
- const std::string& config);
+ const std::string& config,
+ const std::string& fileConfig,
+ bool genexOutput);
void AppendTargetDependsClosure(cmGeneratorTarget const* target,
cmNinjaOuts& outputs,
- const std::string& config, bool omit_self);
+ const std::string& config,
+ const std::string& fileConfig,
+ bool genexOutput, bool omit_self);
void AppendDirectoryForConfig(const std::string& prefix,
const std::string& config,
@@ -429,6 +433,18 @@ public:
return this->DefaultConfigs;
}
+ const std::set<std::string>& GetPerConfigUtilityTargets() const
+ {
+ return this->PerConfigUtilityTargets;
+ }
+
+ void AddPerConfigUtilityTarget(const std::string& name)
+ {
+ this->PerConfigUtilityTargets.insert(name);
+ }
+
+ bool IsSingleConfigUtility(cmGeneratorTarget const* target) const;
+
protected:
void Generate() override;
@@ -522,6 +538,9 @@ private:
/// The mapping from source file to assumed dependencies.
std::map<std::string, std::set<std::string>> AssumedSourceDependencies;
+ /// Utility targets which have per-config outputs
+ std::set<std::string> PerConfigUtilityTargets;
+
struct TargetAlias
{
cmGeneratorTarget* GeneratorTarget;
@@ -561,7 +580,14 @@ private:
/// The set of custom commands we have seen.
std::set<cmCustomCommand const*> CustomCommands;
- std::map<cmGeneratorTarget const*, cmNinjaOuts> TargetDependsClosures;
+ struct TargetDependsClosureKey
+ {
+ cmGeneratorTarget const* Target;
+ std::string Config;
+ bool GenexOutput;
+ };
+
+ std::map<TargetDependsClosureKey, cmNinjaOuts> TargetDependsClosures;
TargetAliasMap TargetAliases;
@@ -570,6 +596,19 @@ private:
std::map<std::string, ByConfig> Configs;
cmNinjaDeps ByproductsForCleanTarget;
+
+ friend bool operator==(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator!=(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator<(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator>(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator<=(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
+ friend bool operator>=(const ByConfig::TargetDependsClosureKey& lhs,
+ const ByConfig::TargetDependsClosureKey& rhs);
};
class cmGlobalNinjaMultiGenerator : public cmGlobalNinjaGenerator
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx
index 7b1c531..d3ede5c 100644
--- a/Source/cmLocalGenerator.cxx
+++ b/Source/cmLocalGenerator.cxx
@@ -1129,9 +1129,8 @@ cmTarget* cmLocalGenerator::AddUtilityCommand(
detail::AddUtilityCommand(
*this, this->DirectoryBacktrace, cmCommandOrigin::Generator, target,
- this->Makefile->GetUtilityOutput(target), workingDir, byproducts, depends,
- commandLines, escapeOldStyle, comment, uses_terminal, command_expand_lists,
- job_pool, stdPipesUTF8);
+ workingDir, byproducts, depends, commandLines, escapeOldStyle, comment,
+ uses_terminal, command_expand_lists, job_pool, stdPipesUTF8);
return target;
}
@@ -4135,7 +4134,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
cmCommandOrigin origin, cmTarget* target,
- const cmUtilityOutput& force, const char* workingDir,
+ const char* workingDir,
const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines,
@@ -4148,10 +4147,14 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
comment = "";
}
+ // Create the generated symbolic output name of the utility target.
+ std::string output =
+ lg.CreateUtilityOutput(target->GetName(), byproducts, lfbt);
+
std::string no_main_dependency;
cmImplicitDependsList no_implicit_depends;
cmSourceFile* rule = AddCustomCommand(
- lg, lfbt, origin, { force.Name }, byproducts, depends, no_main_dependency,
+ lg, lfbt, origin, { output }, byproducts, depends, no_main_dependency,
no_implicit_depends, commandLines, comment, workingDir,
/*replace=*/false, escapeOldStyle, uses_terminal, command_expand_lists,
/*depfile=*/"", job_pool, stdPipesUTF8);
@@ -4159,9 +4162,7 @@ void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
lg.AddTargetByproducts(target, byproducts, lfbt, origin);
}
- if (!force.NameCMP0049.empty()) {
- target->AddSource(force.NameCMP0049);
- }
+ target->AddSource(output);
}
std::vector<std::string> ComputeISPCObjectSuffixes(cmGeneratorTarget* target)
@@ -4254,6 +4255,30 @@ cmSourceFile* cmLocalGenerator::GetSourceFileWithOutput(
return nullptr;
}
+std::string cmLocalGenerator::CreateUtilityOutput(
+ std::string const& targetName, std::vector<std::string> const&,
+ cmListFileBacktrace const&)
+{
+ std::string force =
+ cmStrCat(this->GetCurrentBinaryDirectory(), "/CMakeFiles/", targetName);
+ // The output is not actually created so mark it symbolic.
+ if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
+ sf->SetProperty("SYMBOLIC", "1");
+ } else {
+ cmSystemTools::Error("Could not get source file entry for " + force);
+ }
+ return force;
+}
+
+std::vector<cmCustomCommandGenerator>
+cmLocalGenerator::MakeCustomCommandGenerators(cmCustomCommand const& cc,
+ std::string const& config)
+{
+ std::vector<cmCustomCommandGenerator> ccgs;
+ ccgs.emplace_back(cc, config, this);
+ return ccgs;
+}
+
std::vector<std::string> cmLocalGenerator::ExpandCustomCommandOutputPaths(
cmCompiledGeneratorExpression const& cge, std::string const& config)
{
diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h
index 581badb..91dd8ae 100644
--- a/Source/cmLocalGenerator.h
+++ b/Source/cmLocalGenerator.h
@@ -24,6 +24,7 @@
class cmCompiledGeneratorExpression;
class cmComputeLinkInformation;
+class cmCustomCommand;
class cmCustomCommandGenerator;
class cmCustomCommandLines;
class cmGeneratorTarget;
@@ -363,6 +364,13 @@ public:
bool command_expand_lists = false, const std::string& job_pool = "",
bool stdPipesUTF8 = false);
+ virtual std::string CreateUtilityOutput(
+ std::string const& targetName, std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt);
+
+ virtual std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators(
+ cmCustomCommand const& cc, std::string const& config);
+
std::vector<std::string> ExpandCustomCommandOutputPaths(
cmCompiledGeneratorExpression const& cge, std::string const& config);
std::vector<std::string> ExpandCustomCommandOutputGenex(
@@ -684,7 +692,7 @@ void AppendCustomCommandToOutput(cmLocalGenerator& lg,
void AddUtilityCommand(cmLocalGenerator& lg, const cmListFileBacktrace& lfbt,
cmCommandOrigin origin, cmTarget* target,
- const cmUtilityOutput& force, const char* workingDir,
+ const char* workingDir,
const std::vector<std::string>& byproducts,
const std::vector<std::string>& depends,
const cmCustomCommandLines& commandLines,
diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx
index d90a37b..b035f70 100644
--- a/Source/cmLocalNinjaGenerator.cxx
+++ b/Source/cmLocalNinjaGenerator.cxx
@@ -10,6 +10,8 @@
#include <sstream>
#include <utility>
+#include <cmext/string_view>
+
#include "cmsys/FStream.hxx"
#include "cmCryptoHash.h"
@@ -567,17 +569,208 @@ void cmLocalNinjaGenerator::AppendCustomCommandLines(
}
void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
- cmCustomCommand const* cc, const cmNinjaDeps& orderOnlyDeps,
- const std::string& config)
+ cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets,
+ const std::string& fileConfig)
{
cmGlobalNinjaGenerator* gg = this->GetGlobalNinjaGenerator();
- if (gg->SeenCustomCommand(cc, config)) {
+ if (gg->SeenCustomCommand(cc, fileConfig)) {
return;
}
+ auto ccgs = this->MakeCustomCommandGenerators(*cc, fileConfig);
+ for (cmCustomCommandGenerator const& ccg : ccgs) {
+ cmNinjaDeps orderOnlyDeps;
+
+ // A custom command may appear on multiple targets. However, some build
+ // systems exist where the target dependencies on some of the targets are
+ // overspecified, leading to a dependency cycle. If we assume all target
+ // dependencies are a superset of the true target dependencies for this
+ // custom command, we can take the set intersection of all target
+ // dependencies to obtain a correct dependency list.
+ //
+ // FIXME: This won't work in certain obscure scenarios involving indirect
+ // dependencies.
+ auto j = targets.begin();
+ assert(j != targets.end());
+ this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
+ *j, orderOnlyDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
+ std::sort(orderOnlyDeps.begin(), orderOnlyDeps.end());
+ ++j;
+
+ for (; j != targets.end(); ++j) {
+ std::vector<std::string> jDeps;
+ std::vector<std::string> depsIntersection;
+ this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
+ *j, jDeps, ccg.GetOutputConfig(), fileConfig, ccgs.size() > 1);
+ std::sort(jDeps.begin(), jDeps.end());
+ std::set_intersection(orderOnlyDeps.begin(), orderOnlyDeps.end(),
+ jDeps.begin(), jDeps.end(),
+ std::back_inserter(depsIntersection));
+ orderOnlyDeps = depsIntersection;
+ }
+
+ const std::vector<std::string>& outputs = ccg.GetOutputs();
+ const std::vector<std::string>& byproducts = ccg.GetByproducts();
+
+ bool symbolic = false;
+ for (std::string const& output : outputs) {
+ if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
+ if (sf->GetPropertyAsBool("SYMBOLIC")) {
+ symbolic = true;
+ break;
+ }
+ }
+ }
+
+ cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size());
+ std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
+ gg->MapToNinjaPath());
+ std::transform(byproducts.begin(), byproducts.end(),
+ ninjaOutputs.begin() + outputs.size(),
+ gg->MapToNinjaPath());
+
+ for (std::string const& ninjaOutput : ninjaOutputs) {
+ gg->SeenCustomCommandOutput(ninjaOutput);
+ }
+
+ cmNinjaDeps ninjaDeps;
+ this->AppendCustomCommandDeps(ccg, ninjaDeps, fileConfig);
+
+ std::vector<std::string> cmdLines;
+ this->AppendCustomCommandLines(ccg, cmdLines);
+
+ if (cmdLines.empty()) {
+ cmNinjaBuild build("phony");
+ build.Comment = "Phony custom command for " + ninjaOutputs[0];
+ build.Outputs = std::move(ninjaOutputs);
+ build.ExplicitDeps = std::move(ninjaDeps);
+ build.OrderOnlyDeps = orderOnlyDeps;
+ gg->WriteBuild(this->GetImplFileStream(fileConfig), build);
+ } else {
+ std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
+ // Hash full path to make unique.
+ customStep += '-';
+ cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
+ customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
+
+ std::string depfile = cc->GetDepfile();
+ if (!depfile.empty()) {
+ switch (this->GetPolicyStatus(cmPolicies::CMP0116)) {
+ case cmPolicies::WARN:
+ if (this->GetCurrentBinaryDirectory() !=
+ this->GetBinaryDirectory() ||
+ this->Makefile->PolicyOptionalWarningEnabled(
+ "CMAKE_POLICY_WARNING_CMP0116")) {
+ this->GetCMakeInstance()->IssueMessage(
+ MessageType::AUTHOR_WARNING,
+ cmPolicies::GetPolicyWarning(cmPolicies::CMP0116),
+ cc->GetBacktrace());
+ }
+ CM_FALLTHROUGH;
+ case cmPolicies::OLD:
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ cmSystemTools::MakeDirectory(
+ cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d"));
+ depfile = ccg.GetInternalDepfile();
+ break;
+ }
+ }
+
+ gg->WriteCustomCommandBuild(
+ this->BuildCommandLine(cmdLines, customStep),
+ this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
+ depfile, cc->GetJobPool(), cc->GetUsesTerminal(),
+ /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, fileConfig,
+ ninjaDeps, orderOnlyDeps);
+ }
+ }
+}
+
+namespace {
+bool HasUniqueByproducts(cmLocalGenerator& lg,
+ std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt)
+{
+ std::vector<std::string> configs =
+ lg.GetMakefile()->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig);
+ cmGeneratorExpression ge(bt);
+ for (std::string const& p : byproducts) {
+ if (cmGeneratorExpression::Find(p) == std::string::npos) {
+ return false;
+ }
+ std::set<std::string> seen;
+ std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(p);
+ for (std::string const& config : configs) {
+ for (std::string const& b :
+ lg.ExpandCustomCommandOutputPaths(*cge, config)) {
+ if (!seen.insert(b).second) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool HasUniqueOutputs(std::vector<cmCustomCommandGenerator> const& ccgs)
+{
+ std::set<std::string> allOutputs;
+ std::set<std::string> allByproducts;
+ for (cmCustomCommandGenerator const& ccg : ccgs) {
+ for (std::string const& output : ccg.GetOutputs()) {
+ if (!allOutputs.insert(output).second) {
+ return false;
+ }
+ }
+ for (std::string const& byproduct : ccg.GetByproducts()) {
+ if (!allByproducts.insert(byproduct).second) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+}
+
+std::string cmLocalNinjaGenerator::CreateUtilityOutput(
+ std::string const& targetName, std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt)
+{
+ // In Ninja Multi-Config, we can only produce cross-config utility
+ // commands if all byproducts are per-config.
+ if (!this->GetGlobalGenerator()->IsMultiConfig() ||
+ !HasUniqueByproducts(*this, byproducts, bt)) {
+ return this->cmLocalGenerator::CreateUtilityOutput(targetName, byproducts,
+ bt);
+ }
+
+ std::string const base = cmStrCat(this->GetCurrentBinaryDirectory(),
+ "/CMakeFiles/", targetName, '-');
+ // The output is not actually created so mark it symbolic.
+ for (std::string const& config :
+ this->Makefile->GetGeneratorConfigs(cmMakefile::IncludeEmptyConfig)) {
+ std::string const force = cmStrCat(base, config);
+ if (cmSourceFile* sf = this->Makefile->GetOrCreateGeneratedSource(force)) {
+ sf->SetProperty("SYMBOLIC", "1");
+ } else {
+ cmSystemTools::Error("Could not get source file entry for " + force);
+ }
+ }
+ this->GetGlobalNinjaGenerator()->AddPerConfigUtilityTarget(targetName);
+ return cmStrCat(base, "$<CONFIG>"_s);
+}
+
+std::vector<cmCustomCommandGenerator>
+cmLocalNinjaGenerator::MakeCustomCommandGenerators(
+ cmCustomCommand const& cc, std::string const& fileConfig)
+{
+ cmGlobalNinjaGenerator const* gg = this->GetGlobalNinjaGenerator();
+
bool transformDepfile = false;
- auto cmp0116 = this->GetPolicyStatus(cmPolicies::CMP0116);
- switch (cmp0116) {
+ switch (this->GetPolicyStatus(cmPolicies::CMP0116)) {
case cmPolicies::OLD:
case cmPolicies::WARN:
break;
@@ -588,84 +781,41 @@ void cmLocalNinjaGenerator::WriteCustomCommandBuildStatement(
break;
}
- cmCustomCommandGenerator ccg(*cc, config, this, transformDepfile);
+ // Start with the build graph's configuration.
+ std::vector<cmCustomCommandGenerator> ccgs;
+ ccgs.emplace_back(cc, fileConfig, this, transformDepfile);
- const std::vector<std::string>& outputs = ccg.GetOutputs();
- const std::vector<std::string>& byproducts = ccg.GetByproducts();
-
- bool symbolic = false;
- for (std::string const& output : outputs) {
- if (cmSourceFile* sf = this->Makefile->GetSource(output)) {
- if (sf->GetPropertyAsBool("SYMBOLIC")) {
- symbolic = true;
- break;
- }
- }
+ // Consider adding cross configurations.
+ if (!gg->EnableCrossConfigBuild()) {
+ return ccgs;
}
- cmNinjaDeps ninjaOutputs(outputs.size() + byproducts.size());
- std::transform(outputs.begin(), outputs.end(), ninjaOutputs.begin(),
- gg->MapToNinjaPath());
- std::transform(byproducts.begin(), byproducts.end(),
- ninjaOutputs.begin() + outputs.size(), gg->MapToNinjaPath());
-
- for (std::string const& ninjaOutput : ninjaOutputs) {
- gg->SeenCustomCommandOutput(ninjaOutput);
+ // Outputs and byproducts must be expressed using generator expressions.
+ for (std::string const& output : cc.GetOutputs()) {
+ if (cmGeneratorExpression::Find(output) == std::string::npos) {
+ return ccgs;
+ }
+ }
+ for (std::string const& byproduct : cc.GetByproducts()) {
+ if (cmGeneratorExpression::Find(byproduct) == std::string::npos) {
+ return ccgs;
+ }
}
- cmNinjaDeps ninjaDeps;
- this->AppendCustomCommandDeps(ccg, ninjaDeps, config);
-
- std::vector<std::string> cmdLines;
- this->AppendCustomCommandLines(ccg, cmdLines);
-
- if (cmdLines.empty()) {
- cmNinjaBuild build("phony");
- build.Comment = "Phony custom command for " + ninjaOutputs[0];
- build.Outputs = std::move(ninjaOutputs);
- build.ExplicitDeps = std::move(ninjaDeps);
- build.OrderOnlyDeps = orderOnlyDeps;
- gg->WriteBuild(this->GetImplFileStream(config), build);
- } else {
- std::string customStep = cmSystemTools::GetFilenameName(ninjaOutputs[0]);
- // Hash full path to make unique.
- customStep += '-';
- cmCryptoHash hash(cmCryptoHash::AlgoSHA256);
- customStep += hash.HashString(ninjaOutputs[0]).substr(0, 7);
-
- std::string depfile = cc->GetDepfile();
- if (!depfile.empty()) {
- switch (cmp0116) {
- case cmPolicies::WARN:
- if (this->GetCurrentBinaryDirectory() !=
- this->GetBinaryDirectory() ||
- this->Makefile->PolicyOptionalWarningEnabled(
- "CMAKE_POLICY_WARNING_CMP0116")) {
- this->GetCMakeInstance()->IssueMessage(
- MessageType::AUTHOR_WARNING,
- cmPolicies::GetPolicyWarning(cmPolicies::CMP0116),
- cc->GetBacktrace());
- }
- CM_FALLTHROUGH;
- case cmPolicies::OLD:
- break;
- case cmPolicies::REQUIRED_IF_USED:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::NEW:
- cmSystemTools::MakeDirectory(
- cmStrCat(this->GetBinaryDirectory(), "/CMakeFiles/d"));
- depfile = ccg.GetInternalDepfile();
- break;
- }
+ // Tentatively add the other cross configurations.
+ for (std::string const& config : gg->GetCrossConfigs(fileConfig)) {
+ if (fileConfig != config) {
+ ccgs.emplace_back(cc, fileConfig, this, transformDepfile, config);
}
+ }
- gg->WriteCustomCommandBuild(
- this->BuildCommandLine(cmdLines, customStep),
- this->ConstructComment(ccg), "Custom command for " + ninjaOutputs[0],
- depfile, cc->GetJobPool(), cc->GetUsesTerminal(),
- /*restat*/ !symbolic || !byproducts.empty(), ninjaOutputs, config,
- ninjaDeps, orderOnlyDeps);
+ // If outputs and byproducts are not unique to each configuration,
+ // drop the cross configurations.
+ if (!HasUniqueOutputs(ccgs)) {
+ ccgs.erase(ccgs.begin() + 1, ccgs.end());
}
+
+ return ccgs;
}
void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
@@ -681,42 +831,13 @@ void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc,
}
void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements(
- const std::string& config)
+ const std::string& fileConfig)
{
for (cmCustomCommand const* customCommand : this->CustomCommands) {
auto i = this->CustomCommandTargets.find(customCommand);
assert(i != this->CustomCommandTargets.end());
- // A custom command may appear on multiple targets. However, some build
- // systems exist where the target dependencies on some of the targets are
- // overspecified, leading to a dependency cycle. If we assume all target
- // dependencies are a superset of the true target dependencies for this
- // custom command, we can take the set intersection of all target
- // dependencies to obtain a correct dependency list.
- //
- // FIXME: This won't work in certain obscure scenarios involving indirect
- // dependencies.
- auto j = i->second.begin();
- assert(j != i->second.end());
- std::vector<std::string> ccTargetDeps;
- this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(
- *j, ccTargetDeps, config);
- std::sort(ccTargetDeps.begin(), ccTargetDeps.end());
- ++j;
-
- for (; j != i->second.end(); ++j) {
- std::vector<std::string> jDeps;
- std::vector<std::string> depsIntersection;
- this->GetGlobalNinjaGenerator()->AppendTargetDependsClosure(*j, jDeps,
- config);
- std::sort(jDeps.begin(), jDeps.end());
- std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(),
- jDeps.begin(), jDeps.end(),
- std::back_inserter(depsIntersection));
- ccTargetDeps = depsIntersection;
- }
-
- this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps, config);
+ this->WriteCustomCommandBuildStatement(i->first, i->second, fileConfig);
}
}
diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h
index e81402c..87d5e53 100644
--- a/Source/cmLocalNinjaGenerator.h
+++ b/Source/cmLocalNinjaGenerator.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "cmListFileCache.h"
#include "cmLocalCommonGenerator.h"
#include "cmNinjaTypes.h"
#include "cmOutputConverter.h"
@@ -70,6 +71,13 @@ public:
const std::string& fileConfig,
cmNinjaTargetDepends depends);
+ std::string CreateUtilityOutput(std::string const& targetName,
+ std::vector<std::string> const& byproducts,
+ cmListFileBacktrace const& bt) override;
+
+ std::vector<cmCustomCommandGenerator> MakeCustomCommandGenerators(
+ cmCustomCommand const& cc, std::string const& config) override;
+
void AddCustomCommandTarget(cmCustomCommand const* cc,
cmGeneratorTarget* target);
void AppendCustomCommandLines(cmCustomCommandGenerator const& ccg,
@@ -99,9 +107,9 @@ private:
void WriteProcessedMakefile(std::ostream& os);
void WritePools(std::ostream& os);
- void WriteCustomCommandBuildStatement(cmCustomCommand const* cc,
- const cmNinjaDeps& orderOnlyDeps,
- const std::string& config);
+ void WriteCustomCommandBuildStatement(
+ cmCustomCommand const* cc, const std::set<cmGeneratorTarget*>& targets,
+ const std::string& config);
void WriteCustomCommandBuildStatements(const std::string& config);
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 4e93785..028688d 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -1257,27 +1257,6 @@ void cmMakefile::AppendCustomCommandToOutput(
}
}
-cmUtilityOutput cmMakefile::GetUtilityOutput(cmTarget* target)
-{
- std::string force = cmStrCat(this->GetCurrentBinaryDirectory(),
- "/CMakeFiles/", target->GetName());
- std::string forceCMP0049 = target->GetSourceCMP0049(force);
- {
- cmSourceFile* sf = nullptr;
- if (!forceCMP0049.empty()) {
- sf = this->GetOrCreateSource(forceCMP0049, false,
- cmSourceFileLocationKind::Known);
- }
- // The output is not actually created so mark it symbolic.
- if (sf) {
- sf->SetProperty("SYMBOLIC", "1");
- } else {
- cmSystemTools::Error("Could not get source file entry for " + force);
- }
- }
- return { std::move(force), std::move(forceCMP0049) };
-}
-
cmTarget* cmMakefile::AddUtilityCommand(
const std::string& utilityName, bool excludeFromAll, const char* workingDir,
const std::vector<std::string>& byproducts,
@@ -1294,10 +1273,6 @@ cmTarget* cmMakefile::AddUtilityCommand(
return target;
}
- // Get the output name of the utility target and mark it generated.
- cmUtilityOutput force = this->GetUtilityOutput(target);
- this->GetOrCreateGeneratedSource(force.Name);
-
// Always create the byproduct sources and mark them generated.
this->CreateGeneratedOutputs(byproducts);
@@ -1310,8 +1285,8 @@ cmTarget* cmMakefile::AddUtilityCommand(
[=](cmLocalGenerator& lg, const cmListFileBacktrace& lfbt) {
BacktraceGuard guard(this->Backtrace, lfbt);
detail::AddUtilityCommand(lg, lfbt, cmCommandOrigin::Project, target,
- force, GetCStrOrNull(workingStr), byproducts,
- depends, commandLines, escapeOldStyle,
+ GetCStrOrNull(workingStr), byproducts, depends,
+ commandLines, escapeOldStyle,
GetCStrOrNull(commentStr), uses_terminal,
command_expand_lists, job_pool, stdPipesUTF8);
});
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index a864074..f18f70c 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -243,11 +243,6 @@ public:
bool excludeFromAll = false);
/**
- * Return the utility target output source file name and the CMP0049 name.
- */
- cmUtilityOutput GetUtilityOutput(cmTarget* target);
-
- /**
* Dispatch adding a utility to the build. A utility target is a command
* that is run every time the target is built.
*/
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
index ad1d5f1..0b62e16 100644
--- a/Source/cmNinjaUtilityTargetGenerator.cxx
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -5,6 +5,7 @@
#include <algorithm>
#include <array>
#include <iterator>
+#include <set>
#include <string>
#include <utility>
#include <vector>
@@ -34,13 +35,30 @@ cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
{
+ for (auto const& fileConfig : this->GetConfigNames()) {
+ if (!this->GetGlobalGenerator()
+ ->GetCrossConfigs(fileConfig)
+ .count(config)) {
+ continue;
+ }
+ if (fileConfig != config &&
+ this->GetGeneratorTarget()->GetType() == cmStateEnums::GLOBAL_TARGET) {
+ continue;
+ }
+ this->WriteUtilBuildStatements(config, fileConfig);
+ }
+}
+
+void cmNinjaUtilityTargetGenerator::WriteUtilBuildStatements(
+ std::string const& config, std::string const& fileConfig)
+{
cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
std::string configDir;
if (genTarget->Target->IsPerConfig()) {
- configDir = gg->ConfigDirectory(config);
+ configDir = gg->ConfigDirectory(fileConfig);
}
std::string utilCommandName =
cmStrCat(lg->GetCurrentBinaryDirectory(), "/CMakeFiles", configDir, "/",
@@ -60,8 +78,8 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
for (cmCustomCommand const& ci : *cmdList) {
- cmCustomCommandGenerator ccg(ci, config, lg);
- lg->AppendCustomCommandDeps(ccg, deps, config);
+ cmCustomCommandGenerator ccg(ci, fileConfig, lg);
+ lg->AppendCustomCommandDeps(ccg, deps, fileConfig);
lg->AppendCustomCommandLines(ccg, commands);
std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
std::transform(ccByproducts.begin(), ccByproducts.end(),
@@ -103,13 +121,19 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
std::copy(util_outputs.begin(), util_outputs.end(),
std::back_inserter(gg->GetByproductsForCleanTarget()));
}
- lg->AppendTargetDepends(genTarget, deps, config, config,
+ // TODO: Does this need an output config?
+ // Does this need to go in impl-<config>.ninja?
+ lg->AppendTargetDepends(genTarget, deps, config, fileConfig,
DependOnTargetArtifact);
if (commands.empty()) {
phonyBuild.Comment = "Utility command for " + this->GetTargetName();
phonyBuild.ExplicitDeps = std::move(deps);
- gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild);
+ } else {
+ gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+ }
} else {
std::string command =
lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
@@ -145,15 +169,22 @@ void cmNinjaUtilityTargetGenerator::Generate(const std::string& config)
std::string ccConfig;
if (genTarget->Target->IsPerConfig() &&
genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
- ccConfig = config;
+ ccConfig = fileConfig;
+ }
+ if (config == fileConfig ||
+ gg->GetPerConfigUtilityTargets().count(genTarget->GetName())) {
+ gg->WriteCustomCommandBuild(
+ command, desc, "Utility command for " + this->GetTargetName(),
+ /*depfile*/ "", /*job_pool*/ "", uses_terminal,
+ /*restat*/ true, util_outputs, ccConfig, deps);
}
- gg->WriteCustomCommandBuild(command, desc,
- "Utility command for " + this->GetTargetName(),
- /*depfile*/ "", /*job_pool*/ "", uses_terminal,
- /*restat*/ true, util_outputs, ccConfig, deps);
phonyBuild.ExplicitDeps.push_back(utilCommandName);
- gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+ if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ gg->WriteBuild(this->GetImplFileStream(fileConfig), phonyBuild);
+ } else {
+ gg->WriteBuild(this->GetCommonFileStream(), phonyBuild);
+ }
}
// Find ADDITIONAL_CLEAN_FILES
diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h
index 24b47f8..dbd3797 100644
--- a/Source/cmNinjaUtilityTargetGenerator.h
+++ b/Source/cmNinjaUtilityTargetGenerator.h
@@ -17,4 +17,8 @@ public:
~cmNinjaUtilityTargetGenerator() override;
void Generate(const std::string& config) override;
+
+private:
+ void WriteUtilBuildStatements(std::string const& config,
+ std::string const& fileConfig);
};