summaryrefslogtreecommitdiffstats
path: root/Source/cmNinjaUtilityTargetGenerator.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmNinjaUtilityTargetGenerator.cxx')
-rw-r--r--Source/cmNinjaUtilityTargetGenerator.cxx150
1 files changed, 150 insertions, 0 deletions
diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx
new file mode 100644
index 0000000..95fcf66
--- /dev/null
+++ b/Source/cmNinjaUtilityTargetGenerator.cxx
@@ -0,0 +1,150 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmNinjaUtilityTargetGenerator.h"
+
+#include "cmCustomCommand.h"
+#include "cmCustomCommandGenerator.h"
+#include "cmGeneratedFileStream.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalNinjaGenerator.h"
+#include "cmLocalNinjaGenerator.h"
+#include "cmMakefile.h"
+#include "cmNinjaTypes.h"
+#include "cmOutputConverter.h"
+#include "cmSourceFile.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <vector>
+
+cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
+ cmGeneratorTarget* target)
+ : cmNinjaTargetGenerator(target)
+{
+}
+
+cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
+
+void cmNinjaUtilityTargetGenerator::Generate()
+{
+ std::string utilCommandName =
+ this->GetLocalGenerator()->GetCurrentBinaryDirectory();
+ utilCommandName += "/CMakeFiles";
+ utilCommandName += "/";
+ utilCommandName += this->GetTargetName() + ".util";
+ utilCommandName = this->ConvertToNinjaPath(utilCommandName);
+
+ std::vector<std::string> commands;
+ cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName);
+
+ const std::vector<cmCustomCommand>* cmdLists[2] = {
+ &this->GetGeneratorTarget()->GetPreBuildCommands(),
+ &this->GetGeneratorTarget()->GetPostBuildCommands()
+ };
+
+ bool uses_terminal = false;
+
+ for (unsigned i = 0; i != 2; ++i) {
+ for (cmCustomCommand const& ci : *cmdLists[i]) {
+ cmCustomCommandGenerator ccg(ci, this->GetConfigName(),
+ this->GetLocalGenerator());
+ this->GetLocalGenerator()->AppendCustomCommandDeps(ccg, deps);
+ this->GetLocalGenerator()->AppendCustomCommandLines(ccg, commands);
+ std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(util_outputs), MapToNinjaPath());
+ if (ci.GetUsesTerminal()) {
+ uses_terminal = true;
+ }
+ }
+ }
+
+ std::vector<cmSourceFile*> sources;
+ std::string config =
+ this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
+ this->GetGeneratorTarget()->GetSourceFiles(sources, config);
+ for (cmSourceFile const* source : sources) {
+ if (cmCustomCommand const* cc = source->GetCustomCommand()) {
+ cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
+ this->GetLocalGenerator());
+ this->GetLocalGenerator()->AddCustomCommandTarget(
+ cc, this->GetGeneratorTarget());
+
+ // Depend on all custom command outputs.
+ const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
+ const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
+ std::transform(ccOutputs.begin(), ccOutputs.end(),
+ std::back_inserter(deps), MapToNinjaPath());
+ std::transform(ccByproducts.begin(), ccByproducts.end(),
+ std::back_inserter(deps), MapToNinjaPath());
+ }
+ }
+
+ this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
+ outputs);
+ this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
+ deps);
+
+ if (commands.empty()) {
+ this->GetGlobalGenerator()->WritePhonyBuild(
+ this->GetBuildFileStream(),
+ "Utility command for " + this->GetTargetName(), outputs, deps);
+ } else {
+ std::string command = this->GetLocalGenerator()->BuildCommandLine(
+ commands, "utility", this->GeneratorTarget);
+ const char* echoStr =
+ this->GetGeneratorTarget()->GetProperty("EchoString");
+ std::string desc;
+ if (echoStr) {
+ desc = echoStr;
+ } else {
+ desc = "Running utility command for " + this->GetTargetName();
+ }
+
+ // TODO: fix problematic global targets. For now, search and replace the
+ // makefile vars.
+ cmSystemTools::ReplaceString(
+ command, "$(CMAKE_SOURCE_DIR)",
+ this->GetLocalGenerator()
+ ->ConvertToOutputFormat(
+ this->GetLocalGenerator()->GetSourceDirectory(),
+ cmOutputConverter::SHELL)
+ .c_str());
+ cmSystemTools::ReplaceString(
+ command, "$(CMAKE_BINARY_DIR)",
+ this->GetLocalGenerator()
+ ->ConvertToOutputFormat(
+ this->GetLocalGenerator()->GetBinaryDirectory(),
+ cmOutputConverter::SHELL)
+ .c_str());
+ cmSystemTools::ReplaceString(command, "$(ARGS)", "");
+
+ if (command.find('$') != std::string::npos) {
+ return;
+ }
+
+ for (std::string const& util_output : util_outputs) {
+ this->GetGlobalGenerator()->SeenCustomCommandOutput(util_output);
+ }
+
+ this->GetGlobalGenerator()->WriteCustomCommandBuild(
+ command, desc, "Utility command for " + this->GetTargetName(),
+ /*depfile*/ "", uses_terminal,
+ /*restat*/ true, util_outputs, deps);
+
+ this->GetGlobalGenerator()->WritePhonyBuild(
+ this->GetBuildFileStream(), "", outputs,
+ cmNinjaDeps(1, utilCommandName));
+ }
+
+ // Add an alias for the logical target name regardless of what directory
+ // contains it. Skip this for GLOBAL_TARGET because they are meant to
+ // be per-directory and have one at the top-level anyway.
+ if (this->GetGeneratorTarget()->GetType() != cmStateEnums::GLOBAL_TARGET) {
+ this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
+ this->GetGeneratorTarget());
+ }
+}