cmGlobalNinjaGenerator.cxx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. /*============================================================================
  2. CMake - Cross Platform Makefile Generator
  3. Copyright 2011 Peter Collingbourne <[email protected]>
  4. Copyright 2011 Nicolas Despres <[email protected]>
  5. Distributed under the OSI-approved BSD License (the "License");
  6. see accompanying file Copyright.txt for details.
  7. This software is distributed WITHOUT ANY WARRANTY; without even the
  8. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. See the License for more information.
  10. ============================================================================*/
  11. #include "cmGlobalNinjaGenerator.h"
  12. #include "cmLocalNinjaGenerator.h"
  13. #include "cmMakefile.h"
  14. #include "cmGeneratedFileStream.h"
  15. #include "cmVersion.h"
  16. const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja";
  17. const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja";
  18. const char* cmGlobalNinjaGenerator::INDENT = " ";
  19. void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count)
  20. {
  21. for(int i = 0; i < count; ++i)
  22. os << cmGlobalNinjaGenerator::INDENT;
  23. }
  24. void cmGlobalNinjaGenerator::WriteDivider(std::ostream& os)
  25. {
  26. os
  27. << "# ======================================"
  28. << "=======================================\n";
  29. }
  30. void cmGlobalNinjaGenerator::WriteComment(std::ostream& os,
  31. const std::string& comment)
  32. {
  33. if (comment.empty())
  34. return;
  35. std::string replace = comment;
  36. std::string::size_type lpos = 0;
  37. std::string::size_type rpos;
  38. while((rpos = replace.find('\n', lpos)) != std::string::npos)
  39. {
  40. os << "# " << replace.substr(lpos, rpos - lpos) << "\n";
  41. lpos = rpos + 1;
  42. }
  43. os << "# " << replace.substr(lpos) << "\n";
  44. }
  45. static bool IsIdentChar(char c)
  46. {
  47. return
  48. ('a' <= c && c <= 'z') ||
  49. ('+' <= c && c <= '9') || // +,-./ and numbers
  50. ('A' <= c && c <= 'Z') ||
  51. (c == '_') || (c == '$') || (c == '\\') ||
  52. (c == ' ') || (c == ':');
  53. }
  54. std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string &ident,
  55. std::ostream &vars) {
  56. if (std::find_if(ident.begin(), ident.end(),
  57. std::not1(std::ptr_fun(IsIdentChar))) != ident.end()) {
  58. static unsigned VarNum = 0;
  59. std::ostringstream names;
  60. names << "ident" << VarNum++;
  61. vars << names.str() << " = " << ident << "\n";
  62. return "$" + names.str();
  63. } else {
  64. std::string result = ident;
  65. cmSystemTools::ReplaceString(result, " ", "$ ");
  66. cmSystemTools::ReplaceString(result, ":", "$:");
  67. return result;
  68. }
  69. }
  70. std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string &lit)
  71. {
  72. std::string result = lit;
  73. cmSystemTools::ReplaceString(result, "$", "$$");
  74. return result;
  75. }
  76. void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os,
  77. const std::string& comment,
  78. const std::string& rule,
  79. const cmNinjaDeps& outputs,
  80. const cmNinjaDeps& explicitDeps,
  81. const cmNinjaDeps& implicitDeps,
  82. const cmNinjaDeps& orderOnlyDeps,
  83. const cmNinjaVars& variables)
  84. {
  85. // Make sure there is a rule.
  86. if(rule.empty())
  87. {
  88. cmSystemTools::Error("No rule for WriteBuildStatement! called "
  89. "with comment: ",
  90. comment.c_str());
  91. return;
  92. }
  93. // Make sure there is at least one output file.
  94. if(outputs.empty())
  95. {
  96. cmSystemTools::Error("No output files for WriteBuildStatement! called "
  97. "with comment: ",
  98. comment.c_str());
  99. return;
  100. }
  101. cmGlobalNinjaGenerator::WriteComment(os, comment);
  102. std::ostringstream builds;
  103. // TODO: Better formatting for when there are multiple input/output files.
  104. // Write outputs files.
  105. builds << "build";
  106. for(cmNinjaDeps::const_iterator i = outputs.begin();
  107. i != outputs.end();
  108. ++i)
  109. builds << " " << EncodeIdent(*i, os);
  110. builds << ":";
  111. // Write the rule.
  112. builds << " " << rule;
  113. // Write explicit dependencies.
  114. for(cmNinjaDeps::const_iterator i = explicitDeps.begin();
  115. i != explicitDeps.end();
  116. ++i)
  117. builds << " " << EncodeIdent(*i, os);
  118. // Write implicit dependencies.
  119. if(!implicitDeps.empty())
  120. {
  121. builds << " |";
  122. for(cmNinjaDeps::const_iterator i = implicitDeps.begin();
  123. i != implicitDeps.end();
  124. ++i)
  125. builds << " " << EncodeIdent(*i, os);
  126. }
  127. // Write order-only dependencies.
  128. if(!orderOnlyDeps.empty())
  129. {
  130. builds << " ||";
  131. for(cmNinjaDeps::const_iterator i = orderOnlyDeps.begin();
  132. i != orderOnlyDeps.end();
  133. ++i)
  134. builds << " " << EncodeIdent(*i, os);
  135. }
  136. builds << "\n";
  137. os << builds.str();
  138. // Write the variables bound to this build statement.
  139. for(cmNinjaVars::const_iterator i = variables.begin();
  140. i != variables.end();
  141. ++i)
  142. cmGlobalNinjaGenerator::WriteVariable(os, i->first, i->second, "", 1);
  143. }
  144. void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os,
  145. const std::string& comment,
  146. const cmNinjaDeps& outputs,
  147. const cmNinjaDeps& explicitDeps,
  148. const cmNinjaDeps& implicitDeps,
  149. const cmNinjaDeps& orderOnlyDeps,
  150. const cmNinjaVars& variables)
  151. {
  152. cmGlobalNinjaGenerator::WriteBuild(os,
  153. comment,
  154. "phony",
  155. outputs,
  156. explicitDeps,
  157. implicitDeps,
  158. orderOnlyDeps,
  159. variables);
  160. }
  161. void cmGlobalNinjaGenerator::AddCustomCommandRule()
  162. {
  163. this->AddRule("CUSTOM_COMMAND",
  164. "$COMMAND",
  165. "$DESC",
  166. "Rule for running custom commands.",
  167. /*depfile*/ "",
  168. /*restat*/ true);
  169. }
  170. void
  171. cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command,
  172. const std::string& description,
  173. const std::string& comment,
  174. const cmNinjaDeps& outputs,
  175. const cmNinjaDeps& deps,
  176. const cmNinjaDeps& orderOnlyDeps)
  177. {
  178. this->AddCustomCommandRule();
  179. cmNinjaVars vars;
  180. vars["COMMAND"] = command;
  181. vars["DESC"] = EncodeLiteral(description);
  182. cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream,
  183. comment,
  184. "CUSTOM_COMMAND",
  185. outputs,
  186. deps,
  187. cmNinjaDeps(),
  188. orderOnlyDeps,
  189. vars);
  190. }
  191. void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
  192. const std::string& name,
  193. const std::string& command,
  194. const std::string& description,
  195. const std::string& comment,
  196. const std::string& depfile,
  197. bool restat,
  198. bool generator)
  199. {
  200. // Make sure the rule has a name.
  201. if(name.empty())
  202. {
  203. cmSystemTools::Error("No name given for WriteRuleStatement! called "
  204. "with comment: ",
  205. comment.c_str());
  206. return;
  207. }
  208. // Make sure a command is given.
  209. if(command.empty())
  210. {
  211. cmSystemTools::Error("No command given for WriteRuleStatement! called "
  212. "with comment: ",
  213. comment.c_str());
  214. return;
  215. }
  216. cmGlobalNinjaGenerator::WriteComment(os, comment);
  217. // Write the rule.
  218. os << "rule " << name << "\n";
  219. // Write the depfile if any.
  220. if(!depfile.empty())
  221. {
  222. cmGlobalNinjaGenerator::Indent(os, 1);
  223. os << "depfile = " << depfile << "\n";
  224. }
  225. // Write the command.
  226. cmGlobalNinjaGenerator::Indent(os, 1);
  227. os << "command = " << command << "\n";
  228. // Write the description if any.
  229. if(!description.empty())
  230. {
  231. cmGlobalNinjaGenerator::Indent(os, 1);
  232. os << "description = " << description << "\n";
  233. }
  234. if(restat)
  235. {
  236. cmGlobalNinjaGenerator::Indent(os, 1);
  237. os << "restat = 1\n";
  238. }
  239. if(generator)
  240. {
  241. cmGlobalNinjaGenerator::Indent(os, 1);
  242. os << "generator = 1\n";
  243. }
  244. }
  245. void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os,
  246. const std::string& name,
  247. const std::string& value,
  248. const std::string& comment,
  249. int indent)
  250. {
  251. // Make sure we have a name.
  252. if(name.empty())
  253. {
  254. cmSystemTools::Error("No name given for WriteVariable! called "
  255. "with comment: ",
  256. comment.c_str());
  257. return;
  258. }
  259. // Do not add a variable if the value is empty.
  260. std::string val = cmSystemTools::TrimWhitespace(value);
  261. if(val.empty())
  262. {
  263. return;
  264. }
  265. cmGlobalNinjaGenerator::WriteComment(os, comment);
  266. cmGlobalNinjaGenerator::Indent(os, indent);
  267. os << name << " = " << val << "\n";
  268. }
  269. void cmGlobalNinjaGenerator::WriteInclude(std::ostream& os,
  270. const std::string& filename,
  271. const std::string& comment)
  272. {
  273. cmGlobalNinjaGenerator::WriteComment(os, comment);
  274. os << "include " << filename << "\n";
  275. }
  276. void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os,
  277. const cmNinjaDeps& targets,
  278. const std::string& comment)
  279. {
  280. cmGlobalNinjaGenerator::WriteComment(os, comment);
  281. os << "default";
  282. for(cmNinjaDeps::const_iterator i = targets.begin(); i != targets.end(); ++i)
  283. os << " " << *i;
  284. os << "\n";
  285. }
  286. cmGlobalNinjaGenerator::cmGlobalNinjaGenerator()
  287. : cmGlobalGenerator()
  288. , BuildFileStream(0)
  289. , RulesFileStream(0)
  290. , Rules()
  291. , AllDependencies()
  292. {
  293. // // Ninja is not ported to non-Unix OS yet.
  294. // this->ForceUnixPaths = true;
  295. this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake";
  296. }
  297. //----------------------------------------------------------------------------
  298. // Virtual public methods.
  299. cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator()
  300. {
  301. cmLocalGenerator* lg = new cmLocalNinjaGenerator;
  302. lg->SetGlobalGenerator(this);
  303. return lg;
  304. }
  305. void cmGlobalNinjaGenerator
  306. ::GetDocumentation(cmDocumentationEntry& entry) const
  307. {
  308. entry.Name = this->GetName();
  309. entry.Brief = "Generates build.ninja files (experimental).";
  310. entry.Full =
  311. "A build.ninja file is generated into the build tree. Recent "
  312. "versions of the ninja program can build the project through the "
  313. "\"all\" target. An \"install\" target is also provided.";
  314. }
  315. // Implemented in all cmGlobaleGenerator sub-classes.
  316. // Used in:
  317. // Source/cmLocalGenerator.cxx
  318. // Source/cmake.cxx
  319. void cmGlobalNinjaGenerator::Generate()
  320. {
  321. this->OpenBuildFileStream();
  322. this->OpenRulesFileStream();
  323. this->cmGlobalGenerator::Generate();
  324. this->WriteAssumedSourceDependencies();
  325. this->WriteTargetAliases(*this->BuildFileStream);
  326. this->WriteBuiltinTargets(*this->BuildFileStream);
  327. this->CloseRulesFileStream();
  328. this->CloseBuildFileStream();
  329. }
  330. // Implemented in all cmGlobaleGenerator sub-classes.
  331. // Used in:
  332. // Source/cmMakefile.cxx:
  333. void cmGlobalNinjaGenerator
  334. ::EnableLanguage(std::vector<std::string>const& languages,
  335. cmMakefile *mf,
  336. bool optional)
  337. {
  338. this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
  339. std::string path;
  340. for(std::vector<std::string>::const_iterator l = languages.begin();
  341. l != languages.end(); ++l)
  342. {
  343. if(*l == "NONE")
  344. {
  345. continue;
  346. }
  347. if(*l == "Fortran")
  348. {
  349. std::string message = "The \"";
  350. message += this->GetName();
  351. message += "\" generator does not support the language \"";
  352. message += *l;
  353. message += "\" yet.";
  354. cmSystemTools::Error(message.c_str());
  355. }
  356. this->ResolveLanguageCompiler(*l, mf, optional);
  357. }
  358. }
  359. // Implemented by:
  360. // cmGlobalUnixMakefileGenerator3
  361. // cmGlobalVisualStudio10Generator
  362. // cmGlobalVisualStudio6Generator
  363. // cmGlobalVisualStudio7Generator
  364. // cmGlobalXCodeGenerator
  365. // Called by:
  366. // cmGlobalGenerator::Build()
  367. std::string cmGlobalNinjaGenerator
  368. ::GenerateBuildCommand(const char* makeProgram,
  369. const char* projectName,
  370. const char* additionalOptions,
  371. const char* targetName,
  372. const char* config,
  373. bool ignoreErrors,
  374. bool fast)
  375. {
  376. // Project name and config are not used yet.
  377. (void)projectName;
  378. (void)config;
  379. // Ninja does not have -i equivalent option yet.
  380. (void)ignoreErrors;
  381. // We do not handle fast build yet.
  382. (void)fast;
  383. std::string makeCommand =
  384. cmSystemTools::ConvertToUnixOutputPath(makeProgram);
  385. if(additionalOptions)
  386. {
  387. makeCommand += " ";
  388. makeCommand += additionalOptions;
  389. }
  390. if(targetName)
  391. {
  392. if(strcmp(targetName, "clean") == 0)
  393. {
  394. makeCommand += " -t clean";
  395. }
  396. else
  397. {
  398. makeCommand += " ";
  399. makeCommand += targetName;
  400. }
  401. }
  402. return makeCommand;
  403. }
  404. //----------------------------------------------------------------------------
  405. // Non-virtual public methods.
  406. void cmGlobalNinjaGenerator::AddRule(const std::string& name,
  407. const std::string& command,
  408. const std::string& description,
  409. const std::string& comment,
  410. const std::string& depfile,
  411. bool restat,
  412. bool generator)
  413. {
  414. // Do not add the same rule twice.
  415. if (this->HasRule(name))
  416. return;
  417. this->Rules.insert(name);
  418. cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream,
  419. name,
  420. command,
  421. description,
  422. comment,
  423. depfile,
  424. restat,
  425. generator);
  426. }
  427. bool cmGlobalNinjaGenerator::HasRule(const std::string &name)
  428. {
  429. RulesSetType::const_iterator rule = this->Rules.find(name);
  430. return (rule != this->Rules.end());
  431. }
  432. //----------------------------------------------------------------------------
  433. // Private methods
  434. void cmGlobalNinjaGenerator::OpenBuildFileStream()
  435. {
  436. // Compute Ninja's build file path.
  437. std::string buildFilePath =
  438. this->GetCMakeInstance()->GetHomeOutputDirectory();
  439. buildFilePath += "/";
  440. buildFilePath += cmGlobalNinjaGenerator::NINJA_BUILD_FILE;
  441. // Get a stream where to generate things.
  442. if (!this->BuildFileStream)
  443. {
  444. this->BuildFileStream = new cmGeneratedFileStream(buildFilePath.c_str());
  445. if (!this->BuildFileStream)
  446. {
  447. // An error message is generated by the constructor if it cannot
  448. // open the file.
  449. return;
  450. }
  451. }
  452. // Write the do not edit header.
  453. this->WriteDisclaimer(*this->BuildFileStream);
  454. // Write a comment about this file.
  455. *this->BuildFileStream
  456. << "# This file contains all the build statements describing the\n"
  457. << "# compilation DAG.\n\n"
  458. ;
  459. }
  460. void cmGlobalNinjaGenerator::CloseBuildFileStream()
  461. {
  462. if (this->BuildFileStream)
  463. {
  464. delete this->BuildFileStream;
  465. this->BuildFileStream = 0;
  466. }
  467. else
  468. {
  469. cmSystemTools::Error("Build file stream was not open.");
  470. }
  471. }
  472. void cmGlobalNinjaGenerator::OpenRulesFileStream()
  473. {
  474. // Compute Ninja's build file path.
  475. std::string rulesFilePath =
  476. this->GetCMakeInstance()->GetHomeOutputDirectory();
  477. rulesFilePath += "/";
  478. rulesFilePath += cmGlobalNinjaGenerator::NINJA_RULES_FILE;
  479. // Get a stream where to generate things.
  480. if (!this->RulesFileStream)
  481. {
  482. this->RulesFileStream = new cmGeneratedFileStream(rulesFilePath.c_str());
  483. if (!this->RulesFileStream)
  484. {
  485. // An error message is generated by the constructor if it cannot
  486. // open the file.
  487. return;
  488. }
  489. }
  490. // Write the do not edit header.
  491. this->WriteDisclaimer(*this->RulesFileStream);
  492. // Write comment about this file.
  493. *this->RulesFileStream
  494. << "# This file contains all the rules used to get the outputs files\n"
  495. << "# built from the input files.\n"
  496. << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
  497. ;
  498. }
  499. void cmGlobalNinjaGenerator::CloseRulesFileStream()
  500. {
  501. if (this->RulesFileStream)
  502. {
  503. delete this->RulesFileStream;
  504. this->RulesFileStream = 0;
  505. }
  506. else
  507. {
  508. cmSystemTools::Error("Rules file stream was not open.");
  509. }
  510. }
  511. void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
  512. {
  513. os
  514. << "# CMAKE generated file: DO NOT EDIT!\n"
  515. << "# Generated by \"" << this->GetName() << "\""
  516. << " Generator, CMake Version "
  517. << cmVersion::GetMajorVersion() << "."
  518. << cmVersion::GetMinorVersion() << "\n\n";
  519. }
  520. void cmGlobalNinjaGenerator::AddDependencyToAll(cmTarget* target)
  521. {
  522. this->AppendTargetOutputs(target, this->AllDependencies);
  523. }
  524. void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
  525. {
  526. for (std::map<std::string, std::set<std::string> >::iterator
  527. i = this->AssumedSourceDependencies.begin();
  528. i != this->AssumedSourceDependencies.end(); ++i) {
  529. cmNinjaDeps deps;
  530. std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps));
  531. WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
  532. "Assume dependencies for generated source file.",
  533. cmNinjaDeps(1, i->first), deps);
  534. }
  535. }
  536. void
  537. cmGlobalNinjaGenerator
  538. ::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs)
  539. {
  540. const char* configName =
  541. target->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE");
  542. cmLocalNinjaGenerator *ng =
  543. static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]);
  544. switch (target->GetType()) {
  545. case cmTarget::EXECUTABLE:
  546. case cmTarget::SHARED_LIBRARY:
  547. case cmTarget::STATIC_LIBRARY:
  548. case cmTarget::MODULE_LIBRARY:
  549. outputs.push_back(ng->ConvertToNinjaPath(
  550. target->GetFullPath(configName).c_str()));
  551. break;
  552. case cmTarget::UTILITY: {
  553. std::string path = ng->ConvertToNinjaPath(
  554. target->GetMakefile()->GetStartOutputDirectory());
  555. if (path.empty() || path == ".")
  556. outputs.push_back(target->GetName());
  557. else {
  558. path += "/";
  559. path += target->GetName();
  560. outputs.push_back(path);
  561. }
  562. break;
  563. }
  564. case cmTarget::GLOBAL_TARGET:
  565. // Always use the target in HOME instead of an unused duplicate in a
  566. // subdirectory.
  567. outputs.push_back(target->GetName());
  568. break;
  569. default:
  570. return;
  571. }
  572. }
  573. void
  574. cmGlobalNinjaGenerator
  575. ::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs)
  576. {
  577. if (target->GetType() == cmTarget::GLOBAL_TARGET) {
  578. // Global targets only depend on other utilities, which may not appear in
  579. // the TargetDepends set (e.g. "all").
  580. std::set<cmStdString> const& utils = target->GetUtilities();
  581. std::copy(utils.begin(), utils.end(), std::back_inserter(outputs));
  582. } else {
  583. cmTargetDependSet const& targetDeps =
  584. this->GetTargetDirectDepends(*target);
  585. for (cmTargetDependSet::const_iterator i = targetDeps.begin();
  586. i != targetDeps.end(); ++i) {
  587. this->AppendTargetOutputs(*i, outputs);
  588. }
  589. }
  590. }
  591. void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
  592. cmTarget* target) {
  593. cmNinjaDeps outputs;
  594. this->AppendTargetOutputs(target, outputs);
  595. // Mark the target's outputs as ambiguous to ensure that no other target uses
  596. // the output as an alias.
  597. for (cmNinjaDeps::iterator i = outputs.begin(); i != outputs.end(); ++i)
  598. TargetAliases[*i] = 0;
  599. // Insert the alias into the map. If the alias was already present in the
  600. // map and referred to another target, mark it as ambiguous.
  601. std::pair<TargetAliasMap::iterator, bool> newAlias =
  602. TargetAliases.insert(make_pair(alias, target));
  603. if (newAlias.second && newAlias.first->second != target)
  604. newAlias.first->second = 0;
  605. }
  606. void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
  607. {
  608. cmGlobalNinjaGenerator::WriteDivider(os);
  609. os << "# Target aliases.\n\n";
  610. for (TargetAliasMap::iterator i = TargetAliases.begin();
  611. i != TargetAliases.end(); ++i) {
  612. // Don't write ambiguous aliases.
  613. if (!i->second)
  614. continue;
  615. cmNinjaDeps deps;
  616. this->AppendTargetOutputs(i->second, deps);
  617. cmGlobalNinjaGenerator::WritePhonyBuild(os,
  618. "",
  619. cmNinjaDeps(1, i->first),
  620. deps);
  621. }
  622. }
  623. void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
  624. {
  625. // Write headers.
  626. cmGlobalNinjaGenerator::WriteDivider(os);
  627. os << "# Built-in targets\n\n";
  628. this->WriteTargetAll(os);
  629. this->WriteTargetRebuildManifest(os);
  630. }
  631. void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
  632. {
  633. cmNinjaDeps outputs;
  634. outputs.push_back("all");
  635. cmGlobalNinjaGenerator::WritePhonyBuild(os,
  636. "The main all target.",
  637. outputs,
  638. this->AllDependencies);
  639. cmGlobalNinjaGenerator::WriteDefault(os,
  640. outputs,
  641. "Make the all target the default.");
  642. }
  643. void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
  644. {
  645. cmMakefile* mfRoot = this->LocalGenerators[0]->GetMakefile();
  646. std::ostringstream cmd;
  647. cmd << mfRoot->GetRequiredDefinition("CMAKE_COMMAND")
  648. << " -H" << mfRoot->GetHomeDirectory()
  649. << " -B" << mfRoot->GetHomeOutputDirectory();
  650. WriteRule(*this->RulesFileStream,
  651. "RERUN_CMAKE",
  652. cmd.str(),
  653. "Re-running CMake...",
  654. "Rule for re-running cmake.",
  655. /*depfile=*/ "",
  656. /*restat=*/ false,
  657. /*generator=*/ true);
  658. cmNinjaDeps implicitDeps;
  659. for (std::vector<cmLocalGenerator *>::const_iterator i =
  660. this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) {
  661. const std::vector<std::string>& lf = (*i)->GetMakefile()->GetListFiles();
  662. implicitDeps.insert(implicitDeps.end(), lf.begin(), lf.end());
  663. }
  664. std::sort(implicitDeps.begin(), implicitDeps.end());
  665. implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
  666. implicitDeps.end());
  667. implicitDeps.push_back("CMakeCache.txt");
  668. WriteBuild(os,
  669. "Re-run CMake if any of its inputs changed.",
  670. "RERUN_CMAKE",
  671. /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE),
  672. /*explicitDeps=*/ cmNinjaDeps(),
  673. implicitDeps,
  674. /*orderOnlyDeps=*/ cmNinjaDeps(),
  675. /*variables=*/ cmNinjaVars());
  676. WritePhonyBuild(os,
  677. "A missing CMake input file is not an error.",
  678. implicitDeps,
  679. cmNinjaDeps());
  680. }