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