cmNinjaUtilityTargetGenerator.cxx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmNinjaUtilityTargetGenerator.h"
  4. #include "cmCustomCommand.h"
  5. #include "cmCustomCommandGenerator.h"
  6. #include "cmGeneratedFileStream.h"
  7. #include "cmGeneratorTarget.h"
  8. #include "cmGlobalNinjaGenerator.h"
  9. #include "cmLocalNinjaGenerator.h"
  10. #include "cmMakefile.h"
  11. #include "cmNinjaTypes.h"
  12. #include "cmOutputConverter.h"
  13. #include "cmSourceFile.h"
  14. #include "cmStateTypes.h"
  15. #include "cmSystemTools.h"
  16. #include <algorithm>
  17. #include <array>
  18. #include <iterator>
  19. #include <string>
  20. #include <utility>
  21. #include <vector>
  22. cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
  23. cmGeneratorTarget* target)
  24. : cmNinjaTargetGenerator(target)
  25. {
  26. }
  27. cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() = default;
  28. void cmNinjaUtilityTargetGenerator::Generate()
  29. {
  30. cmGlobalNinjaGenerator* gg = this->GetGlobalGenerator();
  31. cmLocalNinjaGenerator* lg = this->GetLocalGenerator();
  32. cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
  33. std::string utilCommandName = lg->GetCurrentBinaryDirectory();
  34. utilCommandName += "/CMakeFiles/";
  35. utilCommandName += this->GetTargetName() + ".util";
  36. utilCommandName = this->ConvertToNinjaPath(utilCommandName);
  37. cmNinjaBuild phonyBuild("phony");
  38. std::vector<std::string> commands;
  39. cmNinjaDeps deps;
  40. cmNinjaDeps util_outputs(1, utilCommandName);
  41. bool uses_terminal = false;
  42. {
  43. std::array<std::vector<cmCustomCommand> const*, 2> const cmdLists = {
  44. { &genTarget->GetPreBuildCommands(), &genTarget->GetPostBuildCommands() }
  45. };
  46. for (std::vector<cmCustomCommand> const* cmdList : cmdLists) {
  47. for (cmCustomCommand const& ci : *cmdList) {
  48. cmCustomCommandGenerator ccg(ci, this->GetConfigName(), lg);
  49. lg->AppendCustomCommandDeps(ccg, deps);
  50. lg->AppendCustomCommandLines(ccg, commands);
  51. std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
  52. std::transform(ccByproducts.begin(), ccByproducts.end(),
  53. std::back_inserter(util_outputs), MapToNinjaPath());
  54. if (ci.GetUsesTerminal()) {
  55. uses_terminal = true;
  56. }
  57. }
  58. }
  59. }
  60. {
  61. std::string const& config =
  62. this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
  63. std::vector<cmSourceFile*> sources;
  64. genTarget->GetSourceFiles(sources, config);
  65. for (cmSourceFile const* source : sources) {
  66. if (cmCustomCommand const* cc = source->GetCustomCommand()) {
  67. cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), lg);
  68. lg->AddCustomCommandTarget(cc, genTarget);
  69. // Depend on all custom command outputs.
  70. const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
  71. const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
  72. std::transform(ccOutputs.begin(), ccOutputs.end(),
  73. std::back_inserter(deps), MapToNinjaPath());
  74. std::transform(ccByproducts.begin(), ccByproducts.end(),
  75. std::back_inserter(deps), MapToNinjaPath());
  76. }
  77. }
  78. }
  79. lg->AppendTargetOutputs(genTarget, phonyBuild.Outputs);
  80. lg->AppendTargetDepends(genTarget, deps);
  81. if (commands.empty()) {
  82. phonyBuild.Comment = "Utility command for " + this->GetTargetName();
  83. phonyBuild.ExplicitDeps = std::move(deps);
  84. gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
  85. } else {
  86. std::string command =
  87. lg->BuildCommandLine(commands, "utility", this->GeneratorTarget);
  88. std::string desc;
  89. const char* echoStr = genTarget->GetProperty("EchoString");
  90. if (echoStr) {
  91. desc = echoStr;
  92. } else {
  93. desc = "Running utility command for " + this->GetTargetName();
  94. }
  95. // TODO: fix problematic global targets. For now, search and replace the
  96. // makefile vars.
  97. cmSystemTools::ReplaceString(
  98. command, "$(CMAKE_SOURCE_DIR)",
  99. lg->ConvertToOutputFormat(lg->GetSourceDirectory(),
  100. cmOutputConverter::SHELL));
  101. cmSystemTools::ReplaceString(
  102. command, "$(CMAKE_BINARY_DIR)",
  103. lg->ConvertToOutputFormat(lg->GetBinaryDirectory(),
  104. cmOutputConverter::SHELL));
  105. cmSystemTools::ReplaceString(command, "$(ARGS)", "");
  106. if (command.find('$') != std::string::npos) {
  107. return;
  108. }
  109. for (std::string const& util_output : util_outputs) {
  110. gg->SeenCustomCommandOutput(util_output);
  111. }
  112. gg->WriteCustomCommandBuild(command, desc,
  113. "Utility command for " + this->GetTargetName(),
  114. /*depfile*/ "", /*job_pool*/ "", uses_terminal,
  115. /*restat*/ true, util_outputs, deps);
  116. phonyBuild.ExplicitDeps.push_back(utilCommandName);
  117. gg->WriteBuild(this->GetBuildFileStream(), phonyBuild);
  118. }
  119. // Add an alias for the logical target name regardless of what directory
  120. // contains it. Skip this for GLOBAL_TARGET because they are meant to
  121. // be per-directory and have one at the top-level anyway.
  122. if (genTarget->GetType() != cmStateEnums::GLOBAL_TARGET) {
  123. gg->AddTargetAlias(this->GetTargetName(), genTarget);
  124. }
  125. }