cmGlobalNinjaGenerator.cxx 26 KB

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