cmGlobalNinjaGenerator.cxx 28 KB

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