cmNinjaNormalTargetGenerator.cxx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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.SONameFlag = "$SONAME_FLAG";
  150. vars.TargetSOName = "$SONAME";
  151. vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
  152. vars.TargetPDB = "$TARGET_PDB";
  153. // Setup the target version.
  154. std::string targetVersionMajor;
  155. std::string targetVersionMinor;
  156. {
  157. cmOStringStream majorStream;
  158. cmOStringStream minorStream;
  159. int major;
  160. int minor;
  161. this->GetTarget()->GetTargetVersion(major, minor);
  162. majorStream << major;
  163. minorStream << minor;
  164. targetVersionMajor = majorStream.str();
  165. targetVersionMinor = minorStream.str();
  166. }
  167. vars.TargetVersionMajor = targetVersionMajor.c_str();
  168. vars.TargetVersionMinor = targetVersionMinor.c_str();
  169. vars.LinkLibraries = "$LINK_LIBRARIES";
  170. vars.Flags = "$FLAGS";
  171. vars.LinkFlags = "$LINK_FLAGS";
  172. std::string langFlags;
  173. if (targetType != cmTarget::EXECUTABLE) {
  174. this->GetLocalGenerator()->AddLanguageFlags(langFlags,
  175. this->TargetLinkLanguage,
  176. this->GetConfigName());
  177. langFlags += " $ARCH_FLAGS";
  178. vars.LanguageCompileFlags = langFlags.c_str();
  179. }
  180. // Rule for linking library.
  181. std::vector<std::string> linkCmds = this->ComputeLinkCmd();
  182. for(std::vector<std::string>::iterator i = linkCmds.begin();
  183. i != linkCmds.end();
  184. ++i)
  185. {
  186. this->GetLocalGenerator()->ExpandRuleVariables(*i, vars);
  187. }
  188. linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
  189. linkCmds.push_back("$POST_BUILD");
  190. std::string linkCmd =
  191. this->GetLocalGenerator()->BuildCommandLine(linkCmds);
  192. // Write the linker rule.
  193. std::ostringstream comment;
  194. comment << "Rule for linking " << this->TargetLinkLanguage << " "
  195. << this->GetVisibleTypeName() << ".";
  196. std::ostringstream description;
  197. description << "Linking " << this->TargetLinkLanguage << " "
  198. << this->GetVisibleTypeName() << " $out";
  199. this->GetGlobalGenerator()->AddRule(ruleName,
  200. linkCmd,
  201. description.str(),
  202. comment.str());
  203. }
  204. if (this->TargetNameOut != this->TargetNameReal) {
  205. std::string cmakeCommand =
  206. this->GetLocalGenerator()->ConvertToOutputFormat(
  207. this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
  208. cmLocalGenerator::SHELL);
  209. if (targetType == cmTarget::EXECUTABLE)
  210. this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_EXECUTABLE",
  211. cmakeCommand +
  212. " -E cmake_symlink_executable"
  213. " $in $out && $POST_BUILD",
  214. "Creating executable symlink $out",
  215. "Rule for creating executable symlink.");
  216. else
  217. this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_LIBRARY",
  218. cmakeCommand +
  219. " -E cmake_symlink_library"
  220. " $in $SONAME $out && $POST_BUILD",
  221. "Creating library symlink $out",
  222. "Rule for creating library symlink.");
  223. }
  224. }
  225. std::vector<std::string>
  226. cmNinjaNormalTargetGenerator
  227. ::ComputeLinkCmd()
  228. {
  229. std::vector<std::string> linkCmds;
  230. cmTarget::TargetType targetType = this->GetTarget()->GetType();
  231. switch (targetType) {
  232. case cmTarget::STATIC_LIBRARY: {
  233. // Check if you have a non archive way to create the static library.
  234. {
  235. std::string linkCmdVar = "CMAKE_";
  236. linkCmdVar += this->TargetLinkLanguage;
  237. linkCmdVar += "_CREATE_STATIC_LIBRARY";
  238. if (const char *linkCmd =
  239. this->GetMakefile()->GetDefinition(linkCmdVar.c_str()))
  240. {
  241. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  242. return linkCmds;
  243. }
  244. }
  245. // We have archive link commands set. First, delete the existing archive.
  246. std::string cmakeCommand =
  247. this->GetLocalGenerator()->ConvertToOutputFormat(
  248. this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"),
  249. cmLocalGenerator::SHELL);
  250. linkCmds.push_back(cmakeCommand + " -E remove $out");
  251. // TODO: Use ARCHIVE_APPEND for archives over a certain size.
  252. {
  253. std::string linkCmdVar = "CMAKE_";
  254. linkCmdVar += this->TargetLinkLanguage;
  255. linkCmdVar += "_ARCHIVE_CREATE";
  256. const char *linkCmd =
  257. this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
  258. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  259. }
  260. {
  261. std::string linkCmdVar = "CMAKE_";
  262. linkCmdVar += this->TargetLinkLanguage;
  263. linkCmdVar += "_ARCHIVE_FINISH";
  264. const char *linkCmd =
  265. this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
  266. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  267. }
  268. return linkCmds;
  269. }
  270. case cmTarget::SHARED_LIBRARY:
  271. case cmTarget::MODULE_LIBRARY:
  272. case cmTarget::EXECUTABLE: {
  273. std::string linkCmdVar = "CMAKE_";
  274. linkCmdVar += this->TargetLinkLanguage;
  275. switch (targetType) {
  276. case cmTarget::SHARED_LIBRARY:
  277. linkCmdVar += "_CREATE_SHARED_LIBRARY";
  278. break;
  279. case cmTarget::MODULE_LIBRARY:
  280. linkCmdVar += "_CREATE_SHARED_MODULE";
  281. break;
  282. case cmTarget::EXECUTABLE:
  283. linkCmdVar += "_LINK_EXECUTABLE";
  284. break;
  285. default:
  286. assert(0 && "Unexpected target type");
  287. }
  288. const char *linkCmd =
  289. this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str());
  290. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  291. return linkCmds;
  292. }
  293. default:
  294. assert(0 && "Unexpected target type");
  295. }
  296. return std::vector<std::string>();
  297. }
  298. void cmNinjaNormalTargetGenerator::WriteLinkStatement()
  299. {
  300. cmTarget::TargetType targetType = this->GetTarget()->GetType();
  301. // Write comments.
  302. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
  303. this->GetBuildFileStream()
  304. << "# Link build statements for "
  305. << cmTarget::GetTargetTypeName(targetType)
  306. << " target "
  307. << this->GetTargetName()
  308. << "\n\n";
  309. cmNinjaDeps emptyDeps;
  310. cmNinjaVars vars;
  311. std::string targetOutput = ConvertToNinjaPath(
  312. this->GetTarget()->GetFullPath(this->GetConfigName()).c_str());
  313. std::string targetOutputReal = ConvertToNinjaPath(
  314. this->GetTarget()->GetFullPath(this->GetConfigName(),
  315. /*implib=*/false,
  316. /*realpath=*/true).c_str());
  317. std::string targetOutputImplib = ConvertToNinjaPath(
  318. this->GetTarget()->GetFullPath(this->GetConfigName(),
  319. /*implib=*/true).c_str());
  320. // Compute the comment.
  321. std::ostringstream comment;
  322. comment << "Link the " << this->GetVisibleTypeName() << " "
  323. << targetOutputReal;
  324. // Compute outputs.
  325. cmNinjaDeps outputs;
  326. outputs.push_back(targetOutputReal);
  327. // Compute specific libraries to link with.
  328. cmNinjaDeps explicitDeps = this->GetObjects(),
  329. implicitDeps = this->ComputeLinkDeps();
  330. this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"],
  331. vars["FLAGS"],
  332. vars["LINK_FLAGS"],
  333. *this->GetTarget());
  334. this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]);
  335. // Compute architecture specific link flags. Yes, these go into a different
  336. // variable for executables, probably due to a mistake made when duplicating
  337. // code between the Makefile executable and library generators.
  338. this->GetLocalGenerator()
  339. ->AddArchitectureFlags(targetType == cmTarget::EXECUTABLE
  340. ? vars["FLAGS"]
  341. : vars["ARCH_FLAGS"],
  342. this->GetTarget(),
  343. this->TargetLinkLanguage,
  344. this->GetConfigName());
  345. if (this->GetTarget()->HasSOName(this->GetConfigName())) {
  346. vars["SONAME_FLAG"] =
  347. this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
  348. vars["SONAME"] = this->TargetNameSO;
  349. if (targetType == cmTarget::SHARED_LIBRARY) {
  350. std::string install_name_dir = this->GetTarget()
  351. ->GetInstallNameDirForBuildTree(this->GetConfigName());
  352. if (!install_name_dir.empty()) {
  353. vars["INSTALLNAME_DIR"] =
  354. this->GetLocalGenerator()->Convert(install_name_dir.c_str(),
  355. cmLocalGenerator::NONE,
  356. cmLocalGenerator::SHELL, false);
  357. }
  358. }
  359. }
  360. std::string path;
  361. if (!this->TargetNameImport.empty()) {
  362. path = this->GetLocalGenerator()->ConvertToOutputFormat(
  363. targetOutputImplib.c_str(), cmLocalGenerator::SHELL);
  364. vars["TARGET_IMPLIB"] = path;
  365. EnsureParentDirectoryExists(path);
  366. }
  367. path = this->GetLocalGenerator()->ConvertToOutputFormat(
  368. this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL);
  369. vars["TARGET_PDB"] = path;
  370. EnsureParentDirectoryExists(path);
  371. std::vector<cmCustomCommand> *cmdLists[3] = {
  372. &this->GetTarget()->GetPreBuildCommands(),
  373. &this->GetTarget()->GetPreLinkCommands(),
  374. &this->GetTarget()->GetPostBuildCommands()
  375. };
  376. std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
  377. std::vector<std::string> *cmdLineLists[3] = {
  378. &preLinkCmdLines,
  379. &preLinkCmdLines,
  380. &postBuildCmdLines
  381. };
  382. for (unsigned i = 0; i != 3; ++i) {
  383. for (std::vector<cmCustomCommand>::const_iterator
  384. ci = cmdLists[i]->begin();
  385. ci != cmdLists[i]->end(); ++ci) {
  386. this->GetLocalGenerator()->AppendCustomCommandLines(&*ci,
  387. *cmdLineLists[i]);
  388. }
  389. }
  390. // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for
  391. // the link commands.
  392. if (!preLinkCmdLines.empty()) {
  393. path = this->GetLocalGenerator()->ConvertToOutputFormat(
  394. this->GetMakefile()->GetHomeOutputDirectory(),
  395. cmLocalGenerator::SHELL);
  396. preLinkCmdLines.push_back("cd " + path);
  397. }
  398. vars["PRE_LINK"] =
  399. this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines);
  400. std::string postBuildCmdLine =
  401. this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines);
  402. cmNinjaVars symlinkVars;
  403. if (targetOutput == targetOutputReal) {
  404. vars["POST_BUILD"] = postBuildCmdLine;
  405. } else {
  406. vars["POST_BUILD"] = ":";
  407. symlinkVars["POST_BUILD"] = postBuildCmdLine;
  408. }
  409. // Write the build statement for this target.
  410. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
  411. comment.str(),
  412. this->LanguageLinkerRule(),
  413. outputs,
  414. explicitDeps,
  415. implicitDeps,
  416. emptyDeps,
  417. vars);
  418. if (targetOutput != targetOutputReal) {
  419. if (targetType == cmTarget::EXECUTABLE) {
  420. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
  421. "Create executable symlink " + targetOutput,
  422. "CMAKE_SYMLINK_EXECUTABLE",
  423. cmNinjaDeps(1, targetOutput),
  424. cmNinjaDeps(1, targetOutputReal),
  425. emptyDeps,
  426. emptyDeps,
  427. symlinkVars);
  428. } else {
  429. symlinkVars["SONAME"] = this->GetTargetFilePath(this->TargetNameSO);
  430. cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(),
  431. "Create library symlink " + targetOutput,
  432. "CMAKE_SYMLINK_LIBRARY",
  433. cmNinjaDeps(1, targetOutput),
  434. cmNinjaDeps(1, targetOutputReal),
  435. emptyDeps,
  436. emptyDeps,
  437. symlinkVars);
  438. }
  439. }
  440. if (!this->TargetNameImport.empty()) {
  441. // Since using multiple outputs would mess up the $out variable, use an
  442. // alias for the import library.
  443. cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
  444. "Alias for import library.",
  445. cmNinjaDeps(1, targetOutputImplib),
  446. cmNinjaDeps(1, targetOutputReal));
  447. }
  448. // Add aliases for the file name and the target name.
  449. this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut,
  450. this->GetTarget());
  451. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
  452. this->GetTarget());
  453. }
  454. //----------------------------------------------------------------------------
  455. void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
  456. {
  457. // Write a phony output that depends on all object files.
  458. cmNinjaDeps outputs;
  459. this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs);
  460. cmNinjaDeps depends = this->GetObjects();
  461. cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(),
  462. "Object library "
  463. + this->GetTargetName(),
  464. outputs,
  465. depends);
  466. // Add aliases for the target name.
  467. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
  468. this->GetTarget());
  469. }