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"
20 #include "cmLocalGenerator.h"
21 #include "cmLocalUnixMakefileGenerator3.h"
22 #include "cmMakefile.h"
23 #include "cmOSXBundleGenerator.h"
24 #include "cmOutputConverter.h"
25 #include "cmRulePlaceholderExpander.h"
27 #include "cmStateDirectory.h"
28 #include "cmStateSnapshot.h"
29 #include "cmStateTypes.h"
30 #include "cmStringAlgorithms.h"
31 #include "cmSystemTools.h"
34 cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator(
35 cmGeneratorTarget
* target
)
36 : cmMakefileTargetGenerator(target
)
38 this->CustomCommandDriver
= OnDepends
;
40 this->GeneratorTarget
->GetExecutableNames(this->GetConfigName());
42 this->OSXBundleGenerator
= cm::make_unique
<cmOSXBundleGenerator
>(target
);
43 this->OSXBundleGenerator
->SetMacContentFolders(&this->MacContentFolders
);
46 cmMakefileExecutableTargetGenerator::~cmMakefileExecutableTargetGenerator() =
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();
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();
83 this->CloseFileStreams();
86 void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
89 #ifndef CMAKE_BOOTSTRAP
90 const bool requiresDeviceLinking
= requireDeviceLinking(
91 *this->GeneratorTarget
, *this->LocalGenerator
, this->GetConfigName());
92 if (!requiresDeviceLinking
) {
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
);
122 this->WriteNvidiaDeviceExecutableRule(relink
, commands
, targetOutput
);
125 // Write the main driver rule to build everything in this target.
126 this->WriteTargetDriverRule(targetOutput
, relink
);
128 static_cast<void>(relink
);
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
194 std::string buildObjs
;
195 this->CreateObjectLists(
196 useLinkScript
, false, useResponseFileForObjects
, buildObjs
, depends
,
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.
253 // Use a link script.
254 const char* name
= (relink
? "drelink.txt" : "dlink.txt");
255 this->CreateLinkScript(name
, real_link_commands
, commands1
, depends
);
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
);
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());
290 std::string outpathImp
;
292 outpath
= cmStrCat(this->Makefile
->GetCurrentBinaryDirectory(),
293 "/CMakeFiles/CMakeRelink.dir");
294 cmSystemTools::MakeDirectory(outpath
);
296 if (!targetNames
.ImportLibrary
.empty()) {
297 outpathImp
= outpath
;
300 cmSystemTools::MakeDirectory(outpath
);
301 if (!targetNames
.ImportLibrary
.empty()) {
302 outpathImp
= this->GeneratorTarget
->GetDirectory(
303 this->GetConfigName(), cmStateEnums::ImportLibraryArtifact
);
304 cmSystemTools::MakeDirectory(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() + "\".");
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.
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(
379 this->Makefile
->GetSafeDefinition(
380 cmStrCat("CMAKE_", linkLanguage
, "_CREATE_WIN32_EXE")));
382 this->LocalGenerator
->AppendFlags(
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
));
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"));
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
));
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.
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
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
515 std::string buildObjs
;
516 this->CreateObjectLists(useLinkScript
, false, useResponseFileForObjects
,
517 buildObjs
, depends
, useWatcomQuote
, linkLanguage
);
518 if (!this->DeviceLinkObject
.empty()) {
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();
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
;
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();
583 this->Makefile
->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK");
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.
622 // Use a link script.
623 const char* name
= (relink
? "relink.txt" : "link.txt");
624 this->CreateLinkScript(name
, real_link_commands
, commands1
, depends
);
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
);
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
);
648 // Add the post-build rules when building but not when relinking.
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
,
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
663 if (targetFullPath
!= targetFullPathReal
) {
666 depends
.push_back(targetFullPathReal
);
667 this->LocalGenerator
->WriteMakeRule(*this->BuildFileStream
, nullptr,
668 targetFullPath
, depends
, commands
,
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());