cmNinjaUtilityTargetGenerator.cxx 5.67 KB
Newer Older
1 2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3
#include "cmNinjaUtilityTargetGenerator.h"
Brad King's avatar
Brad King committed
4

5
#include "cmCustomCommand.h"
6
#include "cmCustomCommandGenerator.h"
7
#include "cmGeneratedFileStream.h"
8
#include "cmGeneratorTarget.h"
9
#include "cmGlobalNinjaGenerator.h"
10
#include "cmLocalNinjaGenerator.h"
11
#include "cmMakefile.h"
12 13
#include "cmNinjaTypes.h"
#include "cmOutputConverter.h"
14
#include "cmSourceFile.h"
15
#include "cmStateTypes.h"
16 17 18 19 20 21 22
#include "cmSystemTools.h"
#include "cmake.h"

#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
23

24
cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(
25 26 27 28
  cmGeneratorTarget* target)
  : cmNinjaTargetGenerator(target)
{
}
29

30 31 32
cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator()
{
}
33 34 35

void cmNinjaUtilityTargetGenerator::Generate()
{
36 37 38 39
  std::string utilCommandName =
    this->GetLocalGenerator()->GetCurrentBinaryDirectory();
  utilCommandName += cmake::GetCMakeFilesDirectory();
  utilCommandName += "/";
40
  utilCommandName += this->GetTargetName() + ".util";
41
  utilCommandName = this->ConvertToNinjaPath(utilCommandName);
42

43
  std::vector<std::string> commands;
44
  cmNinjaDeps deps, outputs, util_outputs(1, utilCommandName);
45

46
  const std::vector<cmCustomCommand>* cmdLists[2] = {
47 48
    &this->GetGeneratorTarget()->GetPreBuildCommands(),
    &this->GetGeneratorTarget()->GetPostBuildCommands()
49 50
  };

51 52
  bool uses_terminal = false;

53
  for (unsigned i = 0; i != 2; ++i) {
54 55 56
    for (std::vector<cmCustomCommand>::const_iterator ci =
           cmdLists[i]->begin();
         ci != cmdLists[i]->end(); ++ci) {
57
      cmCustomCommandGenerator ccg(*ci, this->GetConfigName(),
58
                                   this->GetLocalGenerator());
59 60
      this->GetLocalGenerator()->AppendCustomCommandDeps(ccg, deps);
      this->GetLocalGenerator()->AppendCustomCommandLines(ccg, commands);
61 62 63
      std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
      std::transform(ccByproducts.begin(), ccByproducts.end(),
                     std::back_inserter(util_outputs), MapToNinjaPath());
64
      if (ci->GetUsesTerminal()) {
65
        uses_terminal = true;
66
      }
67 68 69
    }
  }

70
  std::vector<cmSourceFile*> sources;
71 72
  std::string config =
    this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE");
73
  this->GetGeneratorTarget()->GetSourceFiles(sources, config);
74 75 76
  for (std::vector<cmSourceFile*>::const_iterator source = sources.begin();
       source != sources.end(); ++source) {
    if (cmCustomCommand* cc = (*source)->GetCustomCommand()) {
77
      cmCustomCommandGenerator ccg(*cc, this->GetConfigName(),
78
                                   this->GetLocalGenerator());
79 80
      this->GetLocalGenerator()->AddCustomCommandTarget(
        cc, this->GetGeneratorTarget());
81 82

      // Depend on all custom command outputs.
83
      const std::vector<std::string>& ccOutputs = ccg.GetOutputs();
84
      const std::vector<std::string>& ccByproducts = ccg.GetByproducts();
85
      std::transform(ccOutputs.begin(), ccOutputs.end(),
86
                     std::back_inserter(deps), MapToNinjaPath());
87 88
      std::transform(ccByproducts.begin(), ccByproducts.end(),
                     std::back_inserter(deps), MapToNinjaPath());
89
    }
90
  }
91

92 93 94 95
  this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
                                                 outputs);
  this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
                                                 deps);
96 97

  if (commands.empty()) {
98 99 100
    this->GetGlobalGenerator()->WritePhonyBuild(
      this->GetBuildFileStream(),
      "Utility command for " + this->GetTargetName(), outputs, deps);
101 102 103
  } else {
    std::string command =
      this->GetLocalGenerator()->BuildCommandLine(commands);
104 105
    const char* echoStr =
      this->GetGeneratorTarget()->GetProperty("EchoString");
106
    std::string desc;
107
    if (echoStr) {
108
      desc = echoStr;
109
    } else {
110
      desc = "Running utility command for " + this->GetTargetName();
111
    }
112 113 114

    // TODO: fix problematic global targets.  For now, search and replace the
    // makefile vars.
115
    cmSystemTools::ReplaceString(
116 117 118 119
      command, "$(CMAKE_SOURCE_DIR)",
      this->GetLocalGenerator()
        ->ConvertToOutputFormat(
          this->GetLocalGenerator()->GetSourceDirectory(),
120
          cmOutputConverter::SHELL)
121
        .c_str());
122
    cmSystemTools::ReplaceString(
123 124 125 126
      command, "$(CMAKE_BINARY_DIR)",
      this->GetLocalGenerator()
        ->ConvertToOutputFormat(
          this->GetLocalGenerator()->GetBinaryDirectory(),
127
          cmOutputConverter::SHELL)
128
        .c_str());
129 130
    cmSystemTools::ReplaceString(command, "$(ARGS)", "");

131
    if (command.find('$') != std::string::npos) {
132
      return;
133
    }
134

135 136 137
    for (cmNinjaDeps::const_iterator oi = util_outputs.begin(),
                                     oe = util_outputs.end();
         oi != oe; ++oi) {
138
      this->GetGlobalGenerator()->SeenCustomCommandOutput(*oi);
139
    }
140 141

    this->GetGlobalGenerator()->WriteCustomCommandBuild(
142
      command, desc, "Utility command for " + this->GetTargetName(),
143
      /*depfile*/ "", uses_terminal,
144 145 146 147 148
      /*restat*/ true, util_outputs, deps);

    this->GetGlobalGenerator()->WritePhonyBuild(
      this->GetBuildFileStream(), "", outputs,
      cmNinjaDeps(1, utilCommandName));
149 150
  }

151 152 153
  // 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.
154
  if (this->GetGeneratorTarget()->GetType() != cmStateEnums::GLOBAL_TARGET) {
155 156 157
    this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
                                               this->GetGeneratorTarget());
  }
158
}