cmNinjaNormalTargetGenerator.cxx 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727
  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 <cassert>
  6. #include <iterator>
  7. #include <set>
  8. #include <sstream>
  9. #include <unordered_set>
  10. #include <utility>
  11. #include <cm/memory>
  12. #include <cm/optional>
  13. #include <cm/vector>
  14. #include "cmComputeLinkInformation.h"
  15. #include "cmCustomCommand.h" // IWYU pragma: keep
  16. #include "cmCustomCommandGenerator.h"
  17. #include "cmGeneratedFileStream.h"
  18. #include "cmGeneratorOptions.h"
  19. #include "cmGeneratorTarget.h"
  20. #include "cmGlobalNinjaGenerator.h"
  21. #include "cmLinkLineComputer.h"
  22. #include "cmLinkLineDeviceComputer.h"
  23. #include "cmList.h"
  24. #include "cmLocalCommonGenerator.h"
  25. #include "cmLocalGenerator.h"
  26. #include "cmLocalNinjaGenerator.h"
  27. #include "cmMakefile.h"
  28. #include "cmMessageType.h"
  29. #include "cmNinjaLinkLineDeviceComputer.h"
  30. #include "cmNinjaTypes.h"
  31. #include "cmOSXBundleGenerator.h"
  32. #include "cmOutputConverter.h"
  33. #include "cmRulePlaceholderExpander.h"
  34. #include "cmSourceFile.h"
  35. #include "cmState.h"
  36. #include "cmStateDirectory.h"
  37. #include "cmStateSnapshot.h"
  38. #include "cmStateTypes.h"
  39. #include "cmStringAlgorithms.h"
  40. #include "cmSystemTools.h"
  41. #include "cmValue.h"
  42. cmNinjaNormalTargetGenerator::cmNinjaNormalTargetGenerator(
  43. cmGeneratorTarget* target)
  44. : cmNinjaTargetGenerator(target)
  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. for (auto const& config : this->GetConfigNames()) {
  50. this->EnsureDirectoryExists(target->GetDirectory(config));
  51. }
  52. }
  53. this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
  54. this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
  55. }
  56. cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() = default;
  57. void cmNinjaNormalTargetGenerator::Generate(std::string const& config)
  58. {
  59. if (this->GetGeneratorTarget()->GetType() !=
  60. cmStateEnums::INTERFACE_LIBRARY) {
  61. std::string lang = this->GeneratorTarget->GetLinkerLanguage(config);
  62. if (this->TargetLinkLanguage(config).empty()) {
  63. cmSystemTools::Error(
  64. cmStrCat("CMake can not determine linker language for target: ",
  65. this->GetGeneratorTarget()->GetName()));
  66. return;
  67. }
  68. }
  69. // Write the rules for each language.
  70. this->WriteLanguagesRules(config);
  71. // Write the build statements
  72. bool firstForConfig = true;
  73. for (auto const& fileConfig : this->GetConfigNames()) {
  74. if (!this->GetGlobalGenerator()
  75. ->GetCrossConfigs(fileConfig)
  76. .count(config)) {
  77. continue;
  78. }
  79. this->WriteObjectBuildStatements(config, fileConfig, firstForConfig);
  80. firstForConfig = false;
  81. }
  82. if (this->GetGeneratorTarget()->GetType() == cmStateEnums::OBJECT_LIBRARY) {
  83. this->WriteObjectLibStatement(config);
  84. } else if (this->GetGeneratorTarget()->GetType() ==
  85. cmStateEnums::INTERFACE_LIBRARY) {
  86. bool haveCxxModuleSources = false;
  87. if (this->GetGeneratorTarget()->HaveCxx20ModuleSources()) {
  88. haveCxxModuleSources = true;
  89. }
  90. if (!haveCxxModuleSources) {
  91. cmSystemTools::Error(cmStrCat(
  92. "Ninja does not support INTERFACE libraries without C++ module "
  93. "sources as a normal target: ",
  94. this->GetGeneratorTarget()->GetName()));
  95. return;
  96. }
  97. firstForConfig = true;
  98. for (auto const& fileConfig : this->GetConfigNames()) {
  99. if (!this->GetGlobalGenerator()
  100. ->GetCrossConfigs(fileConfig)
  101. .count(config)) {
  102. continue;
  103. }
  104. if (haveCxxModuleSources) {
  105. this->WriteCxxModuleLibraryStatement(config, fileConfig,
  106. firstForConfig);
  107. }
  108. firstForConfig = false;
  109. }
  110. } else {
  111. firstForConfig = true;
  112. for (auto const& fileConfig : this->GetConfigNames()) {
  113. if (!this->GetGlobalGenerator()
  114. ->GetCrossConfigs(fileConfig)
  115. .count(config)) {
  116. continue;
  117. }
  118. // If this target has cuda language link inputs, and we need to do
  119. // device linking
  120. this->WriteDeviceLinkStatement(config, fileConfig, firstForConfig);
  121. this->WriteLinkStatement(config, fileConfig, firstForConfig);
  122. firstForConfig = false;
  123. }
  124. }
  125. if (this->GetGlobalGenerator()->EnableCrossConfigBuild()) {
  126. this->GetGlobalGenerator()->AddTargetAlias(
  127. this->GetTargetName(), this->GetGeneratorTarget(), "all");
  128. }
  129. // Find ADDITIONAL_CLEAN_FILES
  130. this->AdditionalCleanFiles(config);
  131. }
  132. void cmNinjaNormalTargetGenerator::WriteLanguagesRules(
  133. std::string const& config)
  134. {
  135. #ifdef NINJA_GEN_VERBOSE_FILES
  136. cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream());
  137. this->GetRulesFileStream()
  138. << "# Rules for each language for "
  139. << cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
  140. << " target " << this->GetTargetName() << "\n\n";
  141. #endif
  142. // Write rules for languages compiled in this target.
  143. {
  144. std::set<std::string> languages;
  145. std::vector<cmSourceFile const*> sourceFiles;
  146. this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
  147. if (this->HaveRequiredLanguages(sourceFiles, languages)) {
  148. for (std::string const& language : languages) {
  149. this->WriteLanguageRules(language, config);
  150. }
  151. }
  152. }
  153. // Write rules for languages in BMI-only rules.
  154. {
  155. std::set<std::string> languages;
  156. std::vector<cmSourceFile const*> sourceFiles;
  157. this->GetGeneratorTarget()->GetCxxModuleSources(sourceFiles, config);
  158. if (this->HaveRequiredLanguages(sourceFiles, languages)) {
  159. for (std::string const& language : languages) {
  160. this->WriteLanguageRules(language, config);
  161. }
  162. }
  163. }
  164. }
  165. char const* cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
  166. {
  167. switch (this->GetGeneratorTarget()->GetType()) {
  168. case cmStateEnums::STATIC_LIBRARY:
  169. return "static library";
  170. case cmStateEnums::SHARED_LIBRARY:
  171. return "shared library";
  172. case cmStateEnums::MODULE_LIBRARY:
  173. if (this->GetGeneratorTarget()->IsCFBundleOnApple()) {
  174. return "CFBundle shared module";
  175. } else {
  176. return "shared module";
  177. }
  178. case cmStateEnums::EXECUTABLE:
  179. return "executable";
  180. default:
  181. return nullptr;
  182. }
  183. }
  184. std::string cmNinjaNormalTargetGenerator::LanguageLinkerRule(
  185. std::string const& config) const
  186. {
  187. return cmStrCat(
  188. this->TargetLinkLanguage(config), "_",
  189. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()),
  190. "_LINKER__",
  191. cmGlobalNinjaGenerator::EncodeRuleName(
  192. this->GetGeneratorTarget()->GetName()),
  193. "_", config);
  194. }
  195. std::string cmNinjaNormalTargetGenerator::LanguageLinkerDeviceRule(
  196. std::string const& config) const
  197. {
  198. return cmStrCat(
  199. this->TargetLinkLanguage(config), "_",
  200. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()),
  201. "_DEVICE_LINKER__",
  202. cmGlobalNinjaGenerator::EncodeRuleName(
  203. this->GetGeneratorTarget()->GetName()),
  204. "_", config);
  205. }
  206. std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaDeviceRule(
  207. std::string const& config) const
  208. {
  209. return cmStrCat(
  210. this->TargetLinkLanguage(config), "_DEVICE_LINK__",
  211. cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
  212. '_', config);
  213. }
  214. std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaDeviceCompileRule(
  215. std::string const& config) const
  216. {
  217. return cmStrCat(
  218. this->TargetLinkLanguage(config), "_DEVICE_LINK_COMPILE__",
  219. cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
  220. '_', config);
  221. }
  222. std::string cmNinjaNormalTargetGenerator::LanguageLinkerCudaFatbinaryRule(
  223. std::string const& config) const
  224. {
  225. return cmStrCat(
  226. this->TargetLinkLanguage(config), "_FATBINARY__",
  227. cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
  228. '_', config);
  229. }
  230. std::string cmNinjaNormalTargetGenerator::TextStubsGeneratorRule(
  231. std::string const& config) const
  232. {
  233. return cmStrCat(
  234. "TEXT_STUBS_GENERATOR__",
  235. cmGlobalNinjaGenerator::EncodeRuleName(this->GeneratorTarget->GetName()),
  236. '_', config);
  237. }
  238. bool cmNinjaNormalTargetGenerator::CheckUseResponseFileForLibraries(
  239. std::string const& l) const
  240. {
  241. // Check for an explicit setting one way or the other.
  242. std::string const responseVar =
  243. "CMAKE_" + l + "_USE_RESPONSE_FILE_FOR_LIBRARIES";
  244. // If the option is defined, read it's value
  245. if (cmValue val = this->Makefile->GetDefinition(responseVar)) {
  246. return val.IsOn();
  247. }
  248. // Default to true
  249. return true;
  250. }
  251. struct cmNinjaRemoveNoOpCommands
  252. {
  253. bool operator()(std::string const& cmd)
  254. {
  255. return cmd.empty() || cmd[0] == ':';
  256. }
  257. };
  258. void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkRule(
  259. bool useResponseFile, std::string const& config)
  260. {
  261. cmNinjaRule rule(this->LanguageLinkerDeviceRule(config));
  262. if (!this->GetGlobalGenerator()->HasRule(rule.Name)) {
  263. cmRulePlaceholderExpander::RuleVariables vars;
  264. vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
  265. vars.CMTargetType =
  266. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType())
  267. .c_str();
  268. vars.CMTargetLabels =
  269. this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
  270. vars.Language = "CUDA";
  271. std::string linker =
  272. this->GetGeneratorTarget()->GetLinkerTool("CUDA", config);
  273. vars.Linker = linker.c_str();
  274. // build response file name
  275. std::string responseFlag = this->GetMakefile()->GetSafeDefinition(
  276. "CMAKE_CUDA_RESPONSE_FILE_DEVICE_LINK_FLAG");
  277. if (!useResponseFile || responseFlag.empty()) {
  278. vars.Objects = "$in";
  279. vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
  280. } else {
  281. rule.RspFile = "$RSP_FILE";
  282. responseFlag += rule.RspFile;
  283. // build response file content
  284. if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
  285. rule.RspContent = "$in";
  286. } else {
  287. rule.RspContent = "$in_newline";
  288. }
  289. // add the link command in the file if necessary
  290. if (this->CheckUseResponseFileForLibraries("CUDA")) {
  291. rule.RspContent += " $LINK_LIBRARIES";
  292. vars.LinkLibraries = "";
  293. } else {
  294. vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
  295. }
  296. vars.Objects = responseFlag.c_str();
  297. }
  298. vars.ObjectDir = "$OBJECT_DIR";
  299. vars.Target = "$TARGET_FILE";
  300. vars.SONameFlag = "$SONAME_FLAG";
  301. vars.TargetSOName = "$SONAME";
  302. vars.TargetPDB = "$TARGET_PDB";
  303. vars.TargetCompilePDB = "$TARGET_COMPILE_PDB";
  304. vars.Flags = "$FLAGS";
  305. vars.LinkFlags = "$LINK_FLAGS";
  306. vars.Manifests = "$MANIFESTS";
  307. vars.Config = "$CONFIG";
  308. vars.LanguageCompileFlags = "$LANGUAGE_COMPILE_FLAGS";
  309. std::string launcher;
  310. std::string val = this->GetLocalGenerator()->GetRuleLauncher(
  311. this->GetGeneratorTarget(), "RULE_LAUNCH_LINK", config);
  312. if (cmNonempty(val)) {
  313. launcher = cmStrCat(val, ' ');
  314. }
  315. auto rulePlaceholderExpander =
  316. this->GetLocalGenerator()->CreateRulePlaceholderExpander(
  317. cmBuildStep::Link, this->GetGeneratorTarget(),
  318. this->TargetLinkLanguage(config));
  319. // Rule for linking library/executable.
  320. std::vector<std::string> linkCmds = this->ComputeDeviceLinkCmd();
  321. for (std::string& linkCmd : linkCmds) {
  322. linkCmd = cmStrCat(launcher, linkCmd);
  323. rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  324. linkCmd, vars);
  325. }
  326. // If there is no ranlib the command will be ":". Skip it.
  327. cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands());
  328. rule.Command =
  329. this->GetLocalGenerator()->BuildCommandLine(linkCmds, config, config);
  330. // Write the linker rule with response file if needed.
  331. rule.Comment =
  332. cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ',
  333. this->GetVisibleTypeName(), '.');
  334. rule.Description =
  335. cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ',
  336. this->GetVisibleTypeName(), " $TARGET_FILE");
  337. rule.Restat = "$RESTAT";
  338. this->GetGlobalGenerator()->AddRule(rule);
  339. }
  340. }
  341. void cmNinjaNormalTargetGenerator::WriteDeviceLinkRules(
  342. std::string const& config)
  343. {
  344. cmMakefile const* mf = this->GetMakefile();
  345. cmNinjaRule rule(this->LanguageLinkerCudaDeviceRule(config));
  346. rule.Command = this->GetLocalGenerator()->BuildCommandLine(
  347. { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_DEVICE_LINKER"),
  348. " -arch=$ARCH $REGISTER -o=$out $in") },
  349. config, config);
  350. rule.Comment = "Rule for CUDA device linking.";
  351. rule.Description = "Linking CUDA $out";
  352. this->GetGlobalGenerator()->AddRule(rule);
  353. cmRulePlaceholderExpander::RuleVariables vars;
  354. vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
  355. vars.CMTargetType =
  356. cmState::GetTargetTypeName(this->GetGeneratorTarget()->GetType()).c_str();
  357. vars.CMTargetLabels =
  358. this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
  359. vars.Language = "CUDA";
  360. vars.Object = "$out";
  361. vars.Fatbinary = "$FATBIN";
  362. vars.RegisterFile = "$REGISTER";
  363. vars.LinkFlags = "$LINK_FLAGS";
  364. std::string linker =
  365. this->GetGeneratorTarget()->GetLinkerTool("CUDA", config);
  366. vars.Linker = linker.c_str();
  367. std::string flags = this->GetFlags("CUDA", config);
  368. vars.Flags = flags.c_str();
  369. vars.Config = "$CONFIG";
  370. std::string compileCmd = this->GetMakefile()->GetRequiredDefinition(
  371. "CMAKE_CUDA_DEVICE_LINK_COMPILE");
  372. auto rulePlaceholderExpander =
  373. this->GetLocalGenerator()->CreateRulePlaceholderExpander(
  374. cmBuildStep::Link, this->GetGeneratorTarget(),
  375. this->TargetLinkLanguage(config));
  376. rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  377. compileCmd, vars);
  378. rule.Name = this->LanguageLinkerCudaDeviceCompileRule(config);
  379. rule.Command = this->GetLocalGenerator()->BuildCommandLine({ compileCmd },
  380. config, config);
  381. rule.Comment = "Rule for compiling CUDA device stubs.";
  382. rule.Description = "Compiling CUDA device stub $out";
  383. this->GetGlobalGenerator()->AddRule(rule);
  384. rule.Name = this->LanguageLinkerCudaFatbinaryRule(config);
  385. rule.Command = this->GetLocalGenerator()->BuildCommandLine(
  386. { cmStrCat(mf->GetRequiredDefinition("CMAKE_CUDA_FATBINARY"),
  387. " -64 -cmdline=--compile-only -compress-all -link "
  388. "--embedded-fatbin=$out $PROFILES") },
  389. config, config);
  390. rule.Comment = "Rule for CUDA fatbinaries.";
  391. rule.Description = "Creating fatbinary $out";
  392. this->GetGlobalGenerator()->AddRule(rule);
  393. }
  394. void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
  395. std::string const& config)
  396. {
  397. cmStateEnums::TargetType targetType = this->GetGeneratorTarget()->GetType();
  398. std::string linkRuleName = this->LanguageLinkerRule(config);
  399. if (!this->GetGlobalGenerator()->HasRule(linkRuleName)) {
  400. cmNinjaRule rule(std::move(linkRuleName));
  401. cmRulePlaceholderExpander::RuleVariables vars;
  402. vars.CMTargetName = this->GetGeneratorTarget()->GetName().c_str();
  403. vars.CMTargetType = cmState::GetTargetTypeName(targetType).c_str();
  404. vars.CMTargetLabels =
  405. this->GetGeneratorTarget()->GetTargetLabelsString().c_str();
  406. std::string linker = this->GetGeneratorTarget()->GetLinkerTool(config);
  407. vars.Linker = linker.c_str();
  408. std::string lang = this->TargetLinkLanguage(config);
  409. vars.Language = lang.c_str();
  410. vars.AIXExports = "$AIX_EXPORTS";
  411. if (!this->GetLocalGenerator()->IsSplitSwiftBuild() &&
  412. this->TargetLinkLanguage(config) == "Swift") {
  413. vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
  414. vars.SwiftModule = "$SWIFT_MODULE";
  415. vars.SwiftModuleName = "$SWIFT_MODULE_NAME";
  416. vars.SwiftSources = "$SWIFT_SOURCES";
  417. vars.Defines = "$DEFINES";
  418. vars.Flags = "$FLAGS";
  419. vars.Includes = "$INCLUDES";
  420. }
  421. std::string responseFlag;
  422. std::string cmakeVarLang =
  423. cmStrCat("CMAKE_", this->TargetLinkLanguage(config));
  424. if (this->GeneratorTarget->HasLinkDependencyFile(config)) {
  425. auto DepFileFormat = this->GetMakefile()->GetDefinition(
  426. cmStrCat(cmakeVarLang, "_LINKER_DEPFILE_FORMAT"));
  427. rule.DepType = DepFileFormat;
  428. rule.DepFile = "$DEP_FILE";
  429. }
  430. // build response file name
  431. std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
  432. cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
  433. if (flag) {
  434. responseFlag = *flag;
  435. } else {
  436. responseFlag = "@";
  437. }
  438. if (!useResponseFile || responseFlag.empty()) {
  439. vars.Objects = "$in";
  440. vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
  441. } else {
  442. rule.RspFile = "$RSP_FILE";
  443. responseFlag += rule.RspFile;
  444. // build response file content
  445. if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
  446. rule.RspContent = "$in";
  447. } else {
  448. rule.RspContent = "$in_newline";
  449. }
  450. // If libraries in rsp is enable
  451. if (this->CheckUseResponseFileForLibraries(lang)) {
  452. rule.RspContent += " $LINK_PATH $LINK_LIBRARIES";
  453. vars.LinkLibraries = "";
  454. } else {
  455. vars.LinkLibraries = "$LINK_PATH $LINK_LIBRARIES";
  456. }
  457. if (!this->GetLocalGenerator()->IsSplitSwiftBuild() &&
  458. this->TargetLinkLanguage(config) == "Swift") {
  459. vars.SwiftSources = responseFlag.c_str();
  460. } else {
  461. vars.Objects = responseFlag.c_str();
  462. }
  463. }
  464. vars.ObjectDir = "$OBJECT_DIR";
  465. vars.Target = "$TARGET_FILE";
  466. vars.SONameFlag = "$SONAME_FLAG";
  467. vars.TargetSOName = "$SONAME";
  468. vars.TargetInstallNameDir = "$INSTALLNAME_DIR";
  469. vars.TargetPDB = "$TARGET_PDB";
  470. // Setup the target version.
  471. std::string targetVersionMajor;
  472. std::string targetVersionMinor;
  473. {
  474. std::ostringstream majorStream;
  475. std::ostringstream minorStream;
  476. int major;
  477. int minor;
  478. this->GetGeneratorTarget()->GetTargetVersion(major, minor);
  479. majorStream << major;
  480. minorStream << minor;
  481. targetVersionMajor = majorStream.str();
  482. targetVersionMinor = minorStream.str();
  483. }
  484. vars.TargetVersionMajor = targetVersionMajor.c_str();
  485. vars.TargetVersionMinor = targetVersionMinor.c_str();
  486. vars.Flags = "$FLAGS";
  487. vars.LinkFlags = "$LINK_FLAGS";
  488. vars.Manifests = "$MANIFESTS";
  489. vars.Config = "$CONFIG";
  490. std::string langFlags;
  491. if (targetType != cmStateEnums::EXECUTABLE) {
  492. langFlags += "$LANGUAGE_COMPILE_FLAGS $ARCH_FLAGS";
  493. vars.LanguageCompileFlags = langFlags.c_str();
  494. }
  495. std::string linkerLauncher = this->GetLinkerLauncher(config);
  496. if (cmNonempty(linkerLauncher)) {
  497. vars.Launcher = linkerLauncher.c_str();
  498. }
  499. std::string launcher;
  500. std::string val = this->GetLocalGenerator()->GetRuleLauncher(
  501. this->GetGeneratorTarget(), "RULE_LAUNCH_LINK", config);
  502. if (cmNonempty(val)) {
  503. launcher = cmStrCat(val, ' ');
  504. }
  505. auto rulePlaceholderExpander =
  506. this->GetLocalGenerator()->CreateRulePlaceholderExpander(
  507. cmBuildStep::Link, this->GetGeneratorTarget(),
  508. this->TargetLinkLanguage(config));
  509. // Rule for linking library/executable.
  510. std::vector<std::string> linkCmds = this->ComputeLinkCmd(config);
  511. for (std::string& linkCmd : linkCmds) {
  512. linkCmd = cmStrCat(launcher, linkCmd);
  513. rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  514. linkCmd, vars);
  515. }
  516. // If there is no ranlib the command will be ":". Skip it.
  517. cm::erase_if(linkCmds, cmNinjaRemoveNoOpCommands());
  518. linkCmds.insert(linkCmds.begin(), "$PRE_LINK");
  519. linkCmds.emplace_back("$POST_BUILD");
  520. rule.Command =
  521. this->GetLocalGenerator()->BuildCommandLine(linkCmds, config, config);
  522. // Write the linker rule with response file if needed.
  523. rule.Comment =
  524. cmStrCat("Rule for linking ", this->TargetLinkLanguage(config), ' ',
  525. this->GetVisibleTypeName(), '.');
  526. rule.Description =
  527. cmStrCat("Linking ", this->TargetLinkLanguage(config), ' ',
  528. this->GetVisibleTypeName(), " $TARGET_FILE");
  529. rule.Restat = "$RESTAT";
  530. this->GetGlobalGenerator()->AddRule(rule);
  531. }
  532. auto const tgtNames = this->TargetNames(config);
  533. if (tgtNames.Output != tgtNames.Real &&
  534. !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
  535. std::string cmakeCommand =
  536. this->GetLocalGenerator()->ConvertToOutputFormat(
  537. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  538. if (targetType == cmStateEnums::EXECUTABLE) {
  539. cmNinjaRule rule("CMAKE_SYMLINK_EXECUTABLE");
  540. {
  541. std::vector<std::string> cmd;
  542. cmd.push_back(cmakeCommand + " -E cmake_symlink_executable $in $out");
  543. cmd.emplace_back("$POST_BUILD");
  544. rule.Command =
  545. this->GetLocalGenerator()->BuildCommandLine(cmd, config, config);
  546. }
  547. rule.Description = "Creating executable symlink $out";
  548. rule.Comment = "Rule for creating executable symlink.";
  549. this->GetGlobalGenerator()->AddRule(rule);
  550. } else {
  551. cmNinjaRule rule("CMAKE_SYMLINK_LIBRARY");
  552. {
  553. std::vector<std::string> cmd;
  554. cmd.push_back(cmakeCommand +
  555. " -E cmake_symlink_library $in $SONAME $out");
  556. cmd.emplace_back("$POST_BUILD");
  557. rule.Command =
  558. this->GetLocalGenerator()->BuildCommandLine(cmd, config, config);
  559. }
  560. rule.Description = "Creating library symlink $out";
  561. rule.Comment = "Rule for creating library symlink.";
  562. this->GetGlobalGenerator()->AddRule(rule);
  563. }
  564. }
  565. if (this->GetGeneratorTarget()->IsApple() &&
  566. this->GetGeneratorTarget()->HasImportLibrary(config)) {
  567. cmNinjaRule rule(this->TextStubsGeneratorRule(config));
  568. rule.Comment = cmStrCat("Rule for generating text-based stubs for ",
  569. this->GetVisibleTypeName(), '.');
  570. rule.Description = "Creating text-based stubs $out";
  571. std::string cmd =
  572. this->GetMakefile()->GetDefinition("CMAKE_CREATE_TEXT_STUBS");
  573. auto rulePlaceholderExpander =
  574. this->GetLocalGenerator()->CreateRulePlaceholderExpander();
  575. cmRulePlaceholderExpander::RuleVariables vars;
  576. vars.Target = "$in";
  577. rulePlaceholderExpander->SetTargetImpLib("$out");
  578. rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
  579. cmd, vars);
  580. rule.Command =
  581. this->GetLocalGenerator()->BuildCommandLine({ cmd }, config, config);
  582. this->GetGlobalGenerator()->AddRule(rule);
  583. if (tgtNames.ImportOutput != tgtNames.ImportReal &&
  584. !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
  585. cmNinjaRule slRule("CMAKE_SYMLINK_IMPORT_LIBRARY");
  586. {
  587. std::string cmakeCommand =
  588. this->GetLocalGenerator()->ConvertToOutputFormat(
  589. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  590. std::string slCmd =
  591. cmStrCat(cmakeCommand, " -E cmake_symlink_library $in $SONAME $out");
  592. slRule.Command = this->GetLocalGenerator()->BuildCommandLine(
  593. { slCmd }, config, config);
  594. }
  595. slRule.Description = "Creating import library symlink $out";
  596. slRule.Comment = "Rule for creating import library symlink.";
  597. this->GetGlobalGenerator()->AddRule(slRule);
  598. }
  599. }
  600. }
  601. std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeDeviceLinkCmd()
  602. {
  603. cmList linkCmds;
  604. // this target requires separable cuda compilation
  605. // now build the correct command depending on if the target is
  606. // an executable or a dynamic library.
  607. switch (this->GetGeneratorTarget()->GetType()) {
  608. case cmStateEnums::STATIC_LIBRARY:
  609. case cmStateEnums::SHARED_LIBRARY:
  610. case cmStateEnums::MODULE_LIBRARY: {
  611. linkCmds.assign(
  612. this->GetMakefile()->GetDefinition("CMAKE_CUDA_DEVICE_LINK_LIBRARY"));
  613. } break;
  614. case cmStateEnums::EXECUTABLE: {
  615. linkCmds.assign(this->GetMakefile()->GetDefinition(
  616. "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE"));
  617. } break;
  618. default:
  619. break;
  620. }
  621. return std::move(linkCmds.data());
  622. }
  623. std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd(
  624. std::string const& config)
  625. {
  626. cmList linkCmds;
  627. cmMakefile* mf = this->GetMakefile();
  628. {
  629. // If we have a rule variable prefer it. In the case of static libraries
  630. // this occurs when things like IPO is enabled, and we need to use the
  631. // CMAKE_<lang>_CREATE_STATIC_LIBRARY_IPO define instead.
  632. std::string linkCmdVar = this->GetGeneratorTarget()->GetCreateRuleVariable(
  633. this->TargetLinkLanguage(config), config);
  634. cmValue linkCmd = mf->GetDefinition(linkCmdVar);
  635. if (linkCmd) {
  636. std::string linkCmdStr = *linkCmd;
  637. if (this->GetGeneratorTarget()->HasImplibGNUtoMS(config)) {
  638. std::string ruleVar =
  639. cmStrCat("CMAKE_", this->GeneratorTarget->GetLinkerLanguage(config),
  640. "_GNUtoMS_RULE");
  641. if (cmValue rule = this->Makefile->GetDefinition(ruleVar)) {
  642. linkCmdStr += *rule;
  643. }
  644. }
  645. linkCmds.assign(linkCmdStr);
  646. if (this->UseLWYU) {
  647. cmValue lwyuCheck = mf->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
  648. if (lwyuCheck) {
  649. std::string cmakeCommand = cmStrCat(
  650. this->GetLocalGenerator()->ConvertToOutputFormat(
  651. cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
  652. " -E __run_co_compile --lwyu=");
  653. cmakeCommand +=
  654. this->GetLocalGenerator()->EscapeForShell(*lwyuCheck);
  655. std::string targetOutputReal =
  656. this->ConvertToNinjaPath(this->GetGeneratorTarget()->GetFullPath(
  657. config, cmStateEnums::RuntimeBinaryArtifact,
  658. /*realname=*/true));
  659. cmakeCommand += cmStrCat(" --source=", targetOutputReal);
  660. linkCmds.push_back(std::move(cmakeCommand));
  661. }
  662. }
  663. return std::move(linkCmds.data());
  664. }
  665. }
  666. switch (this->GetGeneratorTarget()->GetType()) {
  667. case cmStateEnums::STATIC_LIBRARY: {
  668. // We have archive link commands set. First, delete the existing archive.
  669. {
  670. std::string cmakeCommand =
  671. this->GetLocalGenerator()->ConvertToOutputFormat(
  672. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  673. linkCmds.push_back(cmakeCommand + " -E rm -f $TARGET_FILE");
  674. }
  675. // TODO: Use ARCHIVE_APPEND for archives over a certain size.
  676. {
  677. std::string linkCmdVar = cmStrCat(
  678. "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_CREATE");
  679. linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
  680. linkCmdVar, this->TargetLinkLanguage(config), config);
  681. std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
  682. linkCmds.append(linkCmd);
  683. }
  684. {
  685. std::string linkCmdVar = cmStrCat(
  686. "CMAKE_", this->TargetLinkLanguage(config), "_ARCHIVE_FINISH");
  687. linkCmdVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable(
  688. linkCmdVar, this->TargetLinkLanguage(config), config);
  689. std::string const& linkCmd = mf->GetRequiredDefinition(linkCmdVar);
  690. linkCmds.append(linkCmd);
  691. }
  692. #ifdef __APPLE__
  693. // On macOS ranlib truncates the fractional part of the static archive
  694. // file modification time. If the archive and at least one contained
  695. // object file were created within the same second this will make look
  696. // the archive older than the object file. On subsequent ninja runs this
  697. // leads to re-archiving and updating dependent targets.
  698. // As a work-around we touch the archive after ranlib (see #19222).
  699. {
  700. std::string cmakeCommand =
  701. this->GetLocalGenerator()->ConvertToOutputFormat(
  702. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  703. linkCmds.push_back(cmakeCommand + " -E touch $TARGET_FILE");
  704. }
  705. #endif
  706. } break;
  707. case cmStateEnums::SHARED_LIBRARY:
  708. case cmStateEnums::MODULE_LIBRARY:
  709. case cmStateEnums::EXECUTABLE:
  710. break;
  711. default:
  712. assert(false && "Unexpected target type");
  713. }
  714. return std::move(linkCmds.data());
  715. }
  716. void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement(
  717. std::string const& config, std::string const& fileConfig,
  718. bool firstForConfig)
  719. {
  720. cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
  721. if (!globalGen->GetLanguageEnabled("CUDA")) {
  722. return;
  723. }
  724. cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
  725. bool requiresDeviceLinking = requireDeviceLinking(
  726. *this->GeneratorTarget, *this->GetLocalGenerator(), config);
  727. if (!requiresDeviceLinking) {
  728. return;
  729. }
  730. // First and very important step is to make sure while inside this
  731. // step our link language is set to CUDA
  732. std::string const& objExt =
  733. this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
  734. std::string targetOutputDir =
  735. cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget),
  736. globalGen->ConfigDirectory(config), "/");
  737. targetOutputDir = globalGen->ExpandCFGIntDir(targetOutputDir, config);
  738. std::string targetOutputReal =
  739. this->ConvertToNinjaPath(targetOutputDir + "cmake_device_link" + objExt);
  740. if (firstForConfig) {
  741. globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
  742. }
  743. this->DeviceLinkObject = targetOutputReal;
  744. // Write comments.
  745. cmGlobalNinjaGenerator::WriteDivider(this->GetCommonFileStream());
  746. this->GetCommonFileStream()
  747. << "# Device Link build statements for "
  748. << cmState::GetTargetTypeName(genTarget->GetType()) << " target "
  749. << this->GetTargetName() << "\n\n";
  750. if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") {
  751. std::string architecturesStr =
  752. this->GeneratorTarget->GetSafeProperty("CUDA_ARCHITECTURES");
  753. if (cmIsOff(architecturesStr)) {
  754. this->Makefile->IssueMessage(MessageType::FATAL_ERROR,
  755. "CUDA_SEPARABLE_COMPILATION on Clang "
  756. "requires CUDA_ARCHITECTURES to be set.");
  757. return;
  758. }
  759. this->WriteDeviceLinkRules(config);
  760. this->WriteDeviceLinkStatements(config, cmList{ architecturesStr },
  761. targetOutputReal);
  762. } else {
  763. this->WriteNvidiaDeviceLinkStatement(config, fileConfig, targetOutputDir,
  764. targetOutputReal);
  765. }
  766. }
  767. void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatements(
  768. std::string const& config, std::vector<std::string> const& architectures,
  769. std::string const& output)
  770. {
  771. // Ensure there are no duplicates.
  772. cmNinjaDeps const explicitDeps = [&]() -> std::vector<std::string> {
  773. std::unordered_set<std::string> depsSet;
  774. cmNinjaDeps const linkDeps =
  775. this->ComputeLinkDeps(this->TargetLinkLanguage(config), config, true);
  776. cmNinjaDeps const objects = this->GetObjects(config);
  777. depsSet.insert(linkDeps.begin(), linkDeps.end());
  778. depsSet.insert(objects.begin(), objects.end());
  779. std::vector<std::string> deps;
  780. std::copy(depsSet.begin(), depsSet.end(), std::back_inserter(deps));
  781. return deps;
  782. }();
  783. cmGlobalNinjaGenerator* globalGen{ this->GetGlobalGenerator() };
  784. std::string const objectDir =
  785. cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
  786. globalGen->ConfigDirectory(config));
  787. std::string const ninjaOutputDir = this->ConvertToNinjaPath(objectDir);
  788. cmNinjaBuild fatbinary(this->LanguageLinkerCudaFatbinaryRule(config));
  789. // Link device code for each architecture.
  790. for (std::string const& architectureKind : architectures) {
  791. // Clang always generates real code, so strip the specifier.
  792. std::string const architecture =
  793. architectureKind.substr(0, architectureKind.find('-'));
  794. std::string const cubin =
  795. cmStrCat(ninjaOutputDir, "/sm_", architecture, ".cubin");
  796. cmNinjaBuild dlink(this->LanguageLinkerCudaDeviceRule(config));
  797. dlink.ExplicitDeps = explicitDeps;
  798. dlink.Outputs = { cubin };
  799. dlink.Variables["ARCH"] = cmStrCat("sm_", architecture);
  800. // The generated register file contains macros that when expanded register
  801. // the device routines. Because the routines are the same for all
  802. // architectures the register file will be the same too. Thus generate it
  803. // only on the first invocation to reduce overhead.
  804. if (fatbinary.ExplicitDeps.empty()) {
  805. dlink.Variables["REGISTER"] = cmStrCat(
  806. "--register-link-binaries=", ninjaOutputDir, "/cmake_cuda_register.h");
  807. }
  808. fatbinary.Variables["PROFILES"] +=
  809. cmStrCat(" -im=profile=sm_", architecture, ",file=", cubin);
  810. fatbinary.ExplicitDeps.emplace_back(cubin);
  811. globalGen->WriteBuild(this->GetCommonFileStream(), dlink);
  812. }
  813. // Combine all architectures into a single fatbinary.
  814. fatbinary.Outputs = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") };
  815. globalGen->WriteBuild(this->GetCommonFileStream(), fatbinary);
  816. // Compile the stub that registers the kernels and contains the fatbinaries.
  817. cmLocalNinjaGenerator* localGen{ this->GetLocalGenerator() };
  818. cmNinjaBuild dcompile(this->LanguageLinkerCudaDeviceCompileRule(config));
  819. dcompile.Outputs = { output };
  820. dcompile.ExplicitDeps = { cmStrCat(ninjaOutputDir, "/cmake_cuda_fatbin.h") };
  821. dcompile.Variables["FATBIN"] = localGen->ConvertToOutputFormat(
  822. cmStrCat(objectDir, "/cmake_cuda_fatbin.h"), cmOutputConverter::SHELL);
  823. dcompile.Variables["REGISTER"] = localGen->ConvertToOutputFormat(
  824. cmStrCat(objectDir, "/cmake_cuda_register.h"), cmOutputConverter::SHELL);
  825. cmNinjaLinkLineDeviceComputer linkLineComputer(
  826. localGen, localGen->GetStateSnapshot().GetDirectory(), globalGen);
  827. linkLineComputer.SetUseNinjaMulti(globalGen->IsMultiConfig());
  828. // Link libraries and paths are only used during the final executable/library
  829. // link.
  830. std::string frameworkPath;
  831. std::string linkPath;
  832. std::string linkLibs;
  833. localGen->GetDeviceLinkFlags(linkLineComputer, config, linkLibs,
  834. dcompile.Variables["LINK_FLAGS"], frameworkPath,
  835. linkPath, this->GetGeneratorTarget());
  836. globalGen->WriteBuild(this->GetCommonFileStream(), dcompile);
  837. }
  838. void cmNinjaNormalTargetGenerator::WriteNvidiaDeviceLinkStatement(
  839. std::string const& config, std::string const& fileConfig,
  840. std::string const& outputDir, std::string const& output)
  841. {
  842. cmGeneratorTarget* genTarget = this->GetGeneratorTarget();
  843. cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
  844. std::string targetOutputImplib = this->ConvertToNinjaPath(
  845. genTarget->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
  846. if (config != fileConfig) {
  847. std::string targetOutputFileConfigDir =
  848. cmStrCat(this->GetLocalGenerator()->GetTargetDirectory(genTarget),
  849. globalGen->ConfigDirectory(fileConfig), "/");
  850. targetOutputFileConfigDir =
  851. globalGen->ExpandCFGIntDir(outputDir, fileConfig);
  852. if (outputDir == targetOutputFileConfigDir) {
  853. return;
  854. }
  855. if (!genTarget->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
  856. .empty() &&
  857. !genTarget
  858. ->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
  859. .empty() &&
  860. targetOutputImplib ==
  861. this->ConvertToNinjaPath(genTarget->GetFullPath(
  862. fileConfig, cmStateEnums::ImportLibraryArtifact))) {
  863. return;
  864. }
  865. }
  866. // Compute the comment.
  867. cmNinjaBuild build(this->LanguageLinkerDeviceRule(config));
  868. build.Comment =
  869. cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', output);
  870. cmNinjaVars& vars = build.Variables;
  871. // Compute outputs.
  872. build.Outputs.push_back(output);
  873. // Compute specific libraries to link with.
  874. build.ExplicitDeps = this->GetObjects(config);
  875. build.ImplicitDeps =
  876. this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
  877. std::string frameworkPath;
  878. std::string linkPath;
  879. std::string createRule =
  880. genTarget->GetCreateRuleVariable(this->TargetLinkLanguage(config), config);
  881. cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
  882. vars["TARGET_FILE"] =
  883. localGen.ConvertToOutputFormat(output, cmOutputConverter::SHELL);
  884. cmNinjaLinkLineDeviceComputer linkLineComputer(
  885. this->GetLocalGenerator(),
  886. this->GetLocalGenerator()->GetStateSnapshot().GetDirectory(), globalGen);
  887. linkLineComputer.SetUseNinjaMulti(globalGen->IsMultiConfig());
  888. localGen.GetDeviceLinkFlags(linkLineComputer, config, vars["LINK_LIBRARIES"],
  889. vars["LINK_FLAGS"], frameworkPath, linkPath,
  890. genTarget);
  891. this->addPoolNinjaVariable("JOB_POOL_LINK", genTarget, vars);
  892. vars["MANIFESTS"] = this->GetManifests(config);
  893. vars["LINK_PATH"] = frameworkPath + linkPath;
  894. // Compute language specific link flags.
  895. std::string langFlags;
  896. localGen.AddLanguageFlagsForLinking(langFlags, genTarget, "CUDA", config);
  897. vars["LANGUAGE_COMPILE_FLAGS"] = langFlags;
  898. auto const tgtNames = this->TargetNames(config);
  899. if (genTarget->HasSOName(config) ||
  900. genTarget->IsArchivedAIXSharedLibrary()) {
  901. vars["SONAME_FLAG"] =
  902. this->GetMakefile()->GetSONameFlag(this->TargetLinkLanguage(config));
  903. vars["SONAME"] = localGen.ConvertToOutputFormat(tgtNames.SharedObject,
  904. cmOutputConverter::SHELL);
  905. if (genTarget->GetType() == cmStateEnums::SHARED_LIBRARY) {
  906. std::string install_dir =
  907. this->GetGeneratorTarget()->GetInstallNameDirForBuildTree(config);
  908. if (!install_dir.empty()) {
  909. vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
  910. install_dir, cmOutputConverter::SHELL);
  911. }
  912. }
  913. }
  914. if (!tgtNames.ImportLibrary.empty()) {
  915. std::string const impLibPath = localGen.ConvertToOutputFormat(
  916. targetOutputImplib, cmOutputConverter::SHELL);
  917. vars["TARGET_IMPLIB"] = impLibPath;
  918. this->EnsureParentDirectoryExists(targetOutputImplib);
  919. }
  920. std::string const objPath =
  921. cmStrCat(this->GetGeneratorTarget()->GetSupportDirectory(),
  922. globalGen->ConfigDirectory(config));
  923. vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
  924. this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
  925. this->EnsureDirectoryExists(objPath);
  926. this->SetMsvcTargetPdbVariable(vars, config);
  927. std::string& linkLibraries = vars["LINK_LIBRARIES"];
  928. std::string& link_path = vars["LINK_PATH"];
  929. if (globalGen->IsGCCOnWindows()) {
  930. // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
  931. std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
  932. std::replace(link_path.begin(), link_path.end(), '\\', '/');
  933. }
  934. // Device linking currently doesn't support response files so
  935. // do not check if the user has explicitly forced a response file.
  936. int const commandLineLengthLimit =
  937. static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
  938. globalGen->GetRuleCmdLength(build.Rule);
  939. build.RspFile = this->ConvertToNinjaPath(
  940. cmStrCat("CMakeFiles/", genTarget->GetName(),
  941. globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp"));
  942. // Gather order-only dependencies.
  943. this->GetLocalGenerator()->AppendTargetDepends(
  944. this->GetGeneratorTarget(), build.OrderOnlyDeps, config, config,
  945. DependOnTargetArtifact);
  946. // Write the build statement for this target.
  947. bool usedResponseFile = false;
  948. globalGen->WriteBuild(this->GetCommonFileStream(), build,
  949. commandLineLengthLimit, &usedResponseFile);
  950. this->WriteNvidiaDeviceLinkRule(usedResponseFile, config);
  951. }
  952. void cmNinjaNormalTargetGenerator::WriteLinkStatement(
  953. std::string const& config, std::string const& fileConfig,
  954. bool firstForConfig)
  955. {
  956. cmMakefile* mf = this->GetMakefile();
  957. cmGlobalNinjaGenerator* globalGen = this->GetGlobalGenerator();
  958. cmGeneratorTarget* gt = this->GetGeneratorTarget();
  959. std::string targetOutput = this->ConvertToNinjaPath(gt->GetFullPath(config));
  960. std::string targetOutputReal = this->ConvertToNinjaPath(
  961. gt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact,
  962. /*realname=*/true));
  963. std::string targetOutputImplib = this->ConvertToNinjaPath(
  964. gt->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
  965. if (config != fileConfig) {
  966. if (targetOutput ==
  967. this->ConvertToNinjaPath(gt->GetFullPath(fileConfig))) {
  968. return;
  969. }
  970. if (targetOutputReal ==
  971. this->ConvertToNinjaPath(
  972. gt->GetFullPath(fileConfig, cmStateEnums::RuntimeBinaryArtifact,
  973. /*realname=*/true))) {
  974. return;
  975. }
  976. if (!gt->GetFullName(config, cmStateEnums::ImportLibraryArtifact)
  977. .empty() &&
  978. !gt->GetFullName(fileConfig, cmStateEnums::ImportLibraryArtifact)
  979. .empty() &&
  980. targetOutputImplib ==
  981. this->ConvertToNinjaPath(gt->GetFullPath(
  982. fileConfig, cmStateEnums::ImportLibraryArtifact))) {
  983. return;
  984. }
  985. }
  986. auto const tgtNames = this->TargetNames(config);
  987. if (gt->IsAppBundleOnApple()) {
  988. // Create the app bundle
  989. std::string outpath = gt->GetDirectory(config);
  990. this->OSXBundleGenerator->CreateAppBundle(tgtNames.Output, outpath,
  991. config);
  992. // Calculate the output path
  993. targetOutput = cmStrCat(outpath, '/', tgtNames.Output);
  994. targetOutput = this->ConvertToNinjaPath(targetOutput);
  995. targetOutputReal = cmStrCat(outpath, '/', tgtNames.Real);
  996. targetOutputReal = this->ConvertToNinjaPath(targetOutputReal);
  997. } else if (gt->IsFrameworkOnApple()) {
  998. // Create the library framework.
  999. cmOSXBundleGenerator::SkipParts bundleSkipParts;
  1000. if (globalGen->GetName() == "Ninja Multi-Config") {
  1001. auto const postFix = this->GeneratorTarget->GetFilePostfix(config);
  1002. // Skip creating Info.plist when there are multiple configurations, and
  1003. // the current configuration has a postfix. The non-postfix configuration
  1004. // Info.plist can be used by all the other configurations.
  1005. if (!postFix.empty()) {
  1006. bundleSkipParts.InfoPlist = true;
  1007. }
  1008. }
  1009. if (gt->HasImportLibrary(config)) {
  1010. bundleSkipParts.TextStubs = false;
  1011. }
  1012. this->OSXBundleGenerator->CreateFramework(
  1013. tgtNames.Output, gt->GetDirectory(config), config, bundleSkipParts);
  1014. } else if (gt->IsCFBundleOnApple()) {
  1015. // Create the core foundation bundle.
  1016. this->OSXBundleGenerator->CreateCFBundle(tgtNames.Output,
  1017. gt->GetDirectory(config), config);
  1018. }
  1019. // Write comments.
  1020. cmGlobalNinjaGenerator::WriteDivider(this->GetImplFileStream(fileConfig));
  1021. cmStateEnums::TargetType const targetType = gt->GetType();
  1022. this->GetImplFileStream(fileConfig)
  1023. << "# Link build statements for " << cmState::GetTargetTypeName(targetType)
  1024. << " target " << this->GetTargetName() << "\n\n";
  1025. cmNinjaBuild linkBuild(this->LanguageLinkerRule(config));
  1026. cmNinjaVars& vars = linkBuild.Variables;
  1027. if (this->GeneratorTarget->HasLinkDependencyFile(config)) {
  1028. this->AddDepfileBinding(vars,
  1029. this->ConvertToNinjaPath(
  1030. this->GetLocalGenerator()->GetLinkDependencyFile(
  1031. this->GeneratorTarget, config)));
  1032. }
  1033. // Compute the comment.
  1034. linkBuild.Comment =
  1035. cmStrCat("Link the ", this->GetVisibleTypeName(), ' ', targetOutputReal);
  1036. // Compute outputs.
  1037. linkBuild.Outputs.push_back(targetOutputReal);
  1038. if (firstForConfig) {
  1039. globalGen->GetByproductsForCleanTarget(config).push_back(targetOutputReal);
  1040. }
  1041. // If we can't split the Swift build model (CMP0157 is OLD or unset), fall
  1042. // back on the old one-step "build/link" logic.
  1043. if (!this->GetLocalGenerator()->IsSplitSwiftBuild() &&
  1044. this->TargetLinkLanguage(config) == "Swift") {
  1045. vars["SWIFT_LIBRARY_NAME"] = [this, config]() -> std::string {
  1046. cmGeneratorTarget::Names targetNames =
  1047. this->GetGeneratorTarget()->GetLibraryNames(config);
  1048. return targetNames.Base;
  1049. }();
  1050. vars["SWIFT_MODULE_NAME"] = gt->GetSwiftModuleName();
  1051. vars["SWIFT_MODULE"] = this->GetLocalGenerator()->ConvertToOutputFormat(
  1052. this->ConvertToNinjaPath(gt->GetSwiftModulePath(config)),
  1053. cmOutputConverter::SHELL);
  1054. vars["SWIFT_SOURCES"] = [this, config]() -> std::string {
  1055. std::vector<cmSourceFile const*> sourceFiles;
  1056. std::stringstream oss;
  1057. this->GetGeneratorTarget()->GetObjectSources(sourceFiles, config);
  1058. cmLocalGenerator const* LocalGen = this->GetLocalGenerator();
  1059. for (auto const& source : sourceFiles) {
  1060. std::string const sourcePath = source->GetLanguage() == "Swift"
  1061. ? this->GetCompiledSourceNinjaPath(source)
  1062. : this->GetObjectFilePath(source, config);
  1063. oss << " "
  1064. << LocalGen->ConvertToOutputFormat(sourcePath,
  1065. cmOutputConverter::SHELL);
  1066. }
  1067. return oss.str();
  1068. }();
  1069. // Since we do not perform object builds, compute the
  1070. // defines/flags/includes here so that they can be passed along
  1071. // appropriately.
  1072. vars["DEFINES"] = this->GetDefines("Swift", config);
  1073. vars["FLAGS"] = this->GetFlags("Swift", config);
  1074. vars["INCLUDES"] = this->GetIncludes("Swift", config);
  1075. this->GenerateSwiftOutputFileMap(config, vars["FLAGS"]);
  1076. // Compute specific libraries to link with.
  1077. std::vector<cmSourceFile const*> sources;
  1078. gt->GetObjectSources(sources, config);
  1079. for (auto const& source : sources) {
  1080. if (source->GetLanguage() == "Swift") {
  1081. linkBuild.Outputs.push_back(
  1082. this->ConvertToNinjaPath(this->GetObjectFilePath(source, config)));
  1083. linkBuild.ExplicitDeps.emplace_back(
  1084. this->GetCompiledSourceNinjaPath(source));
  1085. } else {
  1086. linkBuild.ExplicitDeps.emplace_back(
  1087. this->GetObjectFilePath(source, config));
  1088. }
  1089. }
  1090. if (targetType != cmStateEnums::EXECUTABLE ||
  1091. gt->IsExecutableWithExports()) {
  1092. linkBuild.Outputs.push_back(vars["SWIFT_MODULE"]);
  1093. }
  1094. } else {
  1095. linkBuild.ExplicitDeps = this->GetObjects(config);
  1096. }
  1097. std::vector<std::string> extraISPCObjects =
  1098. this->GetGeneratorTarget()->GetGeneratedISPCObjects(config);
  1099. std::transform(extraISPCObjects.begin(), extraISPCObjects.end(),
  1100. std::back_inserter(linkBuild.ExplicitDeps),
  1101. this->MapToNinjaPath());
  1102. linkBuild.ImplicitDeps =
  1103. this->ComputeLinkDeps(this->TargetLinkLanguage(config), config);
  1104. if (!this->DeviceLinkObject.empty()) {
  1105. linkBuild.ExplicitDeps.push_back(this->DeviceLinkObject);
  1106. }
  1107. std::string frameworkPath;
  1108. std::string linkPath;
  1109. std::string createRule =
  1110. gt->GetCreateRuleVariable(this->TargetLinkLanguage(config), config);
  1111. bool useWatcomQuote = mf->IsOn(createRule + "_USE_WATCOM_QUOTE");
  1112. cmLocalNinjaGenerator& localGen = *this->GetLocalGenerator();
  1113. vars["TARGET_FILE"] =
  1114. localGen.ConvertToOutputFormat(targetOutputReal, cmOutputConverter::SHELL);
  1115. std::unique_ptr<cmLinkLineComputer> linkLineComputer =
  1116. globalGen->CreateLinkLineComputer(
  1117. this->GetLocalGenerator(),
  1118. this->GetLocalGenerator()->GetStateSnapshot().GetDirectory());
  1119. linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
  1120. linkLineComputer->SetUseNinjaMulti(globalGen->IsMultiConfig());
  1121. localGen.GetTargetFlags(linkLineComputer.get(), config,
  1122. vars["LINK_LIBRARIES"], vars["FLAGS"],
  1123. vars["LINK_FLAGS"], frameworkPath, linkPath, gt);
  1124. localGen.AppendDependencyInfoLinkerFlags(vars["LINK_FLAGS"], gt, config,
  1125. this->TargetLinkLanguage(config));
  1126. // Add OS X version flags, if any.
  1127. if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY ||
  1128. this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) {
  1129. this->AppendOSXVerFlag(vars["LINK_FLAGS"],
  1130. this->TargetLinkLanguage(config), "COMPATIBILITY",
  1131. true);
  1132. this->AppendOSXVerFlag(vars["LINK_FLAGS"],
  1133. this->TargetLinkLanguage(config), "CURRENT", false);
  1134. }
  1135. this->addPoolNinjaVariable("JOB_POOL_LINK", gt, vars);
  1136. this->UseLWYU = this->GetLocalGenerator()->AppendLWYUFlags(
  1137. vars["LINK_FLAGS"], this->GetGeneratorTarget(),
  1138. this->TargetLinkLanguage(config));
  1139. vars["MANIFESTS"] = this->GetManifests(config);
  1140. vars["AIX_EXPORTS"] = this->GetAIXExports(config);
  1141. vars["LINK_PATH"] = frameworkPath + linkPath;
  1142. vars["CONFIG"] = config;
  1143. // Compute architecture specific link flags. Yes, these go into a different
  1144. // variable for executables, probably due to a mistake made when duplicating
  1145. // code between the Makefile executable and library generators.
  1146. if (targetType == cmStateEnums::EXECUTABLE) {
  1147. std::string t = vars["FLAGS"];
  1148. localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config),
  1149. config);
  1150. vars["FLAGS"] = t;
  1151. } else {
  1152. std::string t = vars["ARCH_FLAGS"];
  1153. localGen.AddArchitectureFlags(t, gt, this->TargetLinkLanguage(config),
  1154. config);
  1155. vars["ARCH_FLAGS"] = t;
  1156. t.clear();
  1157. localGen.AddLanguageFlagsForLinking(
  1158. t, gt, this->TargetLinkLanguage(config), config);
  1159. vars["LANGUAGE_COMPILE_FLAGS"] = t;
  1160. }
  1161. if (gt->HasSOName(config) || gt->IsArchivedAIXSharedLibrary()) {
  1162. vars["SONAME_FLAG"] = mf->GetSONameFlag(this->TargetLinkLanguage(config));
  1163. vars["SONAME"] = localGen.ConvertToOutputFormat(tgtNames.SharedObject,
  1164. cmOutputConverter::SHELL);
  1165. if (targetType == cmStateEnums::SHARED_LIBRARY) {
  1166. std::string install_dir = gt->GetInstallNameDirForBuildTree(config);
  1167. if (!install_dir.empty()) {
  1168. vars["INSTALLNAME_DIR"] = localGen.ConvertToOutputFormat(
  1169. install_dir, cmOutputConverter::SHELL);
  1170. }
  1171. }
  1172. }
  1173. cmGlobalNinjaGenerator::CCOutputs byproducts(this->GetGlobalGenerator());
  1174. if (!gt->IsApple() && !tgtNames.ImportLibrary.empty()) {
  1175. std::string const impLibPath = localGen.ConvertToOutputFormat(
  1176. targetOutputImplib, cmOutputConverter::SHELL);
  1177. vars["TARGET_IMPLIB"] = impLibPath;
  1178. this->EnsureParentDirectoryExists(targetOutputImplib);
  1179. if (gt->HasImportLibrary(config)) {
  1180. // Some linkers may update a binary without touching its import lib.
  1181. byproducts.ExplicitOuts.emplace_back(targetOutputImplib);
  1182. if (firstForConfig) {
  1183. globalGen->GetByproductsForCleanTarget(config).push_back(
  1184. targetOutputImplib);
  1185. }
  1186. }
  1187. }
  1188. if (!this->SetMsvcTargetPdbVariable(vars, config)) {
  1189. // It is common to place debug symbols at a specific place,
  1190. // so we need a plain target name in the rule available.
  1191. cmGeneratorTarget::NameComponents const& components =
  1192. gt->GetFullNameComponents(config);
  1193. std::string dbg_suffix = ".dbg";
  1194. // TODO: Where to document?
  1195. if (cmValue d = mf->GetDefinition("CMAKE_DEBUG_SYMBOL_SUFFIX")) {
  1196. dbg_suffix = *d;
  1197. }
  1198. vars["TARGET_PDB"] = components.base + components.suffix + dbg_suffix;
  1199. }
  1200. std::string const objPath =
  1201. cmStrCat(gt->GetSupportDirectory(), globalGen->ConfigDirectory(config));
  1202. vars["OBJECT_DIR"] = this->GetLocalGenerator()->ConvertToOutputFormat(
  1203. this->ConvertToNinjaPath(objPath), cmOutputConverter::SHELL);
  1204. this->EnsureDirectoryExists(objPath);
  1205. std::string& linkLibraries = vars["LINK_LIBRARIES"];
  1206. std::string& link_path = vars["LINK_PATH"];
  1207. if (globalGen->IsGCCOnWindows()) {
  1208. // ar.exe can't handle backslashes in rsp files (implicitly used by gcc)
  1209. std::replace(linkLibraries.begin(), linkLibraries.end(), '\\', '/');
  1210. std::replace(link_path.begin(), link_path.end(), '\\', '/');
  1211. }
  1212. std::vector<cmCustomCommand> const* cmdLists[3] = {
  1213. &gt->GetPreBuildCommands(), &gt->GetPreLinkCommands(),
  1214. &gt->GetPostBuildCommands()
  1215. };
  1216. std::vector<std::string> preLinkCmdLines;
  1217. std::vector<std::string> postBuildCmdLines;
  1218. std::vector<std::string>* cmdLineLists[3] = { &preLinkCmdLines,
  1219. &preLinkCmdLines,
  1220. &postBuildCmdLines };
  1221. for (unsigned i = 0; i != 3; ++i) {
  1222. for (cmCustomCommand const& cc : *cmdLists[i]) {
  1223. if (config == fileConfig ||
  1224. this->GetLocalGenerator()->HasUniqueByproducts(cc.GetByproducts(),
  1225. cc.GetBacktrace())) {
  1226. cmCustomCommandGenerator ccg(cc, fileConfig, this->GetLocalGenerator(),
  1227. true, config);
  1228. localGen.AppendCustomCommandLines(ccg, *cmdLineLists[i]);
  1229. std::vector<std::string> const& ccByproducts = ccg.GetByproducts();
  1230. byproducts.Add(ccByproducts);
  1231. std::transform(
  1232. ccByproducts.begin(), ccByproducts.end(),
  1233. std::back_inserter(globalGen->GetByproductsForCleanTarget()),
  1234. this->MapToNinjaPath());
  1235. }
  1236. }
  1237. }
  1238. // maybe create .def file from list of objects
  1239. cmGeneratorTarget::ModuleDefinitionInfo const* mdi =
  1240. gt->GetModuleDefinitionInfo(config);
  1241. if (mdi && mdi->DefFileGenerated) {
  1242. std::string cmakeCommand =
  1243. this->GetLocalGenerator()->ConvertToOutputFormat(
  1244. cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL);
  1245. std::string cmd =
  1246. cmStrCat(cmakeCommand, " -E __create_def ",
  1247. this->GetLocalGenerator()->ConvertToOutputFormat(
  1248. mdi->DefFile, cmOutputConverter::SHELL),
  1249. ' ');
  1250. std::string obj_list_file = mdi->DefFile + ".objs";
  1251. cmd += this->GetLocalGenerator()->ConvertToOutputFormat(
  1252. obj_list_file, cmOutputConverter::SHELL);
  1253. cmValue nm_executable = this->GetMakefile()->GetDefinition("CMAKE_NM");
  1254. if (cmNonempty(nm_executable)) {
  1255. cmd += " --nm=";
  1256. cmd += this->LocalCommonGenerator->ConvertToOutputFormat(
  1257. *nm_executable, cmOutputConverter::SHELL);
  1258. }
  1259. preLinkCmdLines.push_back(std::move(cmd));
  1260. // create a list of obj files for the -E __create_def to read
  1261. cmGeneratedFileStream fout(obj_list_file);
  1262. if (mdi->WindowsExportAllSymbols) {
  1263. cmNinjaDeps objs = this->GetObjects(config);
  1264. for (std::string const& obj : objs) {
  1265. if (cmHasLiteralSuffix(obj, ".obj")) {
  1266. fout << obj << "\n";
  1267. }
  1268. }
  1269. }
  1270. for (cmSourceFile const* src : mdi->Sources) {
  1271. fout << src->GetFullPath() << "\n";
  1272. }
  1273. }
  1274. // If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR
  1275. // for the link commands.
  1276. if (!preLinkCmdLines.empty()) {
  1277. std::string const homeOutDir = localGen.ConvertToOutputFormat(
  1278. localGen.GetBinaryDirectory(), cmOutputConverter::SHELL);
  1279. preLinkCmdLines.push_back("cd " + homeOutDir);
  1280. }
  1281. vars["PRE_LINK"] = localGen.BuildCommandLine(
  1282. preLinkCmdLines, config, fileConfig, "pre-link", this->GeneratorTarget);
  1283. std::string postBuildCmdLine =
  1284. localGen.BuildCommandLine(postBuildCmdLines, config, fileConfig,
  1285. "post-build", this->GeneratorTarget);
  1286. cmNinjaVars symlinkVars;
  1287. bool const symlinkNeeded =
  1288. (targetOutput != targetOutputReal && !gt->IsFrameworkOnApple() &&
  1289. !gt->IsArchivedAIXSharedLibrary());
  1290. if (!symlinkNeeded) {
  1291. vars["POST_BUILD"] = postBuildCmdLine;
  1292. } else {
  1293. vars["POST_BUILD"] = cmGlobalNinjaGenerator::SHELL_NOOP;
  1294. symlinkVars["POST_BUILD"] = postBuildCmdLine;
  1295. }
  1296. std::string cmakeVarLang =
  1297. cmStrCat("CMAKE_", this->TargetLinkLanguage(config));
  1298. // build response file name
  1299. std::string cmakeLinkVar = cmakeVarLang + "_RESPONSE_FILE_LINK_FLAG";
  1300. cmValue flag = this->GetMakefile()->GetDefinition(cmakeLinkVar);
  1301. bool const lang_supports_response =
  1302. !(this->TargetLinkLanguage(config) == "RC" ||
  1303. (this->TargetLinkLanguage(config) == "CUDA" && !flag));
  1304. int commandLineLengthLimit = -1;
  1305. if (!lang_supports_response || !this->ForceResponseFile()) {
  1306. commandLineLengthLimit =
  1307. static_cast<int>(cmSystemTools::CalculateCommandLineLengthLimit()) -
  1308. globalGen->GetRuleCmdLength(linkBuild.Rule);
  1309. }
  1310. linkBuild.RspFile = this->ConvertToNinjaPath(
  1311. cmStrCat("CMakeFiles/", gt->GetName(),
  1312. globalGen->IsMultiConfig() ? cmStrCat('.', config) : "", ".rsp"));
  1313. // Gather order-only dependencies.
  1314. this->GetLocalGenerator()->AppendTargetDepends(
  1315. gt, linkBuild.OrderOnlyDeps, config, fileConfig, DependOnTargetArtifact);
  1316. // Add order-only dependencies on versioning symlinks of shared libs we link.
  1317. // If our target is not producing a runtime binary, it doesn't need the
  1318. // symlinks (anything that links to the target might, but that consumer will
  1319. // get its own order-only dependency).
  1320. if (!gt->IsDLLPlatform() && gt->IsRuntimeBinary()) {
  1321. if (cmComputeLinkInformation* cli = gt->GetLinkInformation(config)) {
  1322. for (auto const& item : cli->GetItems()) {
  1323. if (item.Target &&
  1324. item.Target->GetType() == cmStateEnums::SHARED_LIBRARY &&
  1325. !item.Target->IsFrameworkOnApple()) {
  1326. std::string const& lib =
  1327. this->ConvertToNinjaPath(item.Target->GetFullPath(config));
  1328. if (std::find(linkBuild.ImplicitDeps.begin(),
  1329. linkBuild.ImplicitDeps.end(),
  1330. lib) == linkBuild.ImplicitDeps.end()) {
  1331. linkBuild.OrderOnlyDeps.emplace_back(lib);
  1332. }
  1333. }
  1334. }
  1335. }
  1336. }
  1337. // Add dependencies on swiftmodule files when using the swift linker
  1338. if (this->TargetLinkLanguage(config) == "Swift") {
  1339. if (cmComputeLinkInformation* cli =
  1340. this->GeneratorTarget->GetLinkInformation(config)) {
  1341. for (auto const& dependency : cli->GetItems()) {
  1342. // Both the current target and the linked target must be swift targets
  1343. // in order for there to be a swiftmodule to depend on
  1344. if (dependency.Target &&
  1345. dependency.Target->GetLinkerLanguage(config) == "Swift") {
  1346. std::string swiftmodule = this->ConvertToNinjaPath(
  1347. dependency.Target->GetSwiftModulePath(config));
  1348. linkBuild.ImplicitDeps.emplace_back(swiftmodule);
  1349. }
  1350. }
  1351. }
  1352. }
  1353. // Ninja should restat after linking if and only if there are byproducts.
  1354. vars["RESTAT"] = byproducts.ExplicitOuts.empty() ? "" : "1";
  1355. linkBuild.Outputs.reserve(linkBuild.Outputs.size() +
  1356. byproducts.ExplicitOuts.size());
  1357. std::move(byproducts.ExplicitOuts.begin(), byproducts.ExplicitOuts.end(),
  1358. std::back_inserter(linkBuild.Outputs));
  1359. linkBuild.WorkDirOuts = std::move(byproducts.WorkDirOuts);
  1360. // Write the build statement for this target.
  1361. bool usedResponseFile = false;
  1362. globalGen->WriteBuild(this->GetImplFileStream(fileConfig), linkBuild,
  1363. commandLineLengthLimit, &usedResponseFile);
  1364. this->WriteLinkRule(usedResponseFile, config);
  1365. if (symlinkNeeded) {
  1366. if (targetType == cmStateEnums::EXECUTABLE) {
  1367. cmNinjaBuild build("CMAKE_SYMLINK_EXECUTABLE");
  1368. build.Comment = "Create executable symlink " + targetOutput;
  1369. build.Outputs.push_back(targetOutput);
  1370. if (firstForConfig) {
  1371. globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput);
  1372. }
  1373. build.ExplicitDeps.push_back(targetOutputReal);
  1374. build.Variables = std::move(symlinkVars);
  1375. globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
  1376. } else {
  1377. cmNinjaBuild build("CMAKE_SYMLINK_LIBRARY");
  1378. build.Comment = "Create library symlink " + targetOutput;
  1379. std::string const soName = this->ConvertToNinjaPath(
  1380. this->GetTargetFilePath(tgtNames.SharedObject, config));
  1381. // If one link has to be created.
  1382. if (targetOutputReal == soName || targetOutput == soName) {
  1383. symlinkVars["SONAME"] =
  1384. this->GetLocalGenerator()->ConvertToOutputFormat(
  1385. soName, cmOutputConverter::SHELL);
  1386. } else {
  1387. symlinkVars["SONAME"].clear();
  1388. build.Outputs.push_back(soName);
  1389. if (firstForConfig) {
  1390. globalGen->GetByproductsForCleanTarget(config).push_back(soName);
  1391. }
  1392. }
  1393. build.Outputs.push_back(targetOutput);
  1394. if (firstForConfig) {
  1395. globalGen->GetByproductsForCleanTarget(config).push_back(targetOutput);
  1396. }
  1397. build.ExplicitDeps.push_back(targetOutputReal);
  1398. build.Variables = std::move(symlinkVars);
  1399. globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
  1400. }
  1401. }
  1402. // Add aliases for the file name and the target name.
  1403. globalGen->AddTargetAlias(tgtNames.Output, gt, config);
  1404. globalGen->AddTargetAlias(this->GetTargetName(), gt, config);
  1405. if (this->GetGeneratorTarget()->IsApple() &&
  1406. this->GetGeneratorTarget()->HasImportLibrary(config)) {
  1407. auto dirTBD =
  1408. gt->GetDirectory(config, cmStateEnums::ImportLibraryArtifact);
  1409. auto targetTBD =
  1410. this->ConvertToNinjaPath(cmStrCat(dirTBD, '/', tgtNames.ImportReal));
  1411. this->EnsureParentDirectoryExists(targetTBD);
  1412. cmNinjaBuild build(this->TextStubsGeneratorRule(config));
  1413. build.Comment = cmStrCat("Generate the text-based stubs file ", targetTBD);
  1414. build.Outputs.push_back(targetTBD);
  1415. build.ExplicitDeps.push_back(targetOutputReal);
  1416. globalGen->WriteBuild(this->GetImplFileStream(fileConfig), build);
  1417. if (tgtNames.ImportOutput != tgtNames.ImportReal &&
  1418. !this->GetGeneratorTarget()->IsFrameworkOnApple()) {
  1419. auto outputTBD =
  1420. this->ConvertToNinjaPath(cmStrCat(dirTBD, '/', tgtNames.ImportOutput));
  1421. std::string const soNameTBD = this->ConvertToNinjaPath(
  1422. cmStrCat(dirTBD, '/', tgtNames.ImportLibrary));
  1423. cmNinjaBuild slBuild("CMAKE_SYMLINK_IMPORT_LIBRARY");
  1424. slBuild.Comment = cmStrCat("Create import library symlink ", outputTBD);
  1425. cmNinjaVars slVars;
  1426. // If one link has to be created.
  1427. if (targetTBD == soNameTBD || outputTBD == soNameTBD) {
  1428. slVars["SONAME"] = this->GetLocalGenerator()->ConvertToOutputFormat(
  1429. soNameTBD, cmOutputConverter::SHELL);
  1430. } else {
  1431. slVars["SONAME"].clear();
  1432. slBuild.Outputs.push_back(soNameTBD);
  1433. if (firstForConfig) {
  1434. globalGen->GetByproductsForCleanTarget(config).push_back(soNameTBD);
  1435. }
  1436. }
  1437. slBuild.Outputs.push_back(outputTBD);
  1438. if (firstForConfig) {
  1439. globalGen->GetByproductsForCleanTarget(config).push_back(outputTBD);
  1440. }
  1441. slBuild.ExplicitDeps.push_back(targetTBD);
  1442. slBuild.Variables = std::move(slVars);
  1443. globalGen->WriteBuild(this->GetImplFileStream(fileConfig), slBuild);
  1444. }
  1445. // Add alias for the import file name
  1446. globalGen->AddTargetAlias(tgtNames.ImportOutput, gt, config);
  1447. }
  1448. }
  1449. void cmNinjaNormalTargetGenerator::WriteObjectLibStatement(
  1450. std::string const& config)
  1451. {
  1452. // Write a phony output that depends on all object files.
  1453. {
  1454. cmNinjaBuild build("phony");
  1455. build.Comment = "Object library " + this->GetTargetName();
  1456. this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
  1457. build.Outputs, config);
  1458. this->GetLocalGenerator()->AppendTargetOutputs(
  1459. this->GetGeneratorTarget(),
  1460. this->GetGlobalGenerator()->GetByproductsForCleanTarget(config), config);
  1461. build.ExplicitDeps = this->GetObjects(config);
  1462. this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), build);
  1463. }
  1464. // Add aliases for the target name.
  1465. this->GetGlobalGenerator()->AddTargetAlias(
  1466. this->GetTargetName(), this->GetGeneratorTarget(), config);
  1467. }
  1468. void cmNinjaNormalTargetGenerator::WriteCxxModuleLibraryStatement(
  1469. std::string const& config, std::string const& /*fileConfig*/,
  1470. bool firstForConfig)
  1471. {
  1472. // TODO: How to use `fileConfig` properly?
  1473. // Write a phony output that depends on the scanning output.
  1474. {
  1475. cmNinjaBuild build("phony");
  1476. build.Comment =
  1477. cmStrCat("Imported C++ module library ", this->GetTargetName());
  1478. this->GetLocalGenerator()->AppendTargetOutputs(this->GetGeneratorTarget(),
  1479. build.Outputs, config);
  1480. if (firstForConfig) {
  1481. this->GetLocalGenerator()->AppendTargetOutputs(
  1482. this->GetGeneratorTarget(),
  1483. this->GetGlobalGenerator()->GetByproductsForCleanTarget(config),
  1484. config);
  1485. }
  1486. build.ExplicitDeps.emplace_back(this->GetDyndepFilePath("CXX", config));
  1487. this->GetGlobalGenerator()->WriteBuild(this->GetCommonFileStream(), build);
  1488. }
  1489. // Add aliases for the target name.
  1490. this->GetGlobalGenerator()->AddTargetAlias(
  1491. this->GetTargetName(), this->GetGeneratorTarget(), config);
  1492. }
  1493. cmGeneratorTarget::Names cmNinjaNormalTargetGenerator::TargetNames(
  1494. std::string const& config) const
  1495. {
  1496. if (this->GeneratorTarget->GetType() == cmStateEnums::EXECUTABLE) {
  1497. return this->GeneratorTarget->GetExecutableNames(config);
  1498. }
  1499. return this->GeneratorTarget->GetLibraryNames(config);
  1500. }
  1501. std::string cmNinjaNormalTargetGenerator::TargetLinkLanguage(
  1502. std::string const& config) const
  1503. {
  1504. return this->GeneratorTarget->GetLinkerLanguage(config);
  1505. }