cmCustomCommandGenerator.cxx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  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 "cmCustomCommandGenerator.h"
  4. #include "cmCustomCommand.h"
  5. #include "cmCustomCommandLines.h"
  6. #include "cmGeneratorExpression.h"
  7. #include "cmGeneratorTarget.h"
  8. #include "cmLocalGenerator.h"
  9. #include "cmMakefile.h"
  10. #include "cmOutputConverter.h"
  11. #include "cmStateTypes.h"
  12. #include "cmSystemTools.h"
  13. #include "cm_auto_ptr.hxx"
  14. #include <stddef.h>
  15. cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc,
  16. const std::string& config,
  17. cmLocalGenerator* lg)
  18. : CC(cc)
  19. , Config(config)
  20. , LG(lg)
  21. , OldStyle(cc.GetEscapeOldStyle())
  22. , MakeVars(cc.GetEscapeAllowMakeVars())
  23. , GE(new cmGeneratorExpression(cc.GetBacktrace()))
  24. {
  25. const cmCustomCommandLines& cmdlines = this->CC.GetCommandLines();
  26. for (cmCustomCommandLines::const_iterator cmdline = cmdlines.begin();
  27. cmdline != cmdlines.end(); ++cmdline) {
  28. cmCustomCommandLine argv;
  29. for (cmCustomCommandLine::const_iterator clarg = cmdline->begin();
  30. clarg != cmdline->end(); ++clarg) {
  31. CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(*clarg);
  32. std::string parsed_arg = cge->Evaluate(this->LG, this->Config);
  33. if (this->CC.GetCommandExpandLists()) {
  34. std::vector<std::string> ExpandedArg;
  35. cmSystemTools::ExpandListArgument(parsed_arg, ExpandedArg);
  36. argv.insert(argv.end(), ExpandedArg.begin(), ExpandedArg.end());
  37. } else {
  38. argv.push_back(parsed_arg);
  39. }
  40. }
  41. this->CommandLines.push_back(argv);
  42. }
  43. std::vector<std::string> depends = this->CC.GetDepends();
  44. for (std::vector<std::string>::const_iterator i = depends.begin();
  45. i != depends.end(); ++i) {
  46. CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = this->GE->Parse(*i);
  47. std::vector<std::string> result;
  48. cmSystemTools::ExpandListArgument(cge->Evaluate(this->LG, this->Config),
  49. result);
  50. for (std::vector<std::string>::iterator it = result.begin();
  51. it != result.end(); ++it) {
  52. if (cmSystemTools::FileIsFullPath(it->c_str())) {
  53. *it = cmSystemTools::CollapseFullPath(*it);
  54. }
  55. }
  56. this->Depends.insert(this->Depends.end(), result.begin(), result.end());
  57. }
  58. }
  59. cmCustomCommandGenerator::~cmCustomCommandGenerator()
  60. {
  61. delete this->GE;
  62. }
  63. unsigned int cmCustomCommandGenerator::GetNumberOfCommands() const
  64. {
  65. return static_cast<unsigned int>(this->CC.GetCommandLines().size());
  66. }
  67. const char* cmCustomCommandGenerator::GetCrossCompilingEmulator(
  68. unsigned int c) const
  69. {
  70. if (!this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING")) {
  71. return nullptr;
  72. }
  73. std::string const& argv0 = this->CommandLines[c][0];
  74. cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
  75. if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
  76. !target->IsImported()) {
  77. return target->GetProperty("CROSSCOMPILING_EMULATOR");
  78. }
  79. return nullptr;
  80. }
  81. const char* cmCustomCommandGenerator::GetArgv0Location(unsigned int c) const
  82. {
  83. std::string const& argv0 = this->CommandLines[c][0];
  84. cmGeneratorTarget* target = this->LG->FindGeneratorTargetToUse(argv0);
  85. if (target && target->GetType() == cmStateEnums::EXECUTABLE &&
  86. (target->IsImported() ||
  87. target->GetProperty("CROSSCOMPILING_EMULATOR") ||
  88. !this->LG->GetMakefile()->IsOn("CMAKE_CROSSCOMPILING"))) {
  89. return target->GetLocation(this->Config);
  90. }
  91. return nullptr;
  92. }
  93. bool cmCustomCommandGenerator::HasOnlyEmptyCommandLines() const
  94. {
  95. for (size_t i = 0; i < this->CommandLines.size(); ++i) {
  96. for (size_t j = 0; j < this->CommandLines[i].size(); ++j) {
  97. if (!this->CommandLines[i][j].empty()) {
  98. return false;
  99. }
  100. }
  101. }
  102. return true;
  103. }
  104. std::string cmCustomCommandGenerator::GetCommand(unsigned int c) const
  105. {
  106. if (const char* emulator = this->GetCrossCompilingEmulator(c)) {
  107. return std::string(emulator);
  108. }
  109. if (const char* location = this->GetArgv0Location(c)) {
  110. return std::string(location);
  111. }
  112. return this->CommandLines[c][0];
  113. }
  114. std::string escapeForShellOldStyle(const std::string& str)
  115. {
  116. std::string result;
  117. #if defined(_WIN32) && !defined(__CYGWIN__)
  118. // if there are spaces
  119. std::string temp = str;
  120. if (temp.find(" ") != std::string::npos &&
  121. temp.find("\"") == std::string::npos) {
  122. result = "\"";
  123. result += str;
  124. result += "\"";
  125. return result;
  126. }
  127. return str;
  128. #else
  129. for (const char* ch = str.c_str(); *ch != '\0'; ++ch) {
  130. if (*ch == ' ') {
  131. result += '\\';
  132. }
  133. result += *ch;
  134. }
  135. return result;
  136. #endif
  137. }
  138. void cmCustomCommandGenerator::AppendArguments(unsigned int c,
  139. std::string& cmd) const
  140. {
  141. unsigned int offset = 1;
  142. if (this->GetCrossCompilingEmulator(c) != nullptr) {
  143. offset = 0;
  144. }
  145. cmCustomCommandLine const& commandLine = this->CommandLines[c];
  146. for (unsigned int j = offset; j < commandLine.size(); ++j) {
  147. std::string arg;
  148. if (const char* location = j == 0 ? this->GetArgv0Location(c) : nullptr) {
  149. // GetCommand returned the emulator instead of the argv0 location,
  150. // so transform the latter now.
  151. arg = location;
  152. } else {
  153. arg = commandLine[j];
  154. }
  155. cmd += " ";
  156. if (this->OldStyle) {
  157. cmd += escapeForShellOldStyle(arg);
  158. } else {
  159. cmOutputConverter converter(this->LG->GetStateSnapshot());
  160. cmd += converter.EscapeForShell(arg, this->MakeVars);
  161. }
  162. }
  163. }
  164. const char* cmCustomCommandGenerator::GetComment() const
  165. {
  166. return this->CC.GetComment();
  167. }
  168. std::string cmCustomCommandGenerator::GetWorkingDirectory() const
  169. {
  170. return this->CC.GetWorkingDirectory();
  171. }
  172. std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const
  173. {
  174. return this->CC.GetOutputs();
  175. }
  176. std::vector<std::string> const& cmCustomCommandGenerator::GetByproducts() const
  177. {
  178. return this->CC.GetByproducts();
  179. }
  180. std::vector<std::string> const& cmCustomCommandGenerator::GetDepends() const
  181. {
  182. return this->Depends;
  183. }