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 // Add language feature flags.
140 std::string langFlags;
141 this->LocalGenerator->AddLanguageFlagsForLinking(
142 langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
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));
150 // Determine whether a link script will be used.
151 bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
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);
160 bool useResponseFileForObjects =
161 this->CheckUseResponseFileForObjects(linkLanguage);
162 bool const useResponseFileForLibs =
163 this->CheckUseResponseFileForLibraries(linkLanguage);
165 // Expand the rule variables.
167 // Set path conversion for link script shells.
168 this->LocalGenerator->SetLinkScriptShell(useLinkScript);
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);
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);
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);
190 // Construct object file lists that may be needed to expand the
192 std::string buildObjs;
193 this->CreateObjectLists(
194 useLinkScript, false, useResponseFileForObjects, buildObjs, depends,
195 false, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink);
197 cmRulePlaceholderExpander::RuleVariables vars;
198 std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
200 objectDir = this->LocalGenerator->ConvertToOutputFormat(
201 this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir),
202 cmOutputConverter::SHELL);
204 std::string target = this->LocalGenerator->ConvertToOutputFormat(
205 this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput),
206 cmOutputConverter::SHELL);
208 std::string targetFullPathCompilePDB =
209 this->ComputeTargetCompilePDB(this->GetConfigName());
210 std::string targetOutPathCompilePDB =
211 this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB,
212 cmOutputConverter::SHELL);
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();
223 std::string launcher;
225 cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
227 if (cmNonempty(val)) {
228 launcher = cmStrCat(*val, ' ');
231 std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
232 this->LocalGenerator->CreateRulePlaceholderExpander());
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);
242 // Restore path conversion to normal shells.
243 this->LocalGenerator->SetLinkScriptShell(false);
246 // Optionally convert the build rule to use a script to avoid long
247 // command lines in the make shell.
249 // Use a link script.
250 const char* name = (relink ? "drelink.txt" : "dlink.txt");
251 this->CreateLinkScript(name, real_link_commands, commands1, depends);
253 // No link script. Just use the link rule directly.
254 commands1 = real_link_commands;
256 this->LocalGenerator->CreateCDCommand(
257 commands1, this->Makefile->GetCurrentBinaryDirectory(),
258 this->LocalGenerator->GetBinaryDirectory());
259 cm::append(commands, commands1);
262 // Write the build rule.
263 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
264 targetOutput, depends, commands, false);
266 // Clean all the possible executable names and symlinks.
267 this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());
270 void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
272 std::vector<std::string> commands;
274 // Get the name of the executable to generate.
275 cmGeneratorTarget::Names targetNames =
276 this->GeneratorTarget->GetExecutableNames(this->GetConfigName());
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());
286 std::string outpathImp;
288 outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(),
289 "/CMakeFiles/CMakeRelink.dir");
290 cmSystemTools::MakeDirectory(outpath);
292 if (!targetNames.ImportLibrary.empty()) {
293 outpathImp = outpath;
296 cmSystemTools::MakeDirectory(outpath);
297 if (!targetNames.ImportLibrary.empty()) {
298 outpathImp = this->GeneratorTarget->GetDirectory(
299 this->GetConfigName(), cmStateEnums::ImportLibraryArtifact);
300 cmSystemTools::MakeDirectory(outpathImp);
305 std::string compilePdbOutputPath =
306 this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName());
307 cmSystemTools::MakeDirectory(compilePdbOutputPath);
309 std::string pdbOutputPath =
310 this->GeneratorTarget->GetPDBDirectory(this->GetConfigName());
311 cmSystemTools::MakeDirectory(pdbOutputPath);
312 pdbOutputPath += '/';
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);
332 // Get the language to use for linking this executable.
333 std::string linkLanguage =
334 this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName());
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() + "\".");
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);
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);
361 // Build a list of compiler flags and linker flags.
363 std::string linkFlags;
365 // Add flags to create an executable.
366 this->LocalGenerator->AddConfigVariableFlags(
367 linkFlags, "CMAKE_EXE_LINKER_FLAGS", this->GetConfigName());
369 if (this->GeneratorTarget->IsWin32Executable(
370 this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"))) {
371 this->LocalGenerator->AppendFlags(
373 this->Makefile->GetSafeDefinition(
374 cmStrCat("CMAKE_", linkLanguage, "_CREATE_WIN32_EXE")));
376 this->LocalGenerator->AppendFlags(
378 this->Makefile->GetSafeDefinition(
379 cmStrCat("CMAKE_", linkLanguage, "_CREATE_CONSOLE_EXE")));
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));
390 this->LocalGenerator->AppendFlags(linkFlags,
391 this->LocalGenerator->GetLinkLibsCMP0065(
392 linkLanguage, *this->GeneratorTarget));
394 this->UseLWYU = this->LocalGenerator->AppendLWYUFlags(
395 linkFlags, this->GeneratorTarget, linkLanguage);
397 // Add language feature flags.
398 this->LocalGenerator->AddLanguageFlagsForLinking(
399 flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
401 this->LocalGenerator->AddArchitectureFlags(
402 flags, this->GeneratorTarget, linkLanguage, this->GetConfigName());
404 // Add target-specific linker flags.
405 this->GetTargetLinkFlags(linkFlags, linkLanguage);
408 std::unique_ptr<cmLinkLineComputer> linkLineComputer =
409 this->CreateLinkLineComputer(
410 this->LocalGenerator,
411 this->LocalGenerator->GetStateSnapshot().GetDirectory());
413 this->LocalGenerator->AppendModuleDefinitionFlag(
414 linkFlags, this->GeneratorTarget, linkLineComputer.get(),
415 this->GetConfigName());
418 this->LocalGenerator->AppendIPOLinkerFlags(
419 linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage);
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));
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"));
432 if (this->TargetNames.Real != this->TargetNames.Output) {
433 exeCleanFiles.push_back(
434 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal));
436 if (!this->TargetNames.ImportLibrary.empty()) {
437 exeCleanFiles.push_back(
438 this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport));
440 if (this->GeneratorTarget->GetImplibGNUtoMS(
441 this->GetConfigName(), targetFullPathImport, implib)) {
442 exeCleanFiles.push_back(
443 this->LocalGenerator->MaybeRelativeToCurBinDir(implib));
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));
453 // Add the pre-build and pre-link rules building but not when relinking.
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());
463 // Determine whether a link script will be used.
464 bool useLinkScript = this->GlobalGenerator->GetUseLinkScript();
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
476 std::string implibRuleVar =
477 cmStrCat("CMAKE_", linkLanguage, "_CREATE_IMPORT_LIBRARY");
478 this->Makefile->GetDefExpandList(implibRuleVar, real_link_commands);
481 bool useResponseFileForObjects =
482 this->CheckUseResponseFileForObjects(linkLanguage);
483 bool const useResponseFileForLibs =
484 this->CheckUseResponseFileForLibraries(linkLanguage);
486 // Expand the rule variables.
488 bool useWatcomQuote =
489 this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE");
491 // Set path conversion for link script shells.
492 this->LocalGenerator->SetLinkScriptShell(useLinkScript);
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);
502 // Collect up flags to link in needed libraries.
503 std::string linkLibs;
504 this->CreateLinkLibs(linkLineComputer.get(), linkLibs,
505 useResponseFileForLibs, depends);
507 // Construct object file lists that may be needed to expand the
509 std::string buildObjs;
510 this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
511 buildObjs, depends, useWatcomQuote);
512 if (!this->DeviceLinkObject.empty()) {
514 this->LocalGenerator->ConvertToOutputFormat(
515 this->LocalGenerator->MaybeRelativeToCurBinDir(
516 this->DeviceLinkObject),
517 cmOutputConverter::SHELL);
520 // maybe create .def file from list of objects
521 this->GenDefFile(real_link_commands);
523 std::string manifests = this->GetManifests(this->GetConfigName());
525 std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
527 cmRulePlaceholderExpander::RuleVariables vars;
528 vars.CMTargetName = this->GeneratorTarget->GetName().c_str();
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();
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),
546 vars.Target = target.c_str();
547 vars.TargetPDB = targetOutPathPDB.c_str();
549 // Setup the target version.
550 std::string targetVersionMajor;
551 std::string targetVersionMinor;
553 std::ostringstream majorStream;
554 std::ostringstream minorStream;
557 this->GeneratorTarget->GetTargetVersion(major, minor);
558 majorStream << major;
559 minorStream << minor;
560 targetVersionMajor = majorStream.str();
561 targetVersionMinor = minorStream.str();
563 vars.TargetVersionMajor = targetVersionMajor.c_str();
564 vars.TargetVersionMinor = targetVersionMinor.c_str();
566 vars.LinkLibraries = linkLibs.c_str();
567 vars.Flags = flags.c_str();
568 vars.LinkFlags = linkFlags.c_str();
569 vars.Manifests = manifests.c_str();
571 std::string linkerLauncher =
572 this->GetLinkerLauncher(this->GetConfigName());
573 if (cmNonempty(linkerLauncher)) {
574 vars.Launcher = linkerLauncher.c_str();
579 this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
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));
591 std::string launcher;
593 cmValue val = this->LocalGenerator->GetRuleLauncher(this->GeneratorTarget,
595 if (cmNonempty(val)) {
596 launcher = cmStrCat(*val, ' ');
599 std::unique_ptr<cmRulePlaceholderExpander> rulePlaceholderExpander(
600 this->LocalGenerator->CreateRulePlaceholderExpander());
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);
610 // Restore path conversion to normal shells.
611 this->LocalGenerator->SetLinkScriptShell(false);
614 // Optionally convert the build rule to use a script to avoid long
615 // command lines in the make shell.
617 // Use a link script.
618 const char* name = (relink ? "relink.txt" : "link.txt");
619 this->CreateLinkScript(name, real_link_commands, commands1, depends);
621 // No link script. Just use the link rule directly.
622 commands1 = real_link_commands;
624 this->LocalGenerator->CreateCDCommand(
625 commands1, this->Makefile->GetCurrentBinaryDirectory(),
626 this->LocalGenerator->GetBinaryDirectory());
627 cm::append(commands, commands1);
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);
643 // Add the post-build rules when building but not when relinking.
645 this->LocalGenerator->AppendCustomCommands(
646 commands, this->GeneratorTarget->GetPostBuildCommands(),
647 this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory());
650 // Write the build rule.
651 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
652 targetFullPathReal, depends, commands,
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
658 if (targetFullPath != targetFullPathReal) {
661 depends.push_back(targetFullPathReal);
662 this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr,
663 targetFullPath, depends, commands,
667 // Write the main driver rule to build everything in this target.
668 this->WriteTargetDriverRule(targetFullPath, relink);
670 // Clean all the possible executable names and symlinks.
671 this->CleanFiles.insert(exeCleanFiles.begin(), exeCleanFiles.end());