cmNinjaNormalTargetGenerator.cxx 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing for details. */
  3. #include "cmNinjaNormalTargetGenerator.h"
  4. #include <algorithm>
  5. #include <assert.h>
  6. #include <iterator>
  7. #include <map>
  8. #include <memory> // IWYU pragma: keep
  9. #include <set>
  10. #include <sstream>
  11. #include <utility>
  12. #include "cmAlgorithms.h"
  13. #include "cmCustomCommand.h" // IWYU pragma: keep
  14. #include "cmCustomCommandGenerator.h"
  15. #include "cmGeneratedFileStream.h"
  16. #include "cmGeneratorTarget.h"
  17. #include "cmGlobalNinjaGenerator.h"
  18. #include "cmLinkLineComputer.h"
  19. #include "cmLinkLineDeviceComputer.h"
  20. #include "cmLocalGenerator.h"
  21. #include "cmLocalNinjaGenerator.h"
  22. #include "cmMakefile.h"
  23. #include "cmNinjaTypes.h"
  24. #include "cmOSXBundleGenerator.h"
  25. #include "cmOutputConverter.h"
  26. #include "cmRulePlaceholderExpander.h"
  27. #include "cmSourceFile.h"
  28. #include "cmState.h"
  29. #include "cmStateDirectory.h"
  30. #include "cmStateSnapshot.h"
  31. #include "cmStateTypes.h"
  32. #include "cmSystemTools.h"
  33. cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
  34. cmGeneratorTarget* target)
  35. : cmNinjaTargetGenerator(target)
  36. , TargetLinkLanguage("")
  37. {
  38. this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
  39. if (target->GetType() == cmStateEnums::EXECUTABLE) {
  40. this->TargetNames = this->GetGeneratorTarget()->GetExecutableNames(
  41. GetLocalGenerator()->GetConfigName());
  42. } else {
  43. this->TargetNames = this->GetGeneratorTarget()->GetLibraryNames(
  44. GetLocalGenerator()->GetConfigName());
  45. }
  46. if (target->GetType() != cmStateEnums::OBJECT_LIBRARY) {
  47. // on Windows the output dir is already needed at compile time
  48. // ensure the directory exists (OutDir test)
  49. EnsureDirectoryExists(target->GetDirectory(this->GetConfigName()));
  50. }
  51. this->OSXBundleGenerator =
  52. new cmOSXBundleGenerator(target, this->GetConfigName());
  53. this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
  54. }
  55. cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
  56. {
  57. delete this->OSXBundleGenerator;
  58. }
  59. void cmNinjaNormalTargetGenerator::Generate()
  60. {
  61. if (this->TargetLinkLanguage.empty()) {
  62. cmSystemTools::Error("CMake can not determine linker language for "
  63. "target: " +
  64. this->GetGeneratorTarget()->GetName());
  65. return;
  66. }
  67. // Write the rules for each language.
  68. this->WriteLanguagesRules();
  69. // Write the build statements
  70. this->WriteObjectBuildStatements();
  71. if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  72. this->WriteObjectLibStatement();
  73. } else {
  74. // If this target has cuda language link inputs, and we need to do
  75. // device linking
  76. this->WriteDeviceLinkStatement();
  77. this->WriteLinkStatement();
  78. }
  79. }
  80. void cmNinjaNormalTargetGenerator::WriteLanguagesRules()
  81. {
  82. #ifdef NINJA_GEN_VERBOSE_FILES
  83. cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
  84. this->GetRulesFileStream()
  85. << "# Rules for each languages for "
  86. << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
  87. << " target " << this->GetTargetName() << "\n\n";
  88. #endif
  89. // Write rules for languages compiled in this target.
  90. std::set<std::string> languages;
  91. std::vector<cmSourceFile const*> sourceFiles;
  92. this->GetGeneratorTarget()->GetObjectSources(
  93. sourceFiles, this->GetMakefile()->GetSafeDefinition("CMAKE_BUILD_TYPE"));
  94. for (cmSourceFile const* sf : sourceFiles) {
  95. std::string const lang = sf->GetLanguage();
  96. if (!lang.empty()) {
  97. languages.insert(lang);
  98. }
  99. }
  100. for (std::string const& language : languages) {
  101. this->WriteLanguageRules(language);
  102. }
  103. }
  104. const char* cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
  105. {
  106. switch (this->GetGeneratorTarget()->GetType()) {
  107. case cmStateEnums::STATIC_LIBRARY:
  108. return "static library";
  109. case cmStateEnums::SHARED_LIBRARY:
  110. return "shared library";
  111. case cmStateEnums::MODULE_LIBRARY:
  112. if (this->GetGeneratorTarget()->IsCFBundleOnApple()) {
  113. return "CFBundle shared module";
  114. } else {
  115. return "shared module";
  116. }
  117. case cmStateEnums::EXECUTABLE:
  118. return "executable";
  119. default:
  120. return nullptr;
  121. }
  122. }
  123. std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule() const
  124. {
  125. return this->TargetLinkLanguage + "_" +
  126. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
  127. "_LINKER__" +
  128. cmGlobalNinjaGenerator::EncodeRuleName(
  129. this->GetGeneratorTarget()->GetName());
  130. }
  131. std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule() const
  132. {
  133. return this->TargetLinkLanguage + "_" +
  134. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()) +
  135. "_DEVICE_LINKER__" +
  136. cmGlobalNinjaGenerator::EncodeRuleName(
  137. this->GetGeneratorTarget()->GetName());
  138. }
  139. struct cmNinjaRemoveNoOpCommands
  140. {
  141. bool operator()(std::string const& cmd)
  142. {
  143. return cmd.empty() || cmd[0] == ':';
  144. }
  145. };
  146. void cmNinjaNormalTargetGenerator::WriteDeviceLinkRule(bool useResponseFile)
  147. {
  148. cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
  149. std::string ruleName = this->LanguageLinkerDeviceRule();
  150. // Select whether to use a response file for objects.
  151. std::string rspfile;
  152. std::string rspcontent;
  153. if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
  154. cmRulePlaceholderExpander::RuleVariables vars;
  155. vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
  156. vars.CMTargetType =
  157. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
  158. vars.Language = "CUDA";
  159. std::string responseFlag;
  160. if (!useResponseFile) {
  161. vars.Objects = "$in";
  162. vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
  163. } else {
  164. std::string cmakeVarLang = "CMAKE_";
  165. cmakeVarLang += this->TargetLinkLanguage;
  166. // build response file name
  167. std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
  168. const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
  169. if (flag) {
  170. responseFlag = flag;
  171. } else {
  172. responseFlag = "@";
  173. }
  174. rspfile = "$RSP_FILE";
  175. responseFlag += rspfile;
  176. // build response file content
  177. if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
  178. rspcontent = "$in";
  179. } else {
  180. rspcontent = "$in_newline";
  181. }
  182. rspcontent += " $LINK_LIBRARIES";
  183. vars.Objects = responseFlag.c_str();
  184. vars.LinkLibraries = "";
  185. }
  186. vars.ObjectDir = "$OBJECT_DIR";
  187. vars.Target = "$TARGET_FILE";
  188. vars.SONameFlag = "$SONAME_FLAG";
  189. vars.TargetSOName = "$SONAME";
  190. vars.TargetPDB = "$TARGET_PDB";
  191. vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
  192. vars.Flags = "$FLAGS";
  193. vars.LinkFlags = "$LINK_FLAGS";
  194. vars.Manifests = "$MANIFESTS";
  195. std::string langFlags;
  196. if (targetType != cmStateEnums::EXECUTABLE) {
  197. langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
  198. vars.LanguageCompileFlags = langFlags.c_str();
  199. }
  200. std::string launcher;
  201. const char* val = this->GetLocalGenerator()->GetRuleLauncher(
  202. this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
  203. if (val && *val) {
  204. launcher = val;
  205. launcher += " ";
  206. }
  207. std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
  208. this->GetLocalGenerator()->CreateRulePlaceholderExpander());
  209. // Rule for linking library/executable.
  210. std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd();
  211. for (std::string& linkCmd : linkCmds) {
  212. linkCmd = launcher + linkCmd;
  213. rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  214. linkCmd, vars);
  215. }
  216. // If there is no ranlib the command will be ":". Skip it.
  217. cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
  218. std::string linkCmd =
  219. this->GetLocalGenerator()->BuildCommandLine(linkCmds);
  220. // Write the linker rule with response file if needed.
  221. std::ostringstream comment;
  222. comment << "Rule for linking " << this->TargetLinkLanguage << " "
  223. << this->GetVisibleTypeName() << ".";
  224. std::ostringstream description;
  225. description << "Linking " << this->TargetLinkLanguage << " "
  226. << this->GetVisibleTypeName() << " $TARGET_FILE";
  227. this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
  228. comment.str(),
  229. /*depfile*/ "",
  230. /*deptype*/ "", rspfile, rspcontent,
  231. /*restat*/ "$RESTAT",
  232. /*generator*/ false);
  233. }
  234. }
  235. void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile)
  236. {
  237. cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
  238. std::string ruleName = this->LanguageLinkerRule();
  239. // Select whether to use a response file for objects.
  240. std::string rspfile;
  241. std::string rspcontent;
  242. if (!this->GetGlobalGenerator()->HasRule(ruleName)) {
  243. cmRulePlaceholderExpander::RuleVariables vars;
  244. vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
  245. vars.CMTargetType =
  246. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType());
  247. vars.Language = this->TargetLinkLanguage.c_str();
  248. if (this->TargetLinkLanguage == "Swift") {
  249. vars.SwiftPartialModules = "$SWIFT_PARTIAL_MODULES";
  250. vars.TargetSwiftModule = "$TARGET_SWIFT_MODULE";
  251. vars.TargetSwiftDoc = "$TARGET_SWIFT_DOC";
  252. }
  253. std::string responseFlag;
  254. if (!useResponseFile) {
  255. vars.Objects = "$in";
  256. vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
  257. } else {
  258. std::string cmakeVarLang = "CMAKE_";
  259. cmakeVarLang += this->TargetLinkLanguage;
  260. // build response file name
  261. std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
  262. const char* flag = GetMakefile()->GetDefinition(cmakeLinkVar);
  263. if (flag) {
  264. responseFlag = flag;
  265. } else {
  266. responseFlag = "@";
  267. }
  268. rspfile = "$RSP_FILE";
  269. responseFlag += rspfile;
  270. // build response file content
  271. if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
  272. rspcontent = "$in";
  273. } else {
  274. rspcontent = "$in_newline";
  275. }
  276. rspcontent += " $LINK_PATH $LINK_LIBRARIES";
  277. vars.Objects = responseFlag.c_str();
  278. vars.LinkLibraries = "";
  279. }
  280. vars.ObjectDir = "$OBJECT_DIR";
  281. vars.Target = "$TARGET_FILE";
  282. vars.SONameFlag = "$SONAME_FLAG";
  283. vars.TargetSOName = "$SONAME";
  284. vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
  285. vars.TargetPDB = "$TARGET_PDB";
  286. // Setup the target version.
  287. std::string targetVersionMajor;
  288. std::string targetVersionMinor;
  289. {
  290. std::ostringstream majorStream;
  291. std::ostringstream minorStream;
  292. int major;
  293. int minor;
  294. this->GetGeneratorTarget()->GetTargetVersion(major, minor);
  295. majorStream << major;
  296. minorStream << minor;
  297. targetVersionMajor = majorStream.str();
  298. targetVersionMinor = minorStream.str();
  299. }
  300. vars.TargetVersionMajor = targetVersionMajor.c_str();
  301. vars.TargetVersionMinor = targetVersionMinor.c_str();
  302. vars.Flags = "$FLAGS";
  303. vars.LinkFlags = "$LINK_FLAGS";
  304. vars.Manifests = "$MANIFESTS";
  305. std::string langFlags;
  306. if (targetType != cmStateEnums::EXECUTABLE) {
  307. langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
  308. vars.LanguageCompileFlags = langFlags.c_str();
  309. }
  310. std::string launcher;
  311. const char* val = this->GetLocalGenerator()->GetRuleLauncher(
  312. this->GetGeneratorTarget(), "RULE_LAUNCH_LINK");
  313. if (val && *val) {
  314. launcher = val;
  315. launcher += " ";
  316. }
  317. std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
  318. this->GetLocalGenerator()->CreateRulePlaceholderExpander());
  319. // Rule for linking library/executable.
  320. std::vector<std::string> linkCmds = this->ComputeLinkCmd();
  321. for (std::string& linkCmd : linkCmds) {
  322. linkCmd = launcher + linkCmd;
  323. rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  324. linkCmd, vars);
  325. }
  326. // If there is no ranlib the command will be ":". Skip it.
  327. cmEraseIf(linkCmds, cmNinjaRemoveNoOpCommands());
  328. linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
  329. linkCmds.emplace_back("$POST_BUILD");
  330. std::string linkCmd =
  331. this->GetLocalGenerator()->BuildCommandLine(linkCmds);
  332. // Write the linker rule with response file if needed.
  333. std::ostringstream comment;
  334. comment << "Rule for linking " << this->TargetLinkLanguage << " "
  335. << this->GetVisibleTypeName() << ".";
  336. std::ostringstream description;
  337. description << "Linking " << this->TargetLinkLanguage << " "
  338. << this->GetVisibleTypeName() << " $TARGET_FILE";
  339. this->GetGlobalGenerator()->AddRule(ruleName, linkCmd, description.str(),
  340. comment.str(),
  341. /*depfile*/ "",
  342. /*deptype*/ "", rspfile, rspcontent,
  343. /*restat*/ "$RESTAT",
  344. /*generator*/ false);
  345. }
  346. if (this->TargetNames.Output != this->TargetNames.Real &&
  347. !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
  348. std::string cmakeCommand =
  349. this->GetLocalGenerator()->ConvertToOutputFormat(
  350. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  351. if (targetType == cmStateEnums::EXECUTABLE) {
  352. std::vector<std::string> commandLines;
  353. commandLines.push_back(cmakeCommand +
  354. " -E cmake_symlink_executable $in $out");
  355. commandLines.emplace_back("$POST_BUILD");
  356. this->GetGlobalGenerator()->AddRule(
  357. "CMAKE_SYMLINK_EXECUTABLE",
  358. this->GetLocalGenerator()->BuildCommandLine(commandLines),
  359. "Creating executable symlink $out",
  360. "Rule for creating "
  361. "executable symlink.",
  362. /*depfile*/ "",
  363. /*deptype*/ "",
  364. /*rspfile*/ "",
  365. /*rspcontent*/ "",
  366. /*restat*/ "",
  367. /*generator*/ false);
  368. } else {
  369. std::vector<std::string> commandLines;
  370. commandLines.push_back(cmakeCommand +
  371. " -E cmake_symlink_library $in $SONAME $out");
  372. commandLines.emplace_back("$POST_BUILD");
  373. this->GetGlobalGenerator()->AddRule(
  374. "CMAKE_SYMLINK_LIBRARY",
  375. this->GetLocalGenerator()->BuildCommandLine(commandLines),
  376. "Creating library symlink $out",
  377. "Rule for creating "
  378. "library symlink.",
  379. /*depfile*/ "",
  380. /*deptype*/ "",
  381. /*rspfile*/ "",
  382. /*rspcontent*/ "",
  383. /*restat*/ "",
  384. /*generator*/ false);
  385. }
  386. }
  387. }
  388. std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd()
  389. {
  390. std::vector<std::string> linkCmds;
  391. // this target requires separable cuda compilation
  392. // now build the correct command depending on if the target is
  393. // an executable or a dynamic library.
  394. std::string linkCmd;
  395. switch (this->GetGeneratorTarget()->GetType()) {
  396. case cmStateEnums::STATIC_LIBRARY:
  397. case cmStateEnums::SHARED_LIBRARY:
  398. case cmStateEnums::MODULE_LIBRARY: {
  399. const std::string cudaLinkCmd(
  400. this->GetMakefile()->GetDefinition("CMAKE_CUDA_DEVICE_LINK_LIBRARY"));
  401. cmSystemTools::ExpandListArgument(cudaLinkCmd, linkCmds);
  402. } break;
  403. case cmStateEnums::EXECUTABLE: {
  404. const std::string cudaLinkCmd(this->GetMakefile()->GetDefinition(
  405. "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE"));
  406. cmSystemTools::ExpandListArgument(cudaLinkCmd, linkCmds);
  407. } break;
  408. default:
  409. break;
  410. }
  411. return linkCmds;
  412. }
  413. std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd()
  414. {
  415. std::vector<std::string> linkCmds;
  416. cmMakefile* mf = this->GetMakefile();
  417. {
  418. // If we have a rule variable prefer it. In the case of static libraries
  419. // this occurs when things like IPO is enabled, and we need to use the
  420. // CMAKE_<lang>_CREATE_STATIC_LIBRARY_IPO define instead.
  421. std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable(
  422. this->TargetLinkLanguage, this->GetConfigName());
  423. const char* linkCmd = mf->GetDefinition(linkCmdVar);
  424. if (linkCmd) {
  425. std::string linkCmdStr = linkCmd;
  426. if (this->GetGeneratorTarget()->HasImplibGNUtoMS(this->ConfigName)) {
  427. std::string ruleVar = "CMAKE_";
  428. ruleVar += this->GeneratorTarget->GetLinkerLanguage(this->ConfigName);
  429. ruleVar += "_GNUtoMS_RULE";
  430. if (const char* rule = this->Makefile->GetDefinition(ruleVar)) {
  431. linkCmdStr += rule;
  432. }
  433. }
  434. cmSystemTools::ExpandListArgument(linkCmdStr, linkCmds);
  435. if (this->GetGeneratorTarget()->GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
  436. std::string cmakeCommand =
  437. this->GetLocalGenerator()->ConvertToOutputFormat(
  438. cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL);
  439. cmakeCommand += " -E __run_co_compile --lwyu=";
  440. cmGeneratorTarget& gt = *this->GetGeneratorTarget();
  441. const std::string cfgName = this->GetConfigName();
  442. std::string targetOutputReal = this->ConvertToNinjaPath(
  443. gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
  444. /*realname=*/true));
  445. cmakeCommand += targetOutputReal;
  446. linkCmds.push_back(std::move(cmakeCommand));
  447. }
  448. return linkCmds;
  449. }
  450. }
  451. switch (this->GetGeneratorTarget()->GetType()) {
  452. case cmStateEnums::STATIC_LIBRARY: {
  453. // We have archive link commands set. First, delete the existing archive.
  454. {
  455. std::string cmakeCommand =
  456. this->GetLocalGenerator()->ConvertToOutputFormat(
  457. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  458. linkCmds.push_back(cmakeCommand + " -E remove $TARGET_FILE");
  459. }
  460. // TODO: Use ARCHIVE_APPEND for archives over a certain size.
  461. {
  462. std::string linkCmdVar = "CMAKE_";
  463. linkCmdVar += this->TargetLinkLanguage;
  464. linkCmdVar += "_ARCHIVE_CREATE";
  465. linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
  466. linkCmdVar, this->TargetLinkLanguage, this->GetConfigName());
  467. std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
  468. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  469. }
  470. {
  471. std::string linkCmdVar = "CMAKE_";
  472. linkCmdVar += this->TargetLinkLanguage;
  473. linkCmdVar += "_ARCHIVE_FINISH";
  474. linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
  475. linkCmdVar, this->TargetLinkLanguage, this->GetConfigName());
  476. std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
  477. cmSystemTools::ExpandListArgument(linkCmd, linkCmds);
  478. }
  479. return linkCmds;
  480. }
  481. case cmStateEnums::SHARED_LIBRARY:
  482. case cmStateEnums::MODULE_LIBRARY:
  483. case cmStateEnums::EXECUTABLE:
  484. break;
  485. default:
  486. assert(false && "Unexpected target type");
  487. }
  488. return std::vector<std::string>();
  489. }
  490. void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
  491. {
  492. if (!this->GetGlobalGenerator()->GetLanguageEnabled("CUDA")) {
  493. return;
  494. }
  495. cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
  496. // determine if we need to do any device linking for this target
  497. const std::string cuda_lang("CUDA");
  498. cmGeneratorTarget::LinkClosure const* closure =
  499. genTarget.GetLinkClosure(this->GetConfigName());
  500. const bool hasCUDA =
  501. (std::find(closure->Languages.begin(), closure->Languages.end(),
  502. cuda_lang) != closure->Languages.end());
  503. bool doDeviceLinking = false;
  504. if (const char* resolveDeviceSymbols =
  505. genTarget.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
  506. doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
  507. } else {
  508. switch (genTarget.GetType()) {
  509. case cmStateEnums::SHARED_LIBRARY:
  510. case cmStateEnums::MODULE_LIBRARY:
  511. case cmStateEnums::EXECUTABLE:
  512. doDeviceLinking = true;
  513. break;
  514. default:
  515. break;
  516. }
  517. }
  518. if (!(doDeviceLinking && hasCUDA)) {
  519. return;
  520. }
  521. // Now we can do device linking
  522. // First and very important step is to make sure while inside this
  523. // step our link language is set to CUDA
  524. std::string cudaLinkLanguage = "CUDA";
  525. std::string const objExt =
  526. this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
  527. std::string const cfgName = this->GetConfigName();
  528. std::string const targetOutputReal = ConvertToNinjaPath(
  529. genTarget.ObjectDirectory + "cmake_device_link" + objExt);
  530. std::string const targetOutputImplib = ConvertToNinjaPath(
  531. genTarget.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
  532. this->DeviceLinkObject = targetOutputReal;
  533. // Write comments.
  534. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
  535. const cmStateEnums::TargetType targetType = genTarget.GetType();
  536. this->GetBuildFileStream() << "# Device Link build statements for "
  537. << cmState::GetTargetTypeName(targetType)
  538. << " target " << this->GetTargetName() << "\n\n";
  539. // Compute the comment.
  540. std::ostringstream comment;
  541. comment << "Link the " << this->GetVisibleTypeName() << " "
  542. << targetOutputReal;
  543. cmNinjaDeps emptyDeps;
  544. cmNinjaVars vars;
  545. // Compute outputs.
  546. cmNinjaDeps outputs;
  547. outputs.push_back(targetOutputReal);
  548. // Compute specific libraries to link with.
  549. cmNinjaDeps explicitDeps = this->GetObjects();
  550. cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
  551. std::string frameworkPath;
  552. std::string linkPath;
  553. std::string createRule = genTarget.GetCreateRuleVariable(
  554. this->TargetLinkLanguage, this->GetConfigName());
  555. const bool useWatcomQuote =
  556. this->GetMakefile()->IsOn(createRule + "_USE_WATCOM_QUOTE");
  557. cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
  558. vars["TARGET_FILE"] =
  559. localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
  560. std::unique_ptr<cmLinkLineComputer> linkLineComputer(
  561. new cmNinjaLinkLineDeviceComputer(
  562. this->GetLocalGenerator(),
  563. this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(),
  564. this->GetGlobalGenerator()));
  565. linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
  566. localGen.GetTargetFlags(
  567. linkLineComputer.get(), this->GetConfigName(), vars["LINK_LIBRARIES"],
  568. vars["FLAGS"], vars["LINK_FLAGS"], frameworkPath, linkPath, &genTarget);
  569. this->addPoolNinjaVariable("JOB_POOL_LINK", &genTarget, vars);
  570. vars["LINK_FLAGS"] =
  571. cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
  572. vars["MANIFESTS"] = this->GetManifests();
  573. vars["LINK_PATH"] = frameworkPath + linkPath;
  574. // Compute architecture specific link flags. Yes, these go into a different
  575. // variable for executables, probably due to a mistake made when duplicating
  576. // code between the Makefile executable and library generators.
  577. if (targetType == cmStateEnums::EXECUTABLE) {
  578. std::string t = vars["FLAGS"];
  579. localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName);
  580. vars["FLAGS"] = t;
  581. } else {
  582. std::string t = vars["ARCH_FLAGS"];
  583. localGen.AddArchitectureFlags(t, &genTarget, cudaLinkLanguage, cfgName);
  584. vars["ARCH_FLAGS"] = t;
  585. t.clear();
  586. localGen.AddLanguageFlagsForLinking(t, &genTarget, cudaLinkLanguage,
  587. cfgName);
  588. vars["LANGUAGE_COMPILE_FLAGS"] = t;
  589. }
  590. if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
  591. vars["SONAME_FLAG"] =
  592. this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage);
  593. vars["SONAME"] = this->TargetNames.SharedObject;
  594. if (targetType == cmStateEnums::SHARED_LIBRARY) {
  595. std::string install_dir =
  596. this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
  597. if (!install_dir.empty()) {
  598. vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
  599. install_dir, cmOutputConverter::SHELL);
  600. }
  601. }
  602. }
  603. if (!this->TargetNames.ImportLibrary.empty()) {
  604. const std::string impLibPath = localGen.ConvertToOutputFormat(
  605. targetOutputImplib, cmOutputConverter::SHELL);
  606. vars["TARGET_IMPLIB"] = impLibPath;
  607. EnsureParentDirectoryExists(impLibPath);
  608. }
  609. const std::string objPath = GetGeneratorTarget()->GetSupportDirectory();
  610. vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
  611. this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
  612. EnsureDirectoryExists(objPath);
  613. this->SetMsvcTargetPdbVariable(vars);
  614. if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
  615. // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
  616. std::string& linkLibraries = vars["LINK_LIBRARIES"];
  617. std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
  618. std::string& link_path = vars["LINK_PATH"];
  619. std::replace(link_path.begin(), link_path.end(), '\\', '/');
  620. }
  621. cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
  622. // Device linking currently doesn't support response files so
  623. // do not check if the user has explicitly forced a response file.
  624. int const commandLineLengthLimit =
  625. static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
  626. globalGen.GetRuleCmdLength(this->LanguageLinkerDeviceRule());
  627. const std::string rspfile = this->ConvertToNinjaPath(
  628. std::string("CMakeFiles/") + genTarget.GetName() + ".rsp");
  629. // Gather order-only dependencies.
  630. cmNinjaDeps orderOnlyDeps;
  631. this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
  632. orderOnlyDeps);
  633. // Write the build statement for this target.
  634. bool usedResponseFile = false;
  635. globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
  636. this->LanguageLinkerDeviceRule(), outputs,
  637. /*implicitOuts=*/cmNinjaDeps(), explicitDeps,
  638. implicitDeps, orderOnlyDeps, vars, rspfile,
  639. commandLineLengthLimit, &usedResponseFile);
  640. this->WriteDeviceLinkRule(false);
  641. }
  642. void cmNinjaNormalTargetGenerator::WriteLinkStatement()
  643. {
  644. cmGeneratorTarget& gt = *this->GetGeneratorTarget();
  645. const std::string cfgName = this->GetConfigName();
  646. std::string targetOutput = ConvertToNinjaPath(gt.GetFullPath(cfgName));
  647. std::string targetOutputReal = ConvertToNinjaPath(
  648. gt.GetFullPath(cfgName, cmStateEnums::RuntimeBinaryArtifact,
  649. /*realname=*/true));
  650. std::string targetOutputImplib = ConvertToNinjaPath(
  651. gt.GetFullPath(cfgName, cmStateEnums::ImportLibraryArtifact));
  652. if (gt.IsAppBundleOnApple()) {
  653. // Create the app bundle
  654. std::string outpath = gt.GetDirectory(cfgName);
  655. this->OSXBundleGenerator->CreateAppBundle(this->TargetNames.Output,
  656. outpath);
  657. // Calculate the output path
  658. targetOutput = outpath;
  659. targetOutput += "/";
  660. targetOutput += this->TargetNames.Output;
  661. targetOutput = this->ConvertToNinjaPath(targetOutput);
  662. targetOutputReal = outpath;
  663. targetOutputReal += "/";
  664. targetOutputReal += this->TargetNames.Real;
  665. targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
  666. } else if (gt.IsFrameworkOnApple()) {
  667. // Create the library framework.
  668. this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output,
  669. gt.GetDirectory(cfgName));
  670. } else if (gt.IsCFBundleOnApple()) {
  671. // Create the core foundation bundle.
  672. this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output,
  673. gt.GetDirectory(cfgName));
  674. }
  675. // Write comments.
  676. cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
  677. const cmStateEnums::TargetType targetType = gt.GetType();
  678. this->GetBuildFileStream()
  679. << "# Link build statements for " << cmState::GetTargetTypeName(targetType)
  680. << " target " << this->GetTargetName() << "\n\n";
  681. cmNinjaDeps emptyDeps;
  682. cmNinjaVars vars;
  683. // Compute the comment.
  684. std::ostringstream comment;
  685. comment << "Link the " << this->GetVisibleTypeName() << " "
  686. << targetOutputReal;
  687. // Compute outputs.
  688. cmNinjaDeps outputs;
  689. outputs.push_back(targetOutputReal);
  690. if (this->TargetLinkLanguage == "Swift") {
  691. if (const char* name = gt.GetProperty("SWIFT_MODULE_NAME")) {
  692. vars["TARGET_SWIFT_DOC"] = std::string(name) + ".swiftdoc";
  693. vars["TARGET_SWIFT_MODULE"] = std::string(name) + ".swiftmodule";
  694. } else {
  695. vars["TARGET_SWIFT_DOC"] = gt.GetName() + ".swiftdoc";
  696. vars["TARGET_SWIFT_MODULE"] = gt.GetName() + ".swiftmodule";
  697. }
  698. outputs.push_back(vars["TARGET_SWIFT_DOC"]);
  699. outputs.push_back(vars["TARGET_SWIFT_MODULE"]);
  700. cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
  701. std::string partials;
  702. std::vector<cmSourceFile const*> sources;
  703. gt.GetObjectSources(sources, this->GetConfigName());
  704. for (cmSourceFile const* source : sources) {
  705. partials += " ";
  706. if (const char* partial = source->GetProperty("SWIFT_PARTIAL_MODULE")) {
  707. partials += partial;
  708. } else {
  709. partials += localGen.GetTargetDirectory(&gt) + "/" +
  710. gt.GetObjectName(source) + ".swiftmodule";
  711. }
  712. }
  713. vars["SWIFT_PARTIAL_MODULES"] = partials;
  714. }
  715. // Compute specific libraries to link with.
  716. cmNinjaDeps explicitDeps = this->GetObjects();
  717. cmNinjaDeps implicitDeps = this->ComputeLinkDeps(this->TargetLinkLanguage);
  718. if (!this->DeviceLinkObject.empty()) {
  719. explicitDeps.push_back(this->DeviceLinkObject);
  720. }
  721. cmMakefile* mf = this->GetMakefile();
  722. std::string frameworkPath;
  723. std::string linkPath;
  724. std::string createRule =
  725. gt.GetCreateRuleVariable(this->TargetLinkLanguage, this->GetConfigName());
  726. bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
  727. cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
  728. vars["TARGET_FILE"] =
  729. localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
  730. std::unique_ptr<cmLinkLineComputer> linkLineComputer(
  731. this->GetGlobalGenerator()->CreateLinkLineComputer(
  732. this->GetLocalGenerator(),
  733. this->GetLocalGenerator()->GetStateSnapshot().GetDirectory()));
  734. linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
  735. localGen.GetTargetFlags(linkLineComputer.get(), this->GetConfigName(),
  736. vars["LINK_LIBRARIES"], vars["FLAGS"],
  737. vars["LINK_FLAGS"], frameworkPath, linkPath, &gt);
  738. // Add OS X version flags, if any.
  739. if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
  740. this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
  741. this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage,
  742. "COMPATIBILITY", true);
  743. this->AppendOSXVerFlag(vars["LINK_FLAGS"], this->TargetLinkLanguage,
  744. "CURRENT", false);
  745. }
  746. this->addPoolNinjaVariable("JOB_POOL_LINK", &gt, vars);
  747. this->AddModuleDefinitionFlag(linkLineComputer.get(), vars["LINK_FLAGS"]);
  748. vars["LINK_FLAGS"] =
  749. cmGlobalNinjaGenerator::EncodeLiteral(vars["LINK_FLAGS"]);
  750. vars["MANIFESTS"] = this->GetManifests();
  751. vars["LINK_PATH"] = frameworkPath + linkPath;
  752. std::string lwyuFlags;
  753. if (gt.GetPropertyAsBool("LINK_WHAT_YOU_USE")) {
  754. lwyuFlags = " -Wl,--no-as-needed";
  755. }
  756. // Compute architecture specific link flags. Yes, these go into a different
  757. // variable for executables, probably due to a mistake made when duplicating
  758. // code between the Makefile executable and library generators.
  759. if (targetType == cmStateEnums::EXECUTABLE) {
  760. std::string t = vars["FLAGS"];
  761. localGen.AddArchitectureFlags(t, &gt, TargetLinkLanguage, cfgName);
  762. t += lwyuFlags;
  763. vars["FLAGS"] = t;
  764. } else {
  765. std::string t = vars["ARCH_FLAGS"];
  766. localGen.AddArchitectureFlags(t, &gt, TargetLinkLanguage, cfgName);
  767. vars["ARCH_FLAGS"] = t;
  768. t.clear();
  769. t += lwyuFlags;
  770. localGen.AddLanguageFlagsForLinking(t, &gt, TargetLinkLanguage, cfgName);
  771. vars["LANGUAGE_COMPILE_FLAGS"] = t;
  772. }
  773. if (this->GetGeneratorTarget()->HasSOName(cfgName)) {
  774. vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage);
  775. vars["SONAME"] = this->TargetNames.SharedObject;
  776. if (targetType == cmStateEnums::SHARED_LIBRARY) {
  777. std::string install_dir =
  778. this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(cfgName);
  779. if (!install_dir.empty()) {
  780. vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
  781. install_dir, cmOutputConverter::SHELL);
  782. }
  783. }
  784. }
  785. cmNinjaDeps byproducts;
  786. if (!this->TargetNames.ImportLibrary.empty()) {
  787. const std::string impLibPath = localGen.ConvertToOutputFormat(
  788. targetOutputImplib, cmOutputConverter::SHELL);
  789. vars["TARGET_IMPLIB"] = impLibPath;
  790. EnsureParentDirectoryExists(impLibPath);
  791. if (gt.HasImportLibrary(cfgName)) {
  792. byproducts.push_back(targetOutputImplib);
  793. }
  794. }
  795. if (!this->SetMsvcTargetPdbVariable(vars)) {
  796. // It is common to place debug symbols at a specific place,
  797. // so we need a plain target name in the rule available.
  798. std::string prefix;
  799. std::string base;
  800. std::string suffix;
  801. this->GetGeneratorTarget()->GetFullNameComponents(prefix, base, suffix);
  802. std::string dbg_suffix = ".dbg";
  803. // TODO: Where to document?
  804. if (mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
  805. dbg_suffix = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX");
  806. }
  807. vars["TARGET_PDB"] = base + suffix + dbg_suffix;
  808. }
  809. const std::string objPath = GetGeneratorTarget()->GetSupportDirectory();
  810. vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
  811. this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
  812. EnsureDirectoryExists(objPath);
  813. if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
  814. // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
  815. std::string& linkLibraries = vars["LINK_LIBRARIES"];
  816. std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
  817. std::string& link_path = vars["LINK_PATH"];
  818. std::replace(link_path.begin(), link_path.end(), '\\', '/');
  819. }
  820. const std::vector<cmCustomCommand>* cmdLists[3] = {
  821. &gt.GetPreBuildCommands(), &gt.GetPreLinkCommands(),
  822. &gt.GetPostBuildCommands()
  823. };
  824. std::vector<std::string> preLinkCmdLines, postBuildCmdLines;
  825. std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
  826. &preLinkCmdLines,
  827. &postBuildCmdLines };
  828. for (unsigned i = 0; i != 3; ++i) {
  829. for (cmCustomCommand const& cc : *cmdLists[i]) {
  830. cmCustomCommandGenerator ccg(cc, cfgName, this->GetLocalGenerator());
  831. localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
  832. std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
  833. std::transform(ccByproducts.begin(), ccByproducts.end(),
  834. std::back_inserter(byproducts), MapToNinjaPath());
  835. }
  836. }
  837. // maybe create .def file from list of objects
  838. cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
  839. gt.GetModuleDefinitionInfo(this->GetConfigName());
  840. if (mdi && mdi->DefFileGenerated) {
  841. std::string cmakeCommand =
  842. this->GetLocalGenerator()->ConvertToOutputFormat(
  843. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  844. std::string cmd = cmakeCommand;
  845. cmd += " -E __create_def ";
  846. cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
  847. mdi->DefFile, cmOutputConverter::SHELL);
  848. cmd += " ";
  849. std::string obj_list_file = mdi->DefFile + ".objs";
  850. cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
  851. obj_list_file, cmOutputConverter::SHELL);
  852. preLinkCmdLines.push_back(std::move(cmd));
  853. // create a list of obj files for the -E __create_def to read
  854. cmGeneratedFileStream fout(obj_list_file);
  855. if (mdi->WindowsExportAllSymbols) {
  856. cmNinjaDeps objs = this->GetObjects();
  857. for (std::string const& obj : objs) {
  858. if (cmHasLiteralSuffix(obj, ".obj")) {
  859. fout << obj << "\n";
  860. }
  861. }
  862. }
  863. for (cmSourceFile const* src : mdi->Sources) {
  864. fout << src->GetFullPath() << "\n";
  865. }
  866. }
  867. // If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR
  868. // for
  869. // the link commands.
  870. if (!preLinkCmdLines.empty()) {
  871. const std::string homeOutDir = localGen.ConvertToOutputFormat(
  872. localGen.GetBinaryDirectory(), cmOutputConverter::SHELL);
  873. preLinkCmdLines.push_back("cd " + homeOutDir);
  874. }
  875. vars["PRE_LINK"] = localGen.BuildCommandLine(preLinkCmdLines, "pre-link",
  876. this->GeneratorTarget);
  877. std::string postBuildCmdLine = localGen.BuildCommandLine(
  878. postBuildCmdLines, "post-build", this->GeneratorTarget);
  879. cmNinjaVars symlinkVars;
  880. bool const symlinkNeeded =
  881. (targetOutput != targetOutputReal && !gt.IsFrameworkOnApple());
  882. if (!symlinkNeeded) {
  883. vars["POST_BUILD"] = postBuildCmdLine;
  884. } else {
  885. vars["POST_BUILD"] = cmGlobalNinjaGenerator::SHELL_NOOP;
  886. symlinkVars["POST_BUILD"] = postBuildCmdLine;
  887. }
  888. cmGlobalNinjaGenerator& globalGen = *this->GetGlobalGenerator();
  889. bool const lang_supports_response =
  890. !(this->TargetLinkLanguage == "RC" || this->TargetLinkLanguage == "CUDA");
  891. int commandLineLengthLimit = -1;
  892. if (!lang_supports_response || !this->ForceResponseFile()) {
  893. commandLineLengthLimit =
  894. static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
  895. globalGen.GetRuleCmdLength(this->LanguageLinkerRule());
  896. }
  897. const std::string rspfile = this->ConvertToNinjaPath(
  898. std::string("CMakeFiles/") + gt.GetName() + ".rsp");
  899. // Gather order-only dependencies.
  900. cmNinjaDeps orderOnlyDeps;
  901. this->GetLocalGenerator()->AppendTargetDepends(this->GetGeneratorTarget(),
  902. orderOnlyDeps);
  903. // Ninja should restat after linking if and only if there are byproducts.
  904. vars["RESTAT"] = byproducts.empty() ? "" : "1";
  905. for (std::string const& o : byproducts) {
  906. this->GetGlobalGenerator()->SeenCustomCommandOutput(o);
  907. outputs.push_back(o);
  908. }
  909. // Write the build statement for this target.
  910. bool usedResponseFile = false;
  911. globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(),
  912. this->LanguageLinkerRule(), outputs,
  913. /*implicitOuts=*/cmNinjaDeps(), explicitDeps,
  914. implicitDeps, orderOnlyDeps, vars, rspfile,
  915. commandLineLengthLimit, &usedResponseFile);
  916. this->WriteLinkRule(usedResponseFile);
  917. if (symlinkNeeded) {
  918. if (targetType == cmStateEnums::EXECUTABLE) {
  919. globalGen.WriteBuild(
  920. this->GetBuildFileStream(),
  921. "Create executable symlink " + targetOutput,
  922. "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput),
  923. /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal),
  924. emptyDeps, emptyDeps, symlinkVars);
  925. } else {
  926. cmNinjaDeps symlinks;
  927. std::string const soName = this->ConvertToNinjaPath(
  928. this->GetTargetFilePath(this->TargetNames.SharedObject));
  929. // If one link has to be created.
  930. if (targetOutputReal == soName || targetOutput == soName) {
  931. symlinkVars["SONAME"] = soName;
  932. } else {
  933. symlinkVars["SONAME"].clear();
  934. symlinks.push_back(soName);
  935. }
  936. symlinks.push_back(targetOutput);
  937. globalGen.WriteBuild(
  938. this->GetBuildFileStream(), "Create library symlink " + targetOutput,
  939. "CMAKE_SYMLINK_LIBRARY", symlinks,
  940. /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal),
  941. emptyDeps, emptyDeps, symlinkVars);
  942. }
  943. }
  944. // Add aliases for the file name and the target name.
  945. globalGen.AddTargetAlias(this->TargetNames.Output, &gt);
  946. globalGen.AddTargetAlias(this->GetTargetName(), &gt);
  947. }
  948. void cmNinjaNormalTargetGenerator::WriteObjectLibStatement()
  949. {
  950. // Write a phony output that depends on all object files.
  951. cmNinjaDeps outputs;
  952. this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
  953. outputs);
  954. cmNinjaDeps depends = this->GetObjects();
  955. this->GetGlobalGenerator()->WritePhonyBuild(
  956. this->GetBuildFileStream(), "Object library " + this->GetTargetName(),
  957. outputs, depends);
  958. // Add aliases for the target name.
  959. this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(),
  960. this->GetGeneratorTarget());
  961. }