resolve cyclic dependency with zstd
[platform/upstream/cmake.git] / Source / cmMakefileExecutableTargetGenerator.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 "cmMakefileExecutableTargetGenerator.h"
4
5 #include <set>
6 #include <sstream>
7 #include <string>
8 #include <utility>
9 #include <vector>
10
11 #include <cm/memory>
12 #include <cmext/algorithm>
13
14 #include "cmGeneratedFileStream.h"
15 #include "cmGeneratorTarget.h"
16 #include "cmGlobalUnixMakefileGenerator3.h"
17 #include "cmLinkLineComputer.h"
18 #include "cmLinkLineDeviceComputer.h"
19 #include "cmLocalGenerator.h"
20 #include "cmLocalUnixMakefileGenerator3.h"
21 #include "cmMakefile.h"
22 #include "cmOSXBundleGenerator.h"
23 #include "cmOutputConverter.h"
24 #include "cmRulePlaceholderExpander.h"
25 #include "cmState.h"
26 #include "cmStateDirectory.h"
27 #include "cmStateSnapshot.h"
28 #include "cmStateTypes.h"
29 #include "cmStringAlgorithms.h"
30 #include "cmSystemTools.h"
31 #include "cmValue.h"
32
33 cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
34   cmGeneratorTarget* target)
35   : cmMakefileTargetGenerator(target)
36 {
37   this->CustomCommandDriver = OnDepends;
38   this->TargetNames =
39     this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
40
41   this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
42   this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
43 }
44
45 cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =
46   default;
47
48 void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
49 {
50   // create the build.make file and directory, put in the common blocks
51   this->CreateRuleFile();
52
53   // write rules used to help build object files
54   this->WriteCommonCodeRules();
55
56   // write the per-target per-language flags
57   this->WriteTargetLanguageFlags();
58
59   // write in rules for object files and custom commands
60   this->WriteTargetBuildRules();
61
62   // write the device link rules
63   this->WriteDeviceExecutableRule(false);
64
65   // write the link rules
66   this->WriteExecutableRule(false);
67   if (this->GeneratorTarget->NeedRelinkBeforeInstall(this->GetConfigName())) {
68     // Write rules to link an installable version of the target.
69     this->WriteExecutableRule(true);
70   }
71
72   // Write clean target
73   this->WriteTargetCleanRules();
74
75   // Write the dependency generation rule.  This must be done last so
76   // that multiple output pair information is available.
77   this->WriteTargetDependRules();
78
79   // close the streams
80   this->CloseFileStreams();
81 }
82
83 void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
84   bool relink)
85 {
86 #ifndef CMAKE_BOOTSTRAP
87   const bool requiresDeviceLinking = requireDeviceLinking(
88     *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
89   if (!requiresDeviceLinking) {
90     return;
91   }
92
93   std::vector<std::string> commands;
94
95   // Get the name of the device object to generate.
96   std::string const& objExt =
97     this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION");
98   std::string const targetOutput =
99     this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt;
100   this->DeviceLinkObject = targetOutput;
101
102   this->NumberOfProgressActions++;
103   if (!this->NoRuleMessages) {
104     cmLocalUnixMakefileGenerator3::EchoProgress progress;
105     this->MakeEchoProgress(progress);
106     // Add the link message.
107     std::string buildEcho = cmStrCat(
108       "Linking CUDA device code ",
109       this->LocalGenerator->ConvertToOutputFormat(
110         this->LocalGenerator->MaybeRelativeToCurBinDir(this->DeviceLinkObject),
111         cmOutputConverter::SHELL));
112     this->LocalGenerator->AppendEcho(
113       commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
114   }
115
116   if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") {
117     this->WriteDeviceLinkRule(commands, targetOutput);
118   } else {
119     this->WriteNvidiaDeviceExecutableRule(relink, commands, targetOutput);
120   }
121
122   // Write the main driver rule to build everything in this target.
123   this->WriteTargetDriverRule(targetOutput, relink);
124 #else
125   static_cast<void>(relink);
126 #endif
127 }
128
129 void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
130   bool relink, std::vector<std::string>& commands,
131   const std::string& targetOutput)
132 {
133   const std::string linkLanguage = "CUDA";
134
135   // Build list of dependencies.
136   std::vector<std::string> depends;
137   this->AppendLinkDepends(depends, linkLanguage);
138
139   // Add language feature flags.
140   std::string langFlags;
141   this->LocalGenerator->AddLanguageFlagsForLinking(
142     langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
143
144   // Construct a list of files associated with this executable that
145   // may need to be cleaned.
146   std::vector<std::string> exeCleanFiles;
147   exeCleanFiles.push_back(
148     this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput));
149
150   // Determine whether a link script will be used.
151   bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
152
153   // Construct the main link rule.
154   std::vector<std::string> real_link_commands;
155   const std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_EXECUTABLE";
156   const std::string linkRule = this->GetLinkRule(linkRuleVar);
157   std::vector<std::string> commands1;
158   cmExpandList(linkRule, real_link_commands);
159
160   bool useResponseFileForObjects =
161     this->CheckUseResponseFileForObjects(linkLanguage);
162   bool const useResponseFileForLibs =
163     this->CheckUseResponseFileForLibraries(linkLanguage);
164
165   // Expand the rule variables.
166   {
167     // Set path conversion for link script shells.
168     this->LocalGenerator->SetLinkScriptShell(useLinkScript);
169
170     std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer(
171       new cmLinkLineDeviceComputer(
172         this->LocalGenerator,
173         this->LocalGenerator->GetStateSnapshot().GetDirectory()));
174     linkLineComputer->SetForResponse(useResponseFileForLibs);
175     linkLineComputer->SetRelink(relink);
176
177     // Create set of linking flags.
178     std::string linkFlags;
179     std::string ignored_;
180     this->LocalGenerator->GetDeviceLinkFlags(
181       *linkLineComputer, this->GetConfigName(), ignored_, linkFlags, ignored_,
182       ignored_, this->GeneratorTarget);
183
184     // Collect up flags to link in needed libraries.
185     std::string linkLibs;
186     this->CreateLinkLibs(
187       linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends,
188       cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
189
190     // Construct object file lists that may be needed to expand the
191     // rule.
192     std::string buildObjs;
193     this->CreateObjectLists(
194       useLinkScript, false, useResponseFileForObjects, buildObjs, depends,
195       false, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
196
197     cmRulePlaceholderExpander::RuleVariables vars;
198     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
199
200     objectDir = this->LocalGenerator->ConvertToOutputFormat(
201       this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
202       cmOutputConverter::SHELL);
203
204     std::string target = this->LocalGenerator->ConvertToOutputFormat(
205       this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput),
206       cmOutputConverter::SHELL);
207
208     std::string targetFullPathCompilePDB =
209       this->ComputeTargetCompilePDB(this->GetConfigName());
210     std::string targetOutPathCompilePDB =
211       this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
212                                                   cmOutputConverter::SHELL);
213
214     vars.Language = linkLanguage.c_str();
215     vars.Objects = buildObjs.c_str();
216     vars.ObjectDir = objectDir.c_str();
217     vars.Target = target.c_str();
218     vars.LinkLibraries = linkLibs.c_str();
219     vars.LanguageCompileFlags = langFlags.c_str();
220     vars.LinkFlags = linkFlags.c_str();
221     vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
222
223     std::string launcher;
224
225     cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
226                                                         "RULE_LAUNCH_LINK");
227     if (cmNonempty(val)) {
228       launcher = cmStrCat(*val, ' ');
229     }
230
231     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
232       this->LocalGenerator->CreateRulePlaceholderExpander());
233
234     // Expand placeholders in the commands.
235     rulePlaceholderExpander->SetTargetImpLib(targetOutput);
236     for (std::string& real_link_command : real_link_commands) {
237       real_link_command = cmStrCat(launcher, real_link_command);
238       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
239                                                    real_link_command, vars);
240     }
241
242     // Restore path conversion to normal shells.
243     this->LocalGenerator->SetLinkScriptShell(false);
244   }
245
246   // Optionally convert the build rule to use a script to avoid long
247   // command lines in the make shell.
248   if (useLinkScript) {
249     // Use a link script.
250     const char* name = (relink ? "drelink.txt" : "dlink.txt");
251     this->CreateLinkScript(name, real_link_commands, commands1, depends);
252   } else {
253     // No link script.  Just use the link rule directly.
254     commands1 = real_link_commands;
255   }
256   this->LocalGenerator->CreateCDCommand(
257     commands1, this->Makefile->GetCurrentBinaryDirectory(),
258     this->LocalGenerator->GetBinaryDirectory());
259   cm::append(commands, commands1);
260   commands1.clear();
261
262   // Write the build rule.
263   this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
264                                       targetOutput, depends, commands, false);
265
266   // Clean all the possible executable names and symlinks.
267   this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
268 }
269
270 void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
271 {
272   std::vector<std::string> commands;
273
274   // Get the name of the executable to generate.
275   cmGeneratorTarget::Names targetNames =
276     this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
277
278   // Construct the full path version of the names.
279   std::string outpath =
280     this->GeneratorTarget->GetDirectory(this->GetConfigName());
281   if (this->GeneratorTarget->IsAppBundleOnApple()) {
282     this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
283                                               this->GetConfigName());
284   }
285   outpath += '/';
286   std::string outpathImp;
287   if (relink) {
288     outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(),
289                        "/CMakeFiles/CMakeRelink.dir");
290     cmSystemTools::MakeDirectory(outpath);
291     outpath += '/';
292     if (!targetNames.ImportLibrary.empty()) {
293       outpathImp = outpath;
294     }
295   } else {
296     cmSystemTools::MakeDirectory(outpath);
297     if (!targetNames.ImportLibrary.empty()) {
298       outpathImp = this->GeneratorTarget->GetDirectory(
299         this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
300       cmSystemTools::MakeDirectory(outpathImp);
301       outpathImp += '/';
302     }
303   }
304
305   std::string compilePdbOutputPath =
306     this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
307   cmSystemTools::MakeDirectory(compilePdbOutputPath);
308
309   std::string pdbOutputPath =
310     this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
311   cmSystemTools::MakeDirectory(pdbOutputPath);
312   pdbOutputPath += '/';
313
314   std::string targetFullPath = outpath + targetNames.Output;
315   std::string targetFullPathReal = outpath + targetNames.Real;
316   std::string targetFullPathPDB = pdbOutputPath + targetNames.PDB;
317   std::string targetFullPathImport = outpathImp + targetNames.ImportLibrary;
318   std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
319     targetFullPathPDB, cmOutputConverter::SHELL);
320   // Convert to the output path to use in constructing commands.
321   std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat(
322     this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPath),
323     cmOutputConverter::SHELL);
324   std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
325     this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
326     cmOutputConverter::SHELL);
327   std::string targetOutPathImport =
328     this->LocalGenerator->ConvertToOutputFormat(
329       this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport),
330       cmOutputConverter::SHELL);
331
332   // Get the language to use for linking this executable.
333   std::string linkLanguage =
334     this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
335
336   // Make sure we have a link language.
337   if (linkLanguage.empty()) {
338     cmSystemTools::Error("Cannot determine link language for target \"" +
339                          this->GeneratorTarget->GetName() + "\".");
340     return;
341   }
342
343   // Build list of dependencies.
344   std::vector<std::string> depends;
345   this->AppendLinkDepends(depends, linkLanguage);
346   if (!this->DeviceLinkObject.empty()) {
347     depends.push_back(this->DeviceLinkObject);
348   }
349
350   this->NumberOfProgressActions++;
351   if (!this->NoRuleMessages) {
352     cmLocalUnixMakefileGenerator3::EchoProgress progress;
353     this->MakeEchoProgress(progress);
354     // Add the link message.
355     std::string buildEcho =
356       cmStrCat("Linking ", linkLanguage, " executable ", targetOutPath);
357     this->LocalGenerator->AppendEcho(
358       commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
359   }
360
361   // Build a list of compiler flags and linker flags.
362   std::string flags;
363   std::string linkFlags;
364
365   // Add flags to create an executable.
366   this->LocalGenerator->AddConfigVariableFlags(
367     linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
368
369   if (this->GeneratorTarget->IsWin32Executable(
370         this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
371     this->LocalGenerator->AppendFlags(
372       linkFlags,
373       this->Makefile->GetSafeDefinition(
374         cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE")));
375   } else {
376     this->LocalGenerator->AppendFlags(
377       linkFlags,
378       this->Makefile->GetSafeDefinition(
379         cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE")));
380   }
381
382   // Add symbol export flags if necessary.
383   if (this->GeneratorTarget->IsExecutableWithExports()) {
384     std::string export_flag_var =
385       cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG");
386     this->LocalGenerator->AppendFlags(
387       linkFlags, this->Makefile->GetSafeDefinition(export_flag_var));
388   }
389
390   this->LocalGenerator->AppendFlags(linkFlags,
391                                     this->LocalGenerator->GetLinkLibsCMP0065(
392                                       linkLanguage, *this->GeneratorTarget));
393
394   this->UseLWYU = this->LocalGenerator->AppendLWYUFlags(
395     linkFlags, this->GeneratorTarget, linkLanguage);
396
397   // Add language feature flags.
398   this->LocalGenerator->AddLanguageFlagsForLinking(
399     flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
400
401   this->LocalGenerator->AddArchitectureFlags(
402     flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
403
404   // Add target-specific linker flags.
405   this->GetTargetLinkFlags(linkFlags, linkLanguage);
406
407   {
408     std::unique_ptr<cmLinkLineComputer> linkLineComputer =
409       this->CreateLinkLineComputer(
410         this->LocalGenerator,
411         this->LocalGenerator->GetStateSnapshot().GetDirectory());
412
413     this->LocalGenerator->AppendModuleDefinitionFlag(
414       linkFlags, this->GeneratorTarget, linkLineComputer.get(),
415       this->GetConfigName());
416   }
417
418   this->LocalGenerator->AppendIPOLinkerFlags(
419     linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
420
421   // Construct a list of files associated with this executable that
422   // may need to be cleaned.
423   std::vector<std::string> exeCleanFiles;
424   exeCleanFiles.push_back(
425     this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPath));
426 #ifdef _WIN32
427   // There may be a manifest file for this target.  Add it to the
428   // clean set just in case.
429   exeCleanFiles.push_back(this->LocalGenerator->MaybeRelativeToCurBinDir(
430     targetFullPath + ".manifest"));
431 #endif
432   if (this->TargetNames.Real != this->TargetNames.Output) {
433     exeCleanFiles.push_back(
434       this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal));
435   }
436   if (!this->TargetNames.ImportLibrary.empty()) {
437     exeCleanFiles.push_back(
438       this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport));
439     std::string implib;
440     if (this->GeneratorTarget->GetImplibGNUtoMS(
441           this->GetConfigName(), targetFullPathImport, implib)) {
442       exeCleanFiles.push_back(
443         this->LocalGenerator->MaybeRelativeToCurBinDir(implib));
444     }
445   }
446
447   // List the PDB for cleaning only when the whole target is
448   // cleaned.  We do not want to delete the .pdb file just before
449   // linking the target.
450   this->CleanFiles.insert(
451     this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathPDB));
452
453   // Add the pre-build and pre-link rules building but not when relinking.
454   if (!relink) {
455     this->LocalGenerator->AppendCustomCommands(
456       commands, this->GeneratorTarget->GetPreBuildCommands(),
457       this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
458     this->LocalGenerator->AppendCustomCommands(
459       commands, this->GeneratorTarget->GetPreLinkCommands(),
460       this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
461   }
462
463   // Determine whether a link script will be used.
464   bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
465
466   // Construct the main link rule.
467   std::vector<std::string> real_link_commands;
468   std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable(
469     linkLanguage, this->GetConfigName());
470   std::string linkRule = this->GetLinkRule(linkRuleVar);
471   std::vector<std::string> commands1;
472   cmExpandList(linkRule, real_link_commands);
473   if (this->GeneratorTarget->IsExecutableWithExports()) {
474     // If a separate rule for creating an import library is specified
475     // add it now.
476     std::string implibRuleVar =
477       cmStrCat("CMAKE_", linkLanguage, "_CREATE_IMPORT_LIBRARY");
478     this->Makefile->GetDefExpandList(implibRuleVar, real_link_commands);
479   }
480
481   bool useResponseFileForObjects =
482     this->CheckUseResponseFileForObjects(linkLanguage);
483   bool const useResponseFileForLibs =
484     this->CheckUseResponseFileForLibraries(linkLanguage);
485
486   // Expand the rule variables.
487   {
488     bool useWatcomQuote =
489       this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
490
491     // Set path conversion for link script shells.
492     this->LocalGenerator->SetLinkScriptShell(useLinkScript);
493
494     std::unique_ptr<cmLinkLineComputer> linkLineComputer =
495       this->CreateLinkLineComputer(
496         this->LocalGenerator,
497         this->LocalGenerator->GetStateSnapshot().GetDirectory());
498     linkLineComputer->SetForResponse(useResponseFileForLibs);
499     linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
500     linkLineComputer->SetRelink(relink);
501
502     // Collect up flags to link in needed libraries.
503     std::string linkLibs;
504     this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
505                          useResponseFileForLibs, depends);
506
507     // Construct object file lists that may be needed to expand the
508     // rule.
509     std::string buildObjs;
510     this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
511                             buildObjs, depends, useWatcomQuote);
512     if (!this->DeviceLinkObject.empty()) {
513       buildObjs += " " +
514         this->LocalGenerator->ConvertToOutputFormat(
515           this->LocalGenerator->MaybeRelativeToCurBinDir(
516             this->DeviceLinkObject),
517           cmOutputConverter::SHELL);
518     }
519
520     // maybe create .def file from list of objects
521     this->GenDefFile(real_link_commands);
522
523     std::string manifests = this->GetManifests(this->GetConfigName());
524
525     std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
526
527     cmRulePlaceholderExpander::RuleVariables vars;
528     vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
529     vars.CMTargetType =
530       cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
531     vars.Language = linkLanguage.c_str();
532     vars.AIXExports = aixExports.c_str();
533     vars.Objects = buildObjs.c_str();
534     std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
535
536     objectDir = this->LocalGenerator->ConvertToOutputFormat(
537       this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
538       cmOutputConverter::SHELL);
539     vars.ObjectDir = objectDir.c_str();
540     cmOutputConverter::OutputFormat output = (useWatcomQuote)
541       ? cmOutputConverter::WATCOMQUOTE
542       : cmOutputConverter::SHELL;
543     std::string target = this->LocalGenerator->ConvertToOutputFormat(
544       this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
545       output);
546     vars.Target = target.c_str();
547     vars.TargetPDB = targetOutPathPDB.c_str();
548
549     // Setup the target version.
550     std::string targetVersionMajor;
551     std::string targetVersionMinor;
552     {
553       std::ostringstream majorStream;
554       std::ostringstream minorStream;
555       int major;
556       int minor;
557       this->GeneratorTarget->GetTargetVersion(major, minor);
558       majorStream << major;
559       minorStream << minor;
560       targetVersionMajor = majorStream.str();
561       targetVersionMinor = minorStream.str();
562     }
563     vars.TargetVersionMajor = targetVersionMajor.c_str();
564     vars.TargetVersionMinor = targetVersionMinor.c_str();
565
566     vars.LinkLibraries = linkLibs.c_str();
567     vars.Flags = flags.c_str();
568     vars.LinkFlags = linkFlags.c_str();
569     vars.Manifests = manifests.c_str();
570
571     std::string linkerLauncher =
572       this->GetLinkerLauncher(this->GetConfigName());
573     if (cmNonempty(linkerLauncher)) {
574       vars.Launcher = linkerLauncher.c_str();
575     }
576
577     if (this->UseLWYU) {
578       cmValue lwyuCheck =
579         this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
580       if (lwyuCheck) {
581         std::string cmakeCommand = cmStrCat(
582           this->LocalGenerator->ConvertToOutputFormat(
583             cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
584           " -E __run_co_compile --lwyu=");
585         cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck);
586         cmakeCommand += cmStrCat(" --source=", targetOutPathReal);
587         real_link_commands.push_back(std::move(cmakeCommand));
588       }
589     }
590
591     std::string launcher;
592
593     cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
594                                                         "RULE_LAUNCH_LINK");
595     if (cmNonempty(val)) {
596       launcher = cmStrCat(*val, ' ');
597     }
598
599     std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
600       this->LocalGenerator->CreateRulePlaceholderExpander());
601
602     // Expand placeholders in the commands.
603     rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
604     for (std::string& real_link_command : real_link_commands) {
605       real_link_command = cmStrCat(launcher, real_link_command);
606       rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
607                                                    real_link_command, vars);
608     }
609
610     // Restore path conversion to normal shells.
611     this->LocalGenerator->SetLinkScriptShell(false);
612   }
613
614   // Optionally convert the build rule to use a script to avoid long
615   // command lines in the make shell.
616   if (useLinkScript) {
617     // Use a link script.
618     const char* name = (relink ? "relink.txt" : "link.txt");
619     this->CreateLinkScript(name, real_link_commands, commands1, depends);
620   } else {
621     // No link script.  Just use the link rule directly.
622     commands1 = real_link_commands;
623   }
624   this->LocalGenerator->CreateCDCommand(
625     commands1, this->Makefile->GetCurrentBinaryDirectory(),
626     this->LocalGenerator->GetBinaryDirectory());
627   cm::append(commands, commands1);
628   commands1.clear();
629
630   // Add a rule to create necessary symlinks for the library.
631   if (targetOutPath != targetOutPathReal) {
632     std::string symlink =
633       cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_executable ",
634                targetOutPathReal, ' ', targetOutPath);
635     commands1.push_back(std::move(symlink));
636     this->LocalGenerator->CreateCDCommand(
637       commands1, this->Makefile->GetCurrentBinaryDirectory(),
638       this->LocalGenerator->GetBinaryDirectory());
639     cm::append(commands, commands1);
640     commands1.clear();
641   }
642
643   // Add the post-build rules when building but not when relinking.
644   if (!relink) {
645     this->LocalGenerator->AppendCustomCommands(
646       commands, this->GeneratorTarget->GetPostBuildCommands(),
647       this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
648   }
649
650   // Write the build rule.
651   this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
652                                       targetFullPathReal, depends, commands,
653                                       false);
654
655   // The symlink name for the target should depend on the real target
656   // so if the target version changes it rebuilds and recreates the
657   // symlink.
658   if (targetFullPath != targetFullPathReal) {
659     depends.clear();
660     commands.clear();
661     depends.push_back(targetFullPathReal);
662     this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
663                                         targetFullPath, depends, commands,
664                                         false);
665   }
666
667   // Write the main driver rule to build everything in this target.
668   this->WriteTargetDriverRule(targetFullPath, relink);
669
670   // Clean all the possible executable names and symlinks.
671   this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
672 }