cmNinjaNormalTargetGenerator.cxx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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 "cmNinjaNormalTargetGenerator.h"
  12. #include "cmLocalNinjaGenerator.h"
  13. #include "cmGlobalNinjaGenerator.h"
  14. #include "cmSourceFile.h"
  15. #include "cmGeneratedFileStream.h"
  16. #include "cmMakefile.h"
  17. #include <assert.h>
  18. cmNinjaNormalTargetGenerator::
  19. cmNinjaNormalTargetGenerator(cmTarget* target)
  20. : cmNinjaTargetGenerator(target)
  21. , TargetNameOut()
  22. , TargetNameSO()
  23. , TargetNameReal()
  24. , TargetNameImport()
  25. , TargetNamePDB()
  26. {
  27. this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
  28. if (target->GetType() == cmTarget::EXECUTABLE)
  29. target->GetExecutableNames(this->TargetNameOut,
  30. this->TargetNameReal,
  31. this->TargetNameImport,
  32. this->TargetNamePDB,
  33. GetLocalGenerator()->GetConfigName());
  34. else
  35. target->GetLibraryNames(this->TargetNameOut,
  36. this->TargetNameSO,
  37. this->TargetNameReal,
  38. this->TargetNameImport,
  39. this->TargetNamePDB,
  40. GetLocalGenerator()->GetConfigName());
  41. if(target->GetType() != cmTarget::OBJECT_LIBRARY)
  42. {
  43. // on Windows the output dir is already needed at compile time
  44. // ensure the directory exists (OutDir test)
  45. EnsureDirectoryExists(target->GetDirectory(this->GetConfigName()));
  46. }
  47. }
  48. cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
  49. {
  50. }
  51. void
  52. cmNinjaNormalTargetGenerator
  53. ::EnsureDirectoryExists(const std::string& dir)
  54. {
  55. cmSystemTools::MakeDirectory(dir.c_str());
  56. }
  57. void
  58. cmNinjaNormalTargetGenerator
  59. ::EnsureParentDirectoryExists(const std::string& path)
  60. {
  61. EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path.c_str()));
  62. }
  63. void cmNinjaNormalTargetGenerator::Generate()
  64. {
  65. if (!this->TargetLinkLanguage) {
  66. cmSystemTools::Error("CMake can not determine linker language for target:",
  67. this->GetTarget()->GetName());
  68. return;
  69. }
  70. // Write the rules for each language.
  71. this->WriteLanguagesRules();
  72. // Write the build statements
  73. this->WriteObjectBuildStatements();
  74. if(this->GetTarget()->GetType() == cmTarget::OBJECT_LIBRARY)
  75. {
  76. this->WriteObjectLibStatement();
  77. }
  78. else
  79. {
  80. this->WriteLinkRule();
  81. this->WriteLinkStatement();
  82. }
  83. this->GetBuildFileStream() << "\n";
  84. this->GetRulesFileStream() << "\n";
  85. }
  86. void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
  87. {
  88. cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
  89. this->GetRulesFileStream()
  90. << "# Rules for each languages for "
  91. << cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
  92. << " target "
  93. << this->GetTargetName()
  94. << "\n\n";
  95. std::set<cmStdString> languages;
  96. this->GetTarget()->GetLanguages(languages);
  97. for(std::set<cmStdString>::const_iterator l = languages.begin();
  98. l != languages.end();
  99. ++l)
  100. this->WriteLanguageRules(*l);
  101. }
  102. const char *cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
  103. {
  104. switch (this->GetTarget()->GetType()) {
  105. case cmTarget::STATIC_LIBRARY:
  106. return "static library";
  107. case cmTarget::SHARED_LIBRARY:
  108. return "shared library";
  109. case cmTarget::MODULE_LIBRARY:
  110. return "shared module";
  111. case cmTarget::EXECUTABLE:
  112. return "executable";
  113. default:
  114. return 0;
  115. }
  116. }
  117. std::string
  118. cmNinjaNormalTargetGenerator
  119. ::LanguageLinkerRule() const
  120. {
  121. return std::string(this->TargetLinkLanguage)
  122. + "_"
  123. + cmTarget::GetTargetTypeName(this->GetTarget()->GetType())
  124. + "_LINKER";
  125. }
  126. void
  127. cmNinjaNormalTargetGenerator
  128. ::WriteLinkRule()
  129. {
  130. cmTarget::TargetType targetType = this->GetTarget()->GetType();
  131. std::string ruleName = this->LanguageLinkerRule();
  132. if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
  133. cmLocalGenerator::RuleVariables vars;
  134. vars.RuleLauncher = "RULE_LAUNCH_LINK";
  135. vars.CMTarget = this->GetTarget();
  136. vars.Language = this->TargetLinkLanguage;
  137. vars.Objects = "$in";
  138. std::string objdir =
  139. this->GetLocalGenerator()->GetHomeRelativeOutputPath();
  140. objdir += objdir.empty() ? "" : "/";
  141. objdir += cmake::GetCMakeFilesDirectoryPostSlash();
  142. objdir += this->GetTargetName();
  143. objdir += ".dir";
  144. objdir = this->GetLocalGenerator()->Convert(objdir.c_str(),
  145. cmLocalGenerator::START_OUTPUT,
  146. cmLocalGenerator::SHELL);
  147. vars.ObjectDir = objdir.c_str();
  148. vars.Target = "$out";
  149. vars.TargetSOName = "$SONAME";
  150. vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
  151. vars.TargetPDB = "$TARGET_PDB";
  152. // Setup the target version.
  153. std::string targetVersionMajor;
  154. std::string targetVersionMinor;
  155. {
  156. cmOStringStream majorStream;
  157. cmOStringStream minorStream;
  158. int major;
  159. int minor;
  160. this->GetTarget()->GetTargetVersion(major, minor);
  161. majorStream << major;
  162. minorStream << minor;
  163. targetVersionMajor = majorStream.str();
  164. targetVersionMinor = minorStream.str();
  165. }
  166. vars.TargetVersionMajor = targetVersionMajor.c_str();
  167. vars.TargetVersionMinor = targetVersionMinor.c_str();
  168. vars.LinkLibraries = "$LINK_LIBRARIES";
  169. vars.Flags = "$FLAGS";
  170. vars.LinkFlags = "$LINK_FLAGS";
  171. std::string langFlags;
  172. this->GetLocalGenerator()->AddLanguageFlags(langFlags,
  173. this->TargetLinkLanguage,
  174. this->GetConfigName());
  175. if (targetType != cmTarget::EXECUTABLE)
  176. langFlags += " $ARCH_FLAGS";
  177. vars.LanguageCompileFlags = langFlags.c_str();
  178. // Rule for linking library.
  179. std::vector<std::string> linkCmds = this->ComputeLinkCmd();
  180. for(std::vector<std::string>::iterator i = linkCmds.begin();
  181. i != linkCmds.end();
  182. ++i)
  183. {
  184. this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
  185. }
  186. linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
  187. linkCmds.push_back("$POST_BUILD");
  188. std::string linkCmd =
  189. this->GetLocalGenerator()->BuildCommandLine(linkCmds);
  190. // Write the linker rule.
  191. std::ostringstream comment;
  192. comment << "Rule for linking " << this->TargetLinkLanguage << " "
  193. << this->GetVisibleTypeName() << ".";
  194. std::ostringstream description;
  195. description << "Linking " << this->TargetLinkLanguage << " "
  196. << this->GetVisibleTypeName() << " $out";
  197. this->GetGlobalGenerator()->AddRule(ruleName,
  198. linkCmd,
  199. description.str(),
  200. comment.str());
  201. }
  202. if (this->TargetNameOut != this->TargetNameReal) {
  203. std::string cmakeCommand =
  204. this->GetLocalGenerator()->ConvertToOutputFormat(
  205. this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
  206. cmLocalGenerator::SHELL);
  207. if (targetType == cmTarget::EXECUTABLE)
  208. this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_EXECUTABLE",
  209. cmakeCommand +
  210. " -E cmake_symlink_executable"
  211. " $in $out && $POST_BUILD",
  212. "Creating executable symlink $out",
  213. "Rule for creating executable symlink.");
  214. else
  215. this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_LIBRARY",
  216. cmakeCommand +
  217. " -E cmake_symlink_library"
  218. " $in $SONAME $out && $POST_BUILD",
  219. "Creating library symlink $out",
  220. "Rule for creating library symlink.");
  221. }
  222. }
  223. std::vector<std::string>
  224. cmNinjaNormalTargetGenerator
  225. ::ComputeLinkCmd()
  226. {
  227. std::vector<std::string> linkCmds;
  228. cmTarget::TargetType targetType = this->GetTarget()->GetType();
  229. switch (targetType) {
  230. case cmTarget::STATIC_LIBRARY: {
  231. // Check if you have a non archive way to create the static library.
  232. {
  233. std::string linkCmdVar = "CMAKE_";
  234. linkCmdVar += this->TargetLinkLanguage;
  235. linkCmdVar += "_CREATE_STATIC_LIBRARY";
  236. if (const char *linkCmd =
  237. this->GetMakefile()->GetDefinition(linkCmdVar.c_str()))
  238. {
  239. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  240. return linkCmds;
  241. }
  242. }
  243. // We have archive link commands set. First, delete the existing archive.
  244. std::string cmakeCommand =
  245. this->GetLocalGenerator()->ConvertToOutputFormat(
  246. this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
  247. cmLocalGenerator::SHELL);
  248. linkCmds.push_back(cmakeCommand + " -E remove $out");
  249. // TODO: Use ARCHIVE_APPEND for archives over a certain size.
  250. {
  251. std::string linkCmdVar = "CMAKE_";
  252. linkCmdVar += this->TargetLinkLanguage;
  253. linkCmdVar += "_ARCHIVE_CREATE";
  254. const char *linkCmd =
  255. this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
  256. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  257. }
  258. {
  259. std::string linkCmdVar = "CMAKE_";
  260. linkCmdVar += this->TargetLinkLanguage;
  261. linkCmdVar += "_ARCHIVE_FINISH";
  262. const char *linkCmd =
  263. this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
  264. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  265. }
  266. return linkCmds;
  267. }
  268. case cmTarget::SHARED_LIBRARY:
  269. case cmTarget::MODULE_LIBRARY:
  270. case cmTarget::EXECUTABLE: {
  271. std::string linkCmdVar = "CMAKE_";
  272. linkCmdVar += this->TargetLinkLanguage;
  273. switch (targetType) {
  274. case cmTarget::SHARED_LIBRARY:
  275. linkCmdVar += "_CREATE_SHARED_LIBRARY";
  276. break;
  277. case cmTarget::MODULE_LIBRARY:
  278. linkCmdVar += "_CREATE_SHARED_MODULE";
  279. break;
  280. case cmTarget::EXECUTABLE:
  281. linkCmdVar += "_LINK_EXECUTABLE";
  282. break;
  283. default:
  284. assert(0 && "Unexpected target type");
  285. }
  286. const char *linkCmd =
  287. this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
  288. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  289. return linkCmds;
  290. }
  291. default:
  292. assert(0 && "Unexpected target type");
  293. }
  294. return std::vector<std::string>();
  295. }
  296. void cmNinjaNormalTargetGenerator::WriteLinkStatement()
  297. {
  298. cmTarget::TargetType targetType = this->GetTarget()->GetType();
  299. // Write comments.
  300. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
  301. this->GetBuildFileStream()
  302. << "# Link build statements for "
  303. << cmTarget::GetTargetTypeName(targetType)
  304. << " target "
  305. << this->GetTargetName()
  306. << "\n\n";
  307. cmNinjaDeps emptyDeps;
  308. cmNinjaVars vars;
  309. std::string targetOutput = ConvertToNinjaPath(
  310. this->GetTarget()->GetFullPath(this->GetConfigName()).c_str());
  311. std::string targetOutputReal = ConvertToNinjaPath(
  312. this->GetTarget()->GetFullPath(this->GetConfigName(),
  313. /*implib=*/false,
  314. /*realpath=*/true).c_str());
  315. std::string targetOutputImplib = ConvertToNinjaPath(
  316. this->GetTarget()->GetFullPath(this->GetConfigName(),
  317. /*implib=*/true).c_str());
  318. // Compute the comment.
  319. std::ostringstream comment;
  320. comment << "Link the " << this->GetVisibleTypeName() << " "
  321. << targetOutputReal;
  322. // Compute outputs.
  323. cmNinjaDeps outputs;
  324. outputs.push_back(targetOutputReal);
  325. // Compute specific libraries to link with.
  326. cmNinjaDeps explicitDeps = this->GetObjects(),
  327. implicitDeps = this->ComputeLinkDeps();
  328. this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"],
  329. vars["FLAGS"],
  330. vars["LINK_FLAGS"],
  331. *this->GetTarget());
  332. this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
  333. // Compute architecture specific link flags. Yes, these go into a different
  334. // variable for executables, probably due to a mistake made when duplicating
  335. // code between the Makefile executable and library generators.
  336. this->GetLocalGenerator()
  337. ->AddArchitectureFlags(targetType == cmTarget::EXECUTABLE
  338. ? vars["FLAGS"]
  339. : vars["ARCH_FLAGS"],
  340. this->GetTarget(),
  341. this->TargetLinkLanguage,
  342. this->GetConfigName());
  343. vars["SONAME"] = this->TargetNameSO;
  344. if (targetType == cmTarget::SHARED_LIBRARY) {
  345. std::string install_name_dir =
  346. this->GetTarget()->GetInstallNameDirForBuildTree(this->GetConfigName());
  347. if (!install_name_dir.empty()) {
  348. vars["INSTALLNAME_DIR"] =
  349. this->GetLocalGenerator()->Convert(install_name_dir.c_str(),
  350. cmLocalGenerator::NONE,
  351. cmLocalGenerator::SHELL, false);
  352. }
  353. }
  354. std::string path;
  355. if (!this->TargetNameImport.empty()) {
  356. path = this->GetLocalGenerator()->ConvertToOutputFormat(
  357. targetOutputImplib.c_str(), cmLocalGenerator::SHELL);
  358. vars["TARGET_IMPLIB"] = path;
  359. EnsureParentDirectoryExists(path);
  360. }
  361. path = this->GetLocalGenerator()->ConvertToOutputFormat(
  362. this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL);
  363. vars["TARGET_PDB"] = path;
  364. EnsureParentDirectoryExists(path);
  365. std::vector<cmCustomCommand> *cmdLists[3] = {
  366. &this->GetTarget()->GetPreBuildCommands(),
  367. &this->GetTarget()->GetPreLinkCommands(),
  368. &this->GetTarget()->GetPostBuildCommands()
  369. };
  370. std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
  371. std::vector<std::string> *cmdLineLists[3] = {
  372. &preLinkCmdLines,
  373. &preLinkCmdLines,
  374. &postBuildCmdLines
  375. };
  376. for (unsigned i = 0; i != 3; ++i) {
  377. for (std::vector<cmCustomCommand>::const_iterator
  378. ci = cmdLists[i]->begin();
  379. ci != cmdLists[i]->end(); ++ci) {
  380. this->GetLocalGenerator()->AppendCustomCommandLines(&*ci,
  381. *cmdLineLists[i]);
  382. }
  383. }
  384. // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
  385. // the link commands.
  386. if (!preLinkCmdLines.empty()) {
  387. path = this->GetLocalGenerator()->ConvertToOutputFormat(
  388. this->GetMakefile()->GetHomeOutputDirectory(),
  389. cmLocalGenerator::SHELL);
  390. preLinkCmdLines.push_back("cd " + path);
  391. }
  392. vars["PRE_LINK"] =
  393. this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines);
  394. std::string postBuildCmdLine =
  395. this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines);
  396. cmNinjaVars symlinkVars;
  397. if (targetOutput == targetOutputReal) {
  398. vars["POST_BUILD"] = postBuildCmdLine;
  399. } else {
  400. vars["POST_BUILD"] = ":";
  401. symlinkVars["POST_BUILD"] = postBuildCmdLine;
  402. }
  403. // Write the build statement for this target.
  404. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
  405. comment.str(),
  406. this->LanguageLinkerRule(),
  407. outputs,
  408. explicitDeps,
  409. implicitDeps,
  410. emptyDeps,
  411. vars);
  412. if (targetOutput != targetOutputReal) {
  413. if (targetType == cmTarget::EXECUTABLE) {
  414. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
  415. "Create executable symlink " + targetOutput,
  416. "CMAKE_SYMLINK_EXECUTABLE",
  417. cmNinjaDeps(1, targetOutput),
  418. cmNinjaDeps(1, targetOutputReal),
  419. emptyDeps,
  420. emptyDeps,
  421. symlinkVars);
  422. } else {
  423. symlinkVars["SONAME"] = this->GetTargetFilePath(this->TargetNameSO);
  424. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
  425. "Create library symlink " + targetOutput,
  426. "CMAKE_SYMLINK_LIBRARY",
  427. cmNinjaDeps(1, targetOutput),
  428. cmNinjaDeps(1, targetOutputReal),
  429. emptyDeps,
  430. emptyDeps,
  431. symlinkVars);
  432. }
  433. }
  434. if (!this->TargetNameImport.empty()) {
  435. // Since using multiple outputs would mess up the $out variable, use an
  436. // alias for the import library.
  437. cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
  438. "Alias for import library.",
  439. cmNinjaDeps(1, targetOutputImplib),
  440. cmNinjaDeps(1, targetOutputReal));
  441. }
  442. // Add aliases for the file name and the target name.
  443. this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut,
  444. this->GetTarget());
  445. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
  446. this->GetTarget());
  447. }
  448. //----------------------------------------------------------------------------
  449. void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
  450. {
  451. // Write a phony output that depends on all object files.
  452. cmNinjaDeps outputs;
  453. this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
  454. cmNinjaDeps depends = this->GetObjects();
  455. cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
  456. "Object library "
  457. + this->GetTargetName(),
  458. outputs,
  459. depends);
  460. // Add aliases for the target name.
  461. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
  462. this->GetTarget());
  463. }