cmNinjaNormalTargetGenerator.cxx 46 KB

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