cmNinjaNormalTargetGenerator.cxx 46 KB

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