cmGlobalNinjaGenerator.cxx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  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. if (cmSystemTools::GetErrorOccuredFlag()) {
  337. this->RulesFileStream->setstate(std::ios_base::failbit);
  338. this->BuildFileStream->setstate(std::ios_base::failbit);
  339. }
  340. this->CloseRulesFileStream();
  341. this->CloseBuildFileStream();
  342. }
  343. // Implemented in all cmGlobaleGenerator sub-classes.
  344. // Used in:
  345. // Source/cmMakefile.cxx:
  346. void cmGlobalNinjaGenerator
  347. ::EnableLanguage(std::vector<std::string>const& languages,
  348. cmMakefile *mf,
  349. bool optional)
  350. {
  351. this->cmGlobalGenerator::EnableLanguage(languages, mf, optional);
  352. std::string path;
  353. for(std::vector<std::string>::const_iterator l = languages.begin();
  354. l != languages.end(); ++l)
  355. {
  356. if(*l == "NONE")
  357. {
  358. continue;
  359. }
  360. if(*l == "Fortran")
  361. {
  362. std::string message = "The \"";
  363. message += this->GetName();
  364. message += "\" generator does not support the language \"";
  365. message += *l;
  366. message += "\" yet.";
  367. cmSystemTools::Error(message.c_str());
  368. }
  369. this->ResolveLanguageCompiler(*l, mf, optional);
  370. }
  371. }
  372. // Implemented by:
  373. // cmGlobalUnixMakefileGenerator3
  374. // cmGlobalVisualStudio10Generator
  375. // cmGlobalVisualStudio6Generator
  376. // cmGlobalVisualStudio7Generator
  377. // cmGlobalXCodeGenerator
  378. // Called by:
  379. // cmGlobalGenerator::Build()
  380. std::string cmGlobalNinjaGenerator
  381. ::GenerateBuildCommand(const char* makeProgram,
  382. const char* projectName,
  383. const char* additionalOptions,
  384. const char* targetName,
  385. const char* config,
  386. bool ignoreErrors,
  387. bool fast)
  388. {
  389. // Project name and config are not used yet.
  390. (void)projectName;
  391. (void)config;
  392. // Ninja does not have -i equivalent option yet.
  393. (void)ignoreErrors;
  394. // We do not handle fast build yet.
  395. (void)fast;
  396. std::string makeCommand =
  397. cmSystemTools::ConvertToUnixOutputPath(makeProgram);
  398. if(additionalOptions)
  399. {
  400. makeCommand += " ";
  401. makeCommand += additionalOptions;
  402. }
  403. if(targetName)
  404. {
  405. if(strcmp(targetName, "clean") == 0)
  406. {
  407. makeCommand += " -t clean";
  408. }
  409. else
  410. {
  411. makeCommand += " ";
  412. makeCommand += targetName;
  413. }
  414. }
  415. return makeCommand;
  416. }
  417. //----------------------------------------------------------------------------
  418. // Non-virtual public methods.
  419. void cmGlobalNinjaGenerator::AddRule(const std::string& name,
  420. const std::string& command,
  421. const std::string& description,
  422. const std::string& comment,
  423. const std::string& depfile,
  424. bool restat,
  425. bool generator)
  426. {
  427. // Do not add the same rule twice.
  428. if (this->HasRule(name))
  429. return;
  430. this->Rules.insert(name);
  431. cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream,
  432. name,
  433. command,
  434. description,
  435. comment,
  436. depfile,
  437. restat,
  438. generator);
  439. }
  440. bool cmGlobalNinjaGenerator::HasRule(const std::string &name)
  441. {
  442. RulesSetType::const_iterator rule = this->Rules.find(name);
  443. return (rule != this->Rules.end());
  444. }
  445. //----------------------------------------------------------------------------
  446. // Private virtual overrides
  447. // TODO: Refactor to combine with cmGlobalUnixMakefileGenerator3 impl.
  448. void cmGlobalNinjaGenerator::ComputeTargetObjects(cmGeneratorTarget* gt) const
  449. {
  450. cmTarget* target = gt->Target;
  451. // Compute full path to object file directory for this target.
  452. std::string dir_max;
  453. dir_max += gt->Makefile->GetCurrentOutputDirectory();
  454. dir_max += "/";
  455. dir_max += gt->LocalGenerator->GetTargetDirectory(*target);
  456. dir_max += "/";
  457. gt->ObjectDirectory = dir_max;
  458. // Compute the name of each object file.
  459. for(std::vector<cmSourceFile*>::iterator
  460. si = gt->ObjectSources.begin();
  461. si != gt->ObjectSources.end(); ++si)
  462. {
  463. cmSourceFile* sf = *si;
  464. std::string objectName = gt->LocalGenerator
  465. ->GetObjectFileNameWithoutTarget(*sf, dir_max);
  466. gt->Objects[sf] = objectName;
  467. }
  468. }
  469. //----------------------------------------------------------------------------
  470. // Private methods
  471. void cmGlobalNinjaGenerator::OpenBuildFileStream()
  472. {
  473. // Compute Ninja's build file path.
  474. std::string buildFilePath =
  475. this->GetCMakeInstance()->GetHomeOutputDirectory();
  476. buildFilePath += "/";
  477. buildFilePath += cmGlobalNinjaGenerator::NINJA_BUILD_FILE;
  478. // Get a stream where to generate things.
  479. if (!this->BuildFileStream)
  480. {
  481. this->BuildFileStream = new cmGeneratedFileStream(buildFilePath.c_str());
  482. if (!this->BuildFileStream)
  483. {
  484. // An error message is generated by the constructor if it cannot
  485. // open the file.
  486. return;
  487. }
  488. }
  489. // Write the do not edit header.
  490. this->WriteDisclaimer(*this->BuildFileStream);
  491. // Write a comment about this file.
  492. *this->BuildFileStream
  493. << "# This file contains all the build statements describing the\n"
  494. << "# compilation DAG.\n\n"
  495. ;
  496. }
  497. void cmGlobalNinjaGenerator::CloseBuildFileStream()
  498. {
  499. if (this->BuildFileStream)
  500. {
  501. delete this->BuildFileStream;
  502. this->BuildFileStream = 0;
  503. }
  504. else
  505. {
  506. cmSystemTools::Error("Build file stream was not open.");
  507. }
  508. }
  509. void cmGlobalNinjaGenerator::OpenRulesFileStream()
  510. {
  511. // Compute Ninja's build file path.
  512. std::string rulesFilePath =
  513. this->GetCMakeInstance()->GetHomeOutputDirectory();
  514. rulesFilePath += "/";
  515. rulesFilePath += cmGlobalNinjaGenerator::NINJA_RULES_FILE;
  516. // Get a stream where to generate things.
  517. if (!this->RulesFileStream)
  518. {
  519. this->RulesFileStream = new cmGeneratedFileStream(rulesFilePath.c_str());
  520. if (!this->RulesFileStream)
  521. {
  522. // An error message is generated by the constructor if it cannot
  523. // open the file.
  524. return;
  525. }
  526. }
  527. // Write the do not edit header.
  528. this->WriteDisclaimer(*this->RulesFileStream);
  529. // Write comment about this file.
  530. *this->RulesFileStream
  531. << "# This file contains all the rules used to get the outputs files\n"
  532. << "# built from the input files.\n"
  533. << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n"
  534. ;
  535. }
  536. void cmGlobalNinjaGenerator::CloseRulesFileStream()
  537. {
  538. if (this->RulesFileStream)
  539. {
  540. delete this->RulesFileStream;
  541. this->RulesFileStream = 0;
  542. }
  543. else
  544. {
  545. cmSystemTools::Error("Rules file stream was not open.");
  546. }
  547. }
  548. void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os)
  549. {
  550. os
  551. << "# CMAKE generated file: DO NOT EDIT!\n"
  552. << "# Generated by \"" << this->GetName() << "\""
  553. << " Generator, CMake Version "
  554. << cmVersion::GetMajorVersion() << "."
  555. << cmVersion::GetMinorVersion() << "\n\n";
  556. }
  557. void cmGlobalNinjaGenerator::AddDependencyToAll(cmTarget* target)
  558. {
  559. this->AppendTargetOutputs(target, this->AllDependencies);
  560. }
  561. void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
  562. {
  563. for (std::map<std::string, std::set<std::string> >::iterator
  564. i = this->AssumedSourceDependencies.begin();
  565. i != this->AssumedSourceDependencies.end(); ++i) {
  566. cmNinjaDeps deps;
  567. std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps));
  568. WriteCustomCommandBuild(/*command=*/"", /*description=*/"",
  569. "Assume dependencies for generated source file.",
  570. cmNinjaDeps(1, i->first), deps);
  571. }
  572. }
  573. void
  574. cmGlobalNinjaGenerator
  575. ::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs)
  576. {
  577. const char* configName =
  578. target->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE");
  579. cmLocalNinjaGenerator *ng =
  580. static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]);
  581. switch (target->GetType()) {
  582. case cmTarget::EXECUTABLE:
  583. case cmTarget::SHARED_LIBRARY:
  584. case cmTarget::STATIC_LIBRARY:
  585. case cmTarget::MODULE_LIBRARY:
  586. outputs.push_back(ng->ConvertToNinjaPath(
  587. target->GetFullPath(configName).c_str()));
  588. break;
  589. case cmTarget::OBJECT_LIBRARY:
  590. case cmTarget::UTILITY: {
  591. std::string path = ng->ConvertToNinjaPath(
  592. target->GetMakefile()->GetStartOutputDirectory());
  593. if (path.empty() || path == ".")
  594. outputs.push_back(target->GetName());
  595. else {
  596. path += "/";
  597. path += target->GetName();
  598. outputs.push_back(path);
  599. }
  600. break;
  601. }
  602. case cmTarget::GLOBAL_TARGET:
  603. // Always use the target in HOME instead of an unused duplicate in a
  604. // subdirectory.
  605. outputs.push_back(target->GetName());
  606. break;
  607. default:
  608. return;
  609. }
  610. }
  611. void
  612. cmGlobalNinjaGenerator
  613. ::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs)
  614. {
  615. if (target->GetType() == cmTarget::GLOBAL_TARGET) {
  616. // Global targets only depend on other utilities, which may not appear in
  617. // the TargetDepends set (e.g. "all").
  618. std::set<cmStdString> const& utils = target->GetUtilities();
  619. std::copy(utils.begin(), utils.end(), std::back_inserter(outputs));
  620. } else {
  621. cmTargetDependSet const& targetDeps =
  622. this->GetTargetDirectDepends(*target);
  623. for (cmTargetDependSet::const_iterator i = targetDeps.begin();
  624. i != targetDeps.end(); ++i) {
  625. this->AppendTargetOutputs(*i, outputs);
  626. }
  627. }
  628. }
  629. void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias,
  630. cmTarget* target) {
  631. cmNinjaDeps outputs;
  632. this->AppendTargetOutputs(target, outputs);
  633. // Mark the target's outputs as ambiguous to ensure that no other target uses
  634. // the output as an alias.
  635. for (cmNinjaDeps::iterator i = outputs.begin(); i != outputs.end(); ++i)
  636. TargetAliases[*i] = 0;
  637. // Insert the alias into the map. If the alias was already present in the
  638. // map and referred to another target, mark it as ambiguous.
  639. std::pair<TargetAliasMap::iterator, bool> newAlias =
  640. TargetAliases.insert(make_pair(alias, target));
  641. if (newAlias.second && newAlias.first->second != target)
  642. newAlias.first->second = 0;
  643. }
  644. void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os)
  645. {
  646. cmGlobalNinjaGenerator::WriteDivider(os);
  647. os << "# Target aliases.\n\n";
  648. for (TargetAliasMap::iterator i = TargetAliases.begin();
  649. i != TargetAliases.end(); ++i) {
  650. // Don't write ambiguous aliases.
  651. if (!i->second)
  652. continue;
  653. cmNinjaDeps deps;
  654. this->AppendTargetOutputs(i->second, deps);
  655. cmGlobalNinjaGenerator::WritePhonyBuild(os,
  656. "",
  657. cmNinjaDeps(1, i->first),
  658. deps);
  659. }
  660. }
  661. void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os)
  662. {
  663. // Write headers.
  664. cmGlobalNinjaGenerator::WriteDivider(os);
  665. os << "# Built-in targets\n\n";
  666. this->WriteTargetAll(os);
  667. this->WriteTargetRebuildManifest(os);
  668. }
  669. void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os)
  670. {
  671. cmNinjaDeps outputs;
  672. outputs.push_back("all");
  673. cmGlobalNinjaGenerator::WritePhonyBuild(os,
  674. "The main all target.",
  675. outputs,
  676. this->AllDependencies);
  677. cmGlobalNinjaGenerator::WriteDefault(os,
  678. outputs,
  679. "Make the all target the default.");
  680. }
  681. void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os)
  682. {
  683. cmLocalGenerator *lg = this->LocalGenerators[0];
  684. cmMakefile* mfRoot = lg->GetMakefile();
  685. std::ostringstream cmd;
  686. cmd << lg->ConvertToOutputFormat(
  687. mfRoot->GetRequiredDefinition("CMAKE_COMMAND"),
  688. cmLocalGenerator::SHELL)
  689. << " -H"
  690. << lg->ConvertToOutputFormat(mfRoot->GetHomeDirectory(),
  691. cmLocalGenerator::SHELL)
  692. << " -B"
  693. << lg->ConvertToOutputFormat(mfRoot->GetHomeOutputDirectory(),
  694. cmLocalGenerator::SHELL);
  695. WriteRule(*this->RulesFileStream,
  696. "RERUN_CMAKE",
  697. cmd.str(),
  698. "Re-running CMake...",
  699. "Rule for re-running cmake.",
  700. /*depfile=*/ "",
  701. /*restat=*/ false,
  702. /*generator=*/ true);
  703. cmNinjaDeps implicitDeps;
  704. for (std::vector<cmLocalGenerator *>::const_iterator i =
  705. this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) {
  706. const std::vector<std::string>& lf = (*i)->GetMakefile()->GetListFiles();
  707. implicitDeps.insert(implicitDeps.end(), lf.begin(), lf.end());
  708. }
  709. std::sort(implicitDeps.begin(), implicitDeps.end());
  710. implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()),
  711. implicitDeps.end());
  712. implicitDeps.push_back("CMakeCache.txt");
  713. WriteBuild(os,
  714. "Re-run CMake if any of its inputs changed.",
  715. "RERUN_CMAKE",
  716. /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE),
  717. /*explicitDeps=*/ cmNinjaDeps(),
  718. implicitDeps,
  719. /*orderOnlyDeps=*/ cmNinjaDeps(),
  720. /*variables=*/ cmNinjaVars());
  721. WritePhonyBuild(os,
  722. "A missing CMake input file is not an error.",
  723. implicitDeps,
  724. cmNinjaDeps());
  725. }