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