summaryrefslogtreecommitdiffstats
path: root/Source/cmCustomCommandGenerator.cxx
diff options
context:
space:
mode:
authorKyle Edwards <kyle.edwards@kitware.com>2020-12-09 21:39:15 (GMT)
committerBrad King <brad.king@kitware.com>2020-12-15 12:01:21 (GMT)
commitdcf9f4d2f71d7c608ce24b690d30d465df51dc71 (patch)
tree0868f3cd8176eb883063a77350864b70782b2dad /Source/cmCustomCommandGenerator.cxx
parent15467f12f796205f97721f43ae7d9ee7cdc47466 (diff)
downloadCMake-dcf9f4d2f71d7c608ce24b690d30d465df51dc71.zip
CMake-dcf9f4d2f71d7c608ce24b690d30d465df51dc71.tar.gz
CMake-dcf9f4d2f71d7c608ce24b690d30d465df51dc71.tar.bz2
Ninja Multi-Config: Add support for cross-config custom commands
Co-Author: Brad King <brad.king@kitware.com>
Diffstat (limited to 'Source/cmCustomCommandGenerator.cxx')
-rw-r--r--Source/cmCustomCommandGenerator.cxx132
1 files changed, 110 insertions, 22 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;
}