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"
12 #include <cmext/algorithm>
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"
26 #include "cmStateDirectory.h"
27 #include "cmStateSnapshot.h"
28 #include "cmStateTypes.h"
29 #include "cmStringAlgorithms.h"
30 #include "cmSystemTools.h"
33 cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
34 cmGeneratorTarget* target)
35 : cmMakefileTargetGenerator(target)
37 this->CustomCommandDriver = OnDepends;
39 this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
41 this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target);
42 this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
45 cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =
48 void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
50 // create the build.make file and directory, put in the common blocks
51 this->CreateRuleFile();
53 // write rules used to help build object files
54 this->WriteCommonCodeRules();
56 // write the per-target per-language flags
57 this->WriteTargetLanguageFlags();
59 // write in rules for object files and custom commands
60 this->WriteTargetBuildRules();
62 // write the device link rules
63 this->WriteDeviceExecutableRule(false);
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);
73 this->WriteTargetCleanRules();
75 // Write the dependency generation rule. This must be done last so
76 // that multiple output pair information is available.
77 this->WriteTargetDependRules();
80 this->CloseFileStreams();
83 void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
86 #ifndef CMAKE_BOOTSTRAP
87 const bool requiresDeviceLinking = requireDeviceLinking(
88 *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName());
89 if (!requiresDeviceLinking) {
93 std::vector<std::string> commands;
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;
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);
116 if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") {
117 this->WriteDeviceLinkRule(commands, targetOutput);
119 this->WriteNvidiaDeviceExecutableRule(relink, commands, targetOutput);
122 // Write the main driver rule to build everything in this target.
123 this->WriteTargetDriverRule(targetOutput, relink);
125 static_cast<void>(relink);
129 void cmMakefileExecutableTargetGenerator::WriteNvidiaDeviceExecutableRule(
130 bool relink, std::vector<std::string>& commands,
131 const std::string& targetOutput)
133 const std::string linkLanguage = "CUDA";
135 // Build list of dependencies.
136 std::vector<std::string> depends;
137 this->AppendLinkDepends(depends, linkLanguage);
139 // Build a list of compiler flags and linker flags.
140 std::string langFlags;
141 std::string linkFlags;
143 // Add language feature flags.
144 this->LocalGenerator->AddLanguageFlagsForLinking(
145 langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
147 // Add device-specific linker flags.
148 this->GetDeviceLinkFlags(linkFlags, linkLanguage);
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));
156 // Determine whether a link script will be used.
157 bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
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);
166 bool useResponseFileForObjects =
167 this->CheckUseResponseFileForObjects(linkLanguage);
168 bool const useResponseFileForLibs =
169 this->CheckUseResponseFileForLibraries(linkLanguage);
171 // Expand the rule variables.
173 // Set path conversion for link script shells.
174 this->LocalGenerator->SetLinkScriptShell(useLinkScript);
176 std::unique_ptr<cmLinkLineComputer> linkLineComputer(
177 new cmLinkLineDeviceComputer(
178 this->LocalGenerator,
179 this->LocalGenerator->GetStateSnapshot().GetDirectory()));
180 linkLineComputer->SetForResponse(useResponseFileForLibs);
181 linkLineComputer->SetRelink(relink);
183 // Collect up flags to link in needed libraries.
184 std::string linkLibs;
185 this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
186 useResponseFileForLibs, depends);
188 // Construct object file lists that may be needed to expand the
190 std::string buildObjs;
191 this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
192 buildObjs, depends, false);
194 cmRulePlaceholderExpander::RuleVariables vars;
195 std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
197 objectDir = this->LocalGenerator->ConvertToOutputFormat(
198 this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
199 cmOutputConverter::SHELL);
201 std::string target = this->LocalGenerator->ConvertToOutputFormat(
202 this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput),
203 cmOutputConverter::SHELL);
205 std::string targetFullPathCompilePDB =
206 this->ComputeTargetCompilePDB(this->GetConfigName());
207 std::string targetOutPathCompilePDB =
208 this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
209 cmOutputConverter::SHELL);
211 vars.Language = linkLanguage.c_str();
212 vars.Objects = buildObjs.c_str();
213 vars.ObjectDir = objectDir.c_str();
214 vars.Target = target.c_str();
215 vars.LinkLibraries = linkLibs.c_str();
216 vars.LanguageCompileFlags = langFlags.c_str();
217 vars.LinkFlags = linkFlags.c_str();
218 vars.TargetCompilePDB = targetOutPathCompilePDB.c_str();
220 std::string launcher;
222 cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
224 if (cmNonempty(val)) {
225 launcher = cmStrCat(*val, ' ');
228 std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
229 this->LocalGenerator->CreateRulePlaceholderExpander());
231 // Expand placeholders in the commands.
232 rulePlaceholderExpander->SetTargetImpLib(targetOutput);
233 for (std::string& real_link_command : real_link_commands) {
234 real_link_command = cmStrCat(launcher, real_link_command);
235 rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
236 real_link_command, vars);
239 // Restore path conversion to normal shells.
240 this->LocalGenerator->SetLinkScriptShell(false);
243 // Optionally convert the build rule to use a script to avoid long
244 // command lines in the make shell.
246 // Use a link script.
247 const char* name = (relink ? "drelink.txt" : "dlink.txt");
248 this->CreateLinkScript(name, real_link_commands, commands1, depends);
250 // No link script. Just use the link rule directly.
251 commands1 = real_link_commands;
253 this->LocalGenerator->CreateCDCommand(
254 commands1, this->Makefile->GetCurrentBinaryDirectory(),
255 this->LocalGenerator->GetBinaryDirectory());
256 cm::append(commands, commands1);
259 // Write the build rule.
260 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
261 targetOutput, depends, commands, false);
263 // Clean all the possible executable names and symlinks.
264 this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
267 void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
269 std::vector<std::string> commands;
271 // Get the name of the executable to generate.
272 cmGeneratorTarget::Names targetNames =
273 this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
275 // Construct the full path version of the names.
276 std::string outpath =
277 this->GeneratorTarget->GetDirectory(this->GetConfigName());
278 if (this->GeneratorTarget->IsAppBundleOnApple()) {
279 this->OSXBundleGenerator->CreateAppBundle(targetNames.Output, outpath,
280 this->GetConfigName());
283 std::string outpathImp;
285 outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(),
286 "/CMakeFiles/CMakeRelink.dir");
287 cmSystemTools::MakeDirectory(outpath);
289 if (!targetNames.ImportLibrary.empty()) {
290 outpathImp = outpath;
293 cmSystemTools::MakeDirectory(outpath);
294 if (!targetNames.ImportLibrary.empty()) {
295 outpathImp = this->GeneratorTarget->GetDirectory(
296 this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
297 cmSystemTools::MakeDirectory(outpathImp);
302 std::string compilePdbOutputPath =
303 this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
304 cmSystemTools::MakeDirectory(compilePdbOutputPath);
306 std::string pdbOutputPath =
307 this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
308 cmSystemTools::MakeDirectory(pdbOutputPath);
309 pdbOutputPath += '/';
311 std::string targetFullPath = outpath + targetNames.Output;
312 std::string targetFullPathReal = outpath + targetNames.Real;
313 std::string targetFullPathPDB = pdbOutputPath + targetNames.PDB;
314 std::string targetFullPathImport = outpathImp + targetNames.ImportLibrary;
315 std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat(
316 targetFullPathPDB, cmOutputConverter::SHELL);
317 // Convert to the output path to use in constructing commands.
318 std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat(
319 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPath),
320 cmOutputConverter::SHELL);
321 std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat(
322 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
323 cmOutputConverter::SHELL);
324 std::string targetOutPathImport =
325 this->LocalGenerator->ConvertToOutputFormat(
326 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport),
327 cmOutputConverter::SHELL);
329 // Get the language to use for linking this executable.
330 std::string linkLanguage =
331 this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
333 // Make sure we have a link language.
334 if (linkLanguage.empty()) {
335 cmSystemTools::Error("Cannot determine link language for target \"" +
336 this->GeneratorTarget->GetName() + "\".");
340 // Build list of dependencies.
341 std::vector<std::string> depends;
342 this->AppendLinkDepends(depends, linkLanguage);
343 if (!this->DeviceLinkObject.empty()) {
344 depends.push_back(this->DeviceLinkObject);
347 this->NumberOfProgressActions++;
348 if (!this->NoRuleMessages) {
349 cmLocalUnixMakefileGenerator3::EchoProgress progress;
350 this->MakeEchoProgress(progress);
351 // Add the link message.
352 std::string buildEcho =
353 cmStrCat("Linking ", linkLanguage, " executable ", targetOutPath);
354 this->LocalGenerator->AppendEcho(
355 commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress);
358 // Build a list of compiler flags and linker flags.
360 std::string linkFlags;
362 // Add flags to create an executable.
363 this->LocalGenerator->AddConfigVariableFlags(
364 linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
366 if (this->GeneratorTarget->IsWin32Executable(
367 this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
368 this->LocalGenerator->AppendFlags(
370 this->Makefile->GetSafeDefinition(
371 cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE")));
373 this->LocalGenerator->AppendFlags(
375 this->Makefile->GetSafeDefinition(
376 cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE")));
379 // Add symbol export flags if necessary.
380 if (this->GeneratorTarget->IsExecutableWithExports()) {
381 std::string export_flag_var =
382 cmStrCat("CMAKE_EXE_EXPORTS_", linkLanguage, "_FLAG");
383 this->LocalGenerator->AppendFlags(
384 linkFlags, this->Makefile->GetSafeDefinition(export_flag_var));
387 this->LocalGenerator->AppendFlags(linkFlags,
388 this->LocalGenerator->GetLinkLibsCMP0065(
389 linkLanguage, *this->GeneratorTarget));
391 this->UseLWYU = this->LocalGenerator->AppendLWYUFlags(
392 linkFlags, this->GeneratorTarget, linkLanguage);
394 // Add language feature flags.
395 this->LocalGenerator->AddLanguageFlagsForLinking(
396 flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
398 this->LocalGenerator->AddArchitectureFlags(
399 flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
401 // Add target-specific linker flags.
402 this->GetTargetLinkFlags(linkFlags, linkLanguage);
405 std::unique_ptr<cmLinkLineComputer> linkLineComputer =
406 this->CreateLinkLineComputer(
407 this->LocalGenerator,
408 this->LocalGenerator->GetStateSnapshot().GetDirectory());
410 this->LocalGenerator->AppendModuleDefinitionFlag(
411 linkFlags, this->GeneratorTarget, linkLineComputer.get(),
412 this->GetConfigName());
415 this->LocalGenerator->AppendIPOLinkerFlags(
416 linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
418 // Construct a list of files associated with this executable that
419 // may need to be cleaned.
420 std::vector<std::string> exeCleanFiles;
421 exeCleanFiles.push_back(
422 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPath));
424 // There may be a manifest file for this target. Add it to the
425 // clean set just in case.
426 exeCleanFiles.push_back(this->LocalGenerator->MaybeRelativeToCurBinDir(
427 targetFullPath + ".manifest"));
429 if (this->TargetNames.Real != this->TargetNames.Output) {
430 exeCleanFiles.push_back(
431 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal));
433 if (!this->TargetNames.ImportLibrary.empty()) {
434 exeCleanFiles.push_back(
435 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport));
437 if (this->GeneratorTarget->GetImplibGNUtoMS(
438 this->GetConfigName(), targetFullPathImport, implib)) {
439 exeCleanFiles.push_back(
440 this->LocalGenerator->MaybeRelativeToCurBinDir(implib));
444 // List the PDB for cleaning only when the whole target is
445 // cleaned. We do not want to delete the .pdb file just before
446 // linking the target.
447 this->CleanFiles.insert(
448 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathPDB));
450 // Add the pre-build and pre-link rules building but not when relinking.
452 this->LocalGenerator->AppendCustomCommands(
453 commands, this->GeneratorTarget->GetPreBuildCommands(),
454 this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
455 this->LocalGenerator->AppendCustomCommands(
456 commands, this->GeneratorTarget->GetPreLinkCommands(),
457 this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
460 // Determine whether a link script will be used.
461 bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
463 // Construct the main link rule.
464 std::vector<std::string> real_link_commands;
465 std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable(
466 linkLanguage, this->GetConfigName());
467 std::string linkRule = this->GetLinkRule(linkRuleVar);
468 std::vector<std::string> commands1;
469 cmExpandList(linkRule, real_link_commands);
470 if (this->GeneratorTarget->IsExecutableWithExports()) {
471 // If a separate rule for creating an import library is specified
473 std::string implibRuleVar =
474 cmStrCat("CMAKE_", linkLanguage, "_CREATE_IMPORT_LIBRARY");
475 this->Makefile->GetDefExpandList(implibRuleVar, real_link_commands);
478 bool useResponseFileForObjects =
479 this->CheckUseResponseFileForObjects(linkLanguage);
480 bool const useResponseFileForLibs =
481 this->CheckUseResponseFileForLibraries(linkLanguage);
483 // Expand the rule variables.
485 bool useWatcomQuote =
486 this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
488 // Set path conversion for link script shells.
489 this->LocalGenerator->SetLinkScriptShell(useLinkScript);
491 std::unique_ptr<cmLinkLineComputer> linkLineComputer =
492 this->CreateLinkLineComputer(
493 this->LocalGenerator,
494 this->LocalGenerator->GetStateSnapshot().GetDirectory());
495 linkLineComputer->SetForResponse(useResponseFileForLibs);
496 linkLineComputer->SetUseWatcomQuote(useWatcomQuote);
497 linkLineComputer->SetRelink(relink);
499 // Collect up flags to link in needed libraries.
500 std::string linkLibs;
501 this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
502 useResponseFileForLibs, depends);
504 // Construct object file lists that may be needed to expand the
506 std::string buildObjs;
507 this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
508 buildObjs, depends, useWatcomQuote);
509 if (!this->DeviceLinkObject.empty()) {
511 this->LocalGenerator->ConvertToOutputFormat(
512 this->LocalGenerator->MaybeRelativeToCurBinDir(
513 this->DeviceLinkObject),
514 cmOutputConverter::SHELL);
517 // maybe create .def file from list of objects
518 this->GenDefFile(real_link_commands);
520 std::string manifests = this->GetManifests(this->GetConfigName());
522 std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
524 cmRulePlaceholderExpander::RuleVariables vars;
525 vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
527 cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str();
528 vars.Language = linkLanguage.c_str();
529 vars.AIXExports = aixExports.c_str();
530 vars.Objects = buildObjs.c_str();
531 std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
533 objectDir = this->LocalGenerator->ConvertToOutputFormat(
534 this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
535 cmOutputConverter::SHELL);
536 vars.ObjectDir = objectDir.c_str();
537 cmOutputConverter::OutputFormat output = (useWatcomQuote)
538 ? cmOutputConverter::WATCOMQUOTE
539 : cmOutputConverter::SHELL;
540 std::string target = this->LocalGenerator->ConvertToOutputFormat(
541 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal),
543 vars.Target = target.c_str();
544 vars.TargetPDB = targetOutPathPDB.c_str();
546 // Setup the target version.
547 std::string targetVersionMajor;
548 std::string targetVersionMinor;
550 std::ostringstream majorStream;
551 std::ostringstream minorStream;
554 this->GeneratorTarget->GetTargetVersion(major, minor);
555 majorStream << major;
556 minorStream << minor;
557 targetVersionMajor = majorStream.str();
558 targetVersionMinor = minorStream.str();
560 vars.TargetVersionMajor = targetVersionMajor.c_str();
561 vars.TargetVersionMinor = targetVersionMinor.c_str();
563 vars.LinkLibraries = linkLibs.c_str();
564 vars.Flags = flags.c_str();
565 vars.LinkFlags = linkFlags.c_str();
566 vars.Manifests = manifests.c_str();
568 std::string linkerLauncher =
569 this->GetLinkerLauncher(this->GetConfigName());
570 if (cmNonempty(linkerLauncher)) {
571 vars.Launcher = linkerLauncher.c_str();
576 this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
578 std::string cmakeCommand = cmStrCat(
579 this->LocalGenerator->ConvertToOutputFormat(
580 cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL),
581 " -E __run_co_compile --lwyu=");
582 cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck);
583 cmakeCommand += cmStrCat(" --source=", targetOutPathReal);
584 real_link_commands.push_back(std::move(cmakeCommand));
588 std::string launcher;
590 cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
592 if (cmNonempty(val)) {
593 launcher = cmStrCat(*val, ' ');
596 std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
597 this->LocalGenerator->CreateRulePlaceholderExpander());
599 // Expand placeholders in the commands.
600 rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport);
601 for (std::string& real_link_command : real_link_commands) {
602 real_link_command = cmStrCat(launcher, real_link_command);
603 rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator,
604 real_link_command, vars);
607 // Restore path conversion to normal shells.
608 this->LocalGenerator->SetLinkScriptShell(false);
611 // Optionally convert the build rule to use a script to avoid long
612 // command lines in the make shell.
614 // Use a link script.
615 const char* name = (relink ? "relink.txt" : "link.txt");
616 this->CreateLinkScript(name, real_link_commands, commands1, depends);
618 // No link script. Just use the link rule directly.
619 commands1 = real_link_commands;
621 this->LocalGenerator->CreateCDCommand(
622 commands1, this->Makefile->GetCurrentBinaryDirectory(),
623 this->LocalGenerator->GetBinaryDirectory());
624 cm::append(commands, commands1);
627 // Add a rule to create necessary symlinks for the library.
628 if (targetOutPath != targetOutPathReal) {
629 std::string symlink =
630 cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_executable ",
631 targetOutPathReal, ' ', targetOutPath);
632 commands1.push_back(std::move(symlink));
633 this->LocalGenerator->CreateCDCommand(
634 commands1, this->Makefile->GetCurrentBinaryDirectory(),
635 this->LocalGenerator->GetBinaryDirectory());
636 cm::append(commands, commands1);
640 // Add the post-build rules when building but not when relinking.
642 this->LocalGenerator->AppendCustomCommands(
643 commands, this->GeneratorTarget->GetPostBuildCommands(),
644 this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
647 // Write the build rule.
648 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
649 targetFullPathReal, depends, commands,
652 // The symlink name for the target should depend on the real target
653 // so if the target version changes it rebuilds and recreates the
655 if (targetFullPath != targetFullPathReal) {
658 depends.push_back(targetFullPathReal);
659 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
660 targetFullPath, depends, commands,
664 // Write the main driver rule to build everything in this target.
665 this->WriteTargetDriverRule(targetFullPath, relink);
667 // Clean all the possible executable names and symlinks.
668 this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());