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