diff options
author | Kyle Edwards <kyle.edwards@kitware.com> | 2020-12-09 21:39:15 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2020-12-15 12:01:21 (GMT) |
commit | dcf9f4d2f71d7c608ce24b690d30d465df51dc71 (patch) | |
tree | 0868f3cd8176eb883063a77350864b70782b2dad /Source/cmCustomCommandGenerator.cxx | |
parent | 15467f12f796205f97721f43ae7d9ee7cdc47466 (diff) | |
download | CMake-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.cxx | 132 |
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; } |