/src/CMake/Source/cmMakefileLibraryTargetGenerator.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | #include "cmMakefileLibraryTargetGenerator.h" |
4 | | |
5 | | #include <cstddef> |
6 | | #include <set> |
7 | | #include <sstream> |
8 | | #include <utility> |
9 | | #include <vector> |
10 | | |
11 | | #include <cm/memory> |
12 | | #include <cmext/algorithm> |
13 | | |
14 | | #include "cmGeneratedFileStream.h" |
15 | | #include "cmGeneratorOptions.h" |
16 | | #include "cmGeneratorTarget.h" |
17 | | #include "cmGlobalUnixMakefileGenerator3.h" |
18 | | #include "cmLinkLineComputer.h" |
19 | | #include "cmLinkLineDeviceComputer.h" |
20 | | #include "cmList.h" |
21 | | #include "cmLocalGenerator.h" |
22 | | #include "cmLocalUnixMakefileGenerator3.h" |
23 | | #include "cmMakefile.h" |
24 | | #include "cmOSXBundleGenerator.h" |
25 | | #include "cmOutputConverter.h" |
26 | | #include "cmRulePlaceholderExpander.h" |
27 | | #include "cmState.h" |
28 | | #include "cmStateDirectory.h" |
29 | | #include "cmStateSnapshot.h" |
30 | | #include "cmStateTypes.h" |
31 | | #include "cmStringAlgorithms.h" |
32 | | #include "cmSystemTools.h" |
33 | | #include "cmValue.h" |
34 | | |
35 | | cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator( |
36 | | cmGeneratorTarget* target) |
37 | 0 | : cmMakefileTargetGenerator(target) |
38 | 0 | { |
39 | 0 | this->CustomCommandDriver = OnDepends; |
40 | 0 | if (this->GeneratorTarget->GetType() != cmStateEnums::INTERFACE_LIBRARY) { |
41 | 0 | this->TargetNames = |
42 | 0 | this->GeneratorTarget->GetLibraryNames(this->GetConfigName()); |
43 | 0 | } |
44 | |
|
45 | 0 | this->OSXBundleGenerator = cm::make_unique<cmOSXBundleGenerator>(target); |
46 | 0 | this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders); |
47 | 0 | } |
48 | | |
49 | 0 | cmMakefileLibraryTargetGenerator::~cmMakefileLibraryTargetGenerator() = |
50 | | default; |
51 | | |
52 | | void cmMakefileLibraryTargetGenerator::WriteRuleFiles() |
53 | 0 | { |
54 | | // create the build.make file and directory, put in the common blocks |
55 | 0 | this->CreateRuleFile(); |
56 | | |
57 | | // write rules used to help build object files |
58 | 0 | this->WriteCommonCodeRules(); |
59 | | |
60 | | // write the per-target per-language flags |
61 | 0 | this->WriteTargetLanguageFlags(); |
62 | | |
63 | | // write in rules for object files and custom commands |
64 | 0 | this->WriteTargetBuildRules(); |
65 | | |
66 | | // Write in the rules for the link dependency file |
67 | 0 | this->WriteTargetLinkDependRules(); |
68 | | |
69 | | // write the link rules |
70 | | // Write the rule for this target type. |
71 | 0 | switch (this->GeneratorTarget->GetType()) { |
72 | 0 | case cmStateEnums::STATIC_LIBRARY: |
73 | 0 | this->WriteStaticLibraryRules(); |
74 | 0 | break; |
75 | 0 | case cmStateEnums::SHARED_LIBRARY: |
76 | 0 | this->WriteSharedLibraryRules(false); |
77 | 0 | if (this->GeneratorTarget->NeedRelinkBeforeInstall( |
78 | 0 | this->GetConfigName())) { |
79 | | // Write rules to link an installable version of the target. |
80 | 0 | this->WriteSharedLibraryRules(true); |
81 | 0 | } |
82 | 0 | break; |
83 | 0 | case cmStateEnums::MODULE_LIBRARY: |
84 | 0 | this->WriteModuleLibraryRules(false); |
85 | 0 | if (this->GeneratorTarget->NeedRelinkBeforeInstall( |
86 | 0 | this->GetConfigName())) { |
87 | | // Write rules to link an installable version of the target. |
88 | 0 | this->WriteModuleLibraryRules(true); |
89 | 0 | } |
90 | 0 | break; |
91 | 0 | case cmStateEnums::OBJECT_LIBRARY: |
92 | 0 | this->WriteObjectLibraryRules(); |
93 | 0 | break; |
94 | 0 | default: |
95 | | // If language is not known, this is an error. |
96 | 0 | cmSystemTools::Error("Unknown Library Type"); |
97 | 0 | break; |
98 | 0 | } |
99 | | |
100 | | // Write clean target |
101 | 0 | this->WriteTargetCleanRules(); |
102 | | |
103 | | // Write the dependency generation rule. This must be done last so |
104 | | // that multiple output pair information is available. |
105 | 0 | this->WriteTargetDependRules(); |
106 | | |
107 | | // close the streams |
108 | 0 | this->CloseFileStreams(); |
109 | 0 | } |
110 | | |
111 | | void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules() |
112 | 0 | { |
113 | 0 | std::vector<std::string> commands; |
114 | 0 | std::vector<std::string> depends; |
115 | | |
116 | | // Add post-build rules. |
117 | 0 | this->LocalGenerator->AppendCustomCommands( |
118 | 0 | commands, this->GeneratorTarget->GetPostBuildCommands(), |
119 | 0 | this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); |
120 | | |
121 | | // Depend on the object files. |
122 | 0 | this->AppendObjectDepends(depends); |
123 | | |
124 | | // Write the rule. |
125 | 0 | this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, nullptr, |
126 | 0 | this->GeneratorTarget->GetName(), |
127 | 0 | depends, commands, true); |
128 | | |
129 | | // Write the main driver rule to build everything in this target. |
130 | 0 | this->WriteTargetDriverRule(this->GeneratorTarget->GetName(), false); |
131 | 0 | } |
132 | | |
133 | | void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() |
134 | 0 | { |
135 | 0 | bool const requiresDeviceLinking = requireDeviceLinking( |
136 | 0 | *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); |
137 | 0 | if (requiresDeviceLinking) { |
138 | 0 | this->WriteDeviceLibraryRules("CMAKE_CUDA_DEVICE_LINK_LIBRARY", false); |
139 | 0 | } |
140 | |
|
141 | 0 | std::string linkLanguage = |
142 | 0 | this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); |
143 | |
|
144 | 0 | std::string linkRuleVar = this->GeneratorTarget->GetCreateRuleVariable( |
145 | 0 | linkLanguage, this->GetConfigName()); |
146 | |
|
147 | 0 | std::string extraFlags; |
148 | 0 | this->LocalGenerator->GetStaticLibraryFlags( |
149 | 0 | extraFlags, this->GetConfigName(), linkLanguage, this->GeneratorTarget); |
150 | 0 | this->WriteLibraryRules(linkRuleVar, extraFlags, false); |
151 | 0 | } |
152 | | |
153 | | void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink) |
154 | 0 | { |
155 | 0 | if (this->GeneratorTarget->IsFrameworkOnApple()) { |
156 | 0 | this->WriteFrameworkRules(relink); |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | 0 | if (!relink) { |
161 | 0 | bool const requiresDeviceLinking = requireDeviceLinking( |
162 | 0 | *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); |
163 | 0 | if (requiresDeviceLinking) { |
164 | 0 | this->WriteDeviceLibraryRules("CMAKE_CUDA_DEVICE_LINK_LIBRARY", relink); |
165 | 0 | } |
166 | 0 | } |
167 | |
|
168 | 0 | std::string linkLanguage = |
169 | 0 | this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); |
170 | 0 | std::string linkRuleVar = |
171 | 0 | cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY"); |
172 | |
|
173 | 0 | if (this->GeneratorTarget->IsArchivedAIXSharedLibrary()) { |
174 | 0 | linkRuleVar = |
175 | 0 | cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_LIBRARY_ARCHIVE"); |
176 | 0 | } |
177 | |
|
178 | 0 | std::string extraFlags; |
179 | 0 | this->LocalGenerator->AppendTargetCreationLinkFlags( |
180 | 0 | extraFlags, this->GeneratorTarget, linkLanguage); |
181 | 0 | this->LocalGenerator->AddTargetTypeLinkerFlags( |
182 | 0 | extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
183 | 0 | this->LocalGenerator->AddPerLanguageLinkFlags( |
184 | 0 | extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
185 | |
|
186 | 0 | std::unique_ptr<cmLinkLineComputer> linkLineComputer = |
187 | 0 | this->CreateLinkLineComputer( |
188 | 0 | this->LocalGenerator, |
189 | 0 | this->LocalGenerator->GetStateSnapshot().GetDirectory()); |
190 | |
|
191 | 0 | this->LocalGenerator->AppendModuleDefinitionFlag( |
192 | 0 | extraFlags, this->GeneratorTarget, linkLineComputer.get(), |
193 | 0 | this->GetConfigName(), linkLanguage); |
194 | |
|
195 | 0 | this->UseLWYU = this->LocalGenerator->AppendLWYUFlags( |
196 | 0 | extraFlags, this->GeneratorTarget, linkLanguage); |
197 | |
|
198 | 0 | this->GetTargetLinkFlags(extraFlags, linkLanguage); |
199 | |
|
200 | 0 | this->WriteLibraryRules(linkRuleVar, extraFlags, relink); |
201 | 0 | } |
202 | | |
203 | | void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink) |
204 | 0 | { |
205 | 0 | if (!relink) { |
206 | 0 | bool const requiresDeviceLinking = requireDeviceLinking( |
207 | 0 | *this->GeneratorTarget, *this->LocalGenerator, this->GetConfigName()); |
208 | 0 | if (requiresDeviceLinking) { |
209 | 0 | this->WriteDeviceLibraryRules("CMAKE_CUDA_DEVICE_LINK_LIBRARY", relink); |
210 | 0 | } |
211 | 0 | } |
212 | |
|
213 | 0 | std::string linkLanguage = |
214 | 0 | this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); |
215 | 0 | std::string linkRuleVar = |
216 | 0 | cmStrCat("CMAKE_", linkLanguage, "_CREATE_SHARED_MODULE"); |
217 | |
|
218 | 0 | std::string extraFlags; |
219 | 0 | this->LocalGenerator->AppendTargetCreationLinkFlags( |
220 | 0 | extraFlags, this->GeneratorTarget, linkLanguage); |
221 | 0 | this->LocalGenerator->AddTargetTypeLinkerFlags( |
222 | 0 | extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
223 | 0 | this->LocalGenerator->AddPerLanguageLinkFlags( |
224 | 0 | extraFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
225 | |
|
226 | 0 | std::unique_ptr<cmLinkLineComputer> linkLineComputer = |
227 | 0 | this->CreateLinkLineComputer( |
228 | 0 | this->LocalGenerator, |
229 | 0 | this->LocalGenerator->GetStateSnapshot().GetDirectory()); |
230 | |
|
231 | 0 | this->LocalGenerator->AppendModuleDefinitionFlag( |
232 | 0 | extraFlags, this->GeneratorTarget, linkLineComputer.get(), |
233 | 0 | this->GetConfigName(), linkLanguage); |
234 | |
|
235 | 0 | this->UseLWYU = this->LocalGenerator->AppendLWYUFlags( |
236 | 0 | extraFlags, this->GeneratorTarget, linkLanguage); |
237 | |
|
238 | 0 | this->GetTargetLinkFlags(extraFlags, linkLanguage); |
239 | |
|
240 | 0 | this->WriteLibraryRules(linkRuleVar, extraFlags, relink); |
241 | 0 | } |
242 | | |
243 | | void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink) |
244 | 0 | { |
245 | 0 | std::string linkLanguage = |
246 | 0 | this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); |
247 | 0 | std::string linkRuleVar = |
248 | 0 | cmStrCat("CMAKE_", linkLanguage, "_CREATE_MACOSX_FRAMEWORK"); |
249 | |
|
250 | 0 | std::string extraFlags; |
251 | 0 | this->LocalGenerator->AppendTargetCreationLinkFlags( |
252 | 0 | extraFlags, this->GeneratorTarget, linkLanguage); |
253 | 0 | this->LocalGenerator->AddConfigVariableFlags( |
254 | 0 | extraFlags, "CMAKE_MACOSX_FRAMEWORK_LINKER_FLAGS", this->GeneratorTarget, |
255 | 0 | cmBuildStep::Link, linkLanguage, this->GetConfigName()); |
256 | 0 | this->GetTargetLinkFlags(extraFlags, linkLanguage); |
257 | |
|
258 | 0 | this->WriteLibraryRules(linkRuleVar, extraFlags, relink); |
259 | 0 | } |
260 | | |
261 | | void cmMakefileLibraryTargetGenerator::WriteDeviceLibraryRules( |
262 | | std::string const& linkRuleVar, bool relink) |
263 | 0 | { |
264 | 0 | #ifndef CMAKE_BOOTSTRAP |
265 | | // TODO: Merge the methods that call this method to avoid |
266 | | // code duplication. |
267 | 0 | std::vector<std::string> commands; |
268 | 0 | std::string const objExt = |
269 | 0 | this->Makefile->GetSafeDefinition("CMAKE_CUDA_OUTPUT_EXTENSION"); |
270 | | |
271 | | // Get the name of the device object to generate. |
272 | 0 | std::string const targetOutput = |
273 | 0 | this->GeneratorTarget->ObjectDirectory + "cmake_device_link" + objExt; |
274 | 0 | this->DeviceLinkObject = targetOutput; |
275 | |
|
276 | 0 | this->NumberOfProgressActions++; |
277 | 0 | if (!this->NoRuleMessages) { |
278 | 0 | cmLocalUnixMakefileGenerator3::EchoProgress progress; |
279 | 0 | this->MakeEchoProgress(progress); |
280 | | // Add the link message. |
281 | 0 | std::string buildEcho = cmStrCat( |
282 | 0 | "Linking CUDA device code ", |
283 | 0 | this->LocalGenerator->ConvertToOutputFormat( |
284 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(this->DeviceLinkObject), |
285 | 0 | cmOutputConverter::SHELL)); |
286 | 0 | this->LocalGenerator->AppendEcho( |
287 | 0 | commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress); |
288 | 0 | } |
289 | |
|
290 | 0 | if (this->Makefile->GetSafeDefinition("CMAKE_CUDA_COMPILER_ID") == "Clang") { |
291 | 0 | this->WriteDeviceLinkRule(commands, targetOutput); |
292 | 0 | } else { |
293 | 0 | this->WriteNvidiaDeviceLibraryRules(linkRuleVar, relink, commands, |
294 | 0 | targetOutput); |
295 | 0 | } |
296 | | |
297 | | // Write the main driver rule to build everything in this target. |
298 | 0 | this->WriteTargetDriverRule(targetOutput, relink); |
299 | 0 | } |
300 | | |
301 | | void cmMakefileLibraryTargetGenerator::WriteNvidiaDeviceLibraryRules( |
302 | | std::string const& linkRuleVar, bool relink, |
303 | | std::vector<std::string>& commands, std::string const& targetOutput) |
304 | 0 | { |
305 | 0 | std::string linkLanguage = "CUDA"; |
306 | | |
307 | | // Build list of dependencies. |
308 | 0 | std::vector<std::string> depends; |
309 | 0 | this->AppendLinkDepends(depends, linkLanguage); |
310 | | |
311 | | // Add language-specific flags. |
312 | 0 | std::string langFlags; |
313 | 0 | this->LocalGenerator->AddLanguageFlagsForLinking( |
314 | 0 | langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
315 | | |
316 | | // Clean files associated with this library. |
317 | 0 | std::set<std::string> libCleanFiles; |
318 | 0 | libCleanFiles.insert( |
319 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput)); |
320 | | |
321 | | // Determine whether a link script will be used. |
322 | 0 | bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); |
323 | |
|
324 | 0 | bool useResponseFileForObjects = |
325 | 0 | this->CheckUseResponseFileForObjects(linkLanguage); |
326 | 0 | bool const useResponseFileForLibs = |
327 | 0 | this->CheckUseResponseFileForLibraries(linkLanguage); |
328 | |
|
329 | 0 | cmRulePlaceholderExpander::RuleVariables vars; |
330 | 0 | vars.Language = linkLanguage.c_str(); |
331 | | |
332 | | // Expand the rule variables. |
333 | 0 | cmList real_link_commands; |
334 | 0 | { |
335 | | // Set path conversion for link script shells. |
336 | 0 | this->LocalGenerator->SetLinkScriptShell(useLinkScript); |
337 | | |
338 | | // Collect up flags to link in needed libraries. |
339 | 0 | std::string linkLibs; |
340 | 0 | std::unique_ptr<cmLinkLineDeviceComputer> linkLineComputer( |
341 | 0 | new cmLinkLineDeviceComputer( |
342 | 0 | this->LocalGenerator, |
343 | 0 | this->LocalGenerator->GetStateSnapshot().GetDirectory())); |
344 | 0 | linkLineComputer->SetForResponse(useResponseFileForLibs); |
345 | 0 | linkLineComputer->SetRelink(relink); |
346 | | |
347 | | // Create set of linking flags. |
348 | 0 | std::string linkFlags; |
349 | 0 | std::string ignored_; |
350 | 0 | this->LocalGenerator->GetDeviceLinkFlags( |
351 | 0 | *linkLineComputer, this->GetConfigName(), ignored_, linkFlags, ignored_, |
352 | 0 | ignored_, this->GeneratorTarget); |
353 | |
|
354 | 0 | this->CreateLinkLibs( |
355 | 0 | linkLineComputer.get(), linkLibs, useResponseFileForLibs, depends, |
356 | 0 | linkLanguage, cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); |
357 | | |
358 | | // Construct object file lists that may be needed to expand the |
359 | | // rule. |
360 | 0 | std::string buildObjs; |
361 | 0 | this->CreateObjectLists( |
362 | 0 | useLinkScript, false, // useArchiveRules |
363 | 0 | useResponseFileForObjects, buildObjs, depends, false, linkLanguage, |
364 | 0 | cmMakefileTargetGenerator::ResponseFlagFor::DeviceLink); |
365 | |
|
366 | 0 | std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); |
367 | 0 | objectDir = this->LocalGenerator->ConvertToOutputFormat( |
368 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir), |
369 | 0 | cmOutputConverter::SHELL); |
370 | |
|
371 | 0 | std::string targetSupportDir = |
372 | 0 | this->GeneratorTarget->GetCMFSupportDirectory(); |
373 | 0 | targetSupportDir = this->LocalGenerator->ConvertToOutputFormat( |
374 | 0 | this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir), |
375 | 0 | cmOutputConverter::SHELL); |
376 | |
|
377 | 0 | std::string target = this->LocalGenerator->ConvertToOutputFormat( |
378 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetOutput), |
379 | 0 | cmOutputConverter::SHELL); |
380 | |
|
381 | 0 | std::string targetFullPathCompilePDB = |
382 | 0 | this->ComputeTargetCompilePDB(this->GetConfigName()); |
383 | 0 | std::string targetOutPathCompilePDB = |
384 | 0 | this->LocalGenerator->ConvertToOutputFormat(targetFullPathCompilePDB, |
385 | 0 | cmOutputConverter::SHELL); |
386 | |
|
387 | 0 | vars.Objects = buildObjs.c_str(); |
388 | 0 | vars.ObjectDir = objectDir.c_str(); |
389 | 0 | vars.TargetSupportDir = targetSupportDir.c_str(); |
390 | 0 | vars.Target = target.c_str(); |
391 | 0 | vars.LinkLibraries = linkLibs.c_str(); |
392 | 0 | vars.ObjectsQuoted = buildObjs.c_str(); |
393 | 0 | vars.LanguageCompileFlags = langFlags.c_str(); |
394 | 0 | vars.LinkFlags = linkFlags.c_str(); |
395 | 0 | vars.TargetCompilePDB = targetOutPathCompilePDB.c_str(); |
396 | |
|
397 | 0 | std::string launcher; |
398 | 0 | std::string val = this->LocalGenerator->GetRuleLauncher( |
399 | 0 | this->GeneratorTarget, "RULE_LAUNCH_LINK", |
400 | 0 | this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); |
401 | 0 | if (cmNonempty(val)) { |
402 | 0 | launcher = cmStrCat(val, ' '); |
403 | 0 | } |
404 | |
|
405 | 0 | auto rulePlaceholderExpander = |
406 | 0 | this->LocalGenerator->CreateRulePlaceholderExpander(cmBuildStep::Link); |
407 | | |
408 | | // Construct the main link rule and expand placeholders. |
409 | 0 | rulePlaceholderExpander->SetTargetImpLib(targetOutput); |
410 | 0 | std::string linkRule = this->GetLinkRule(linkRuleVar); |
411 | 0 | real_link_commands.append(linkRule); |
412 | | |
413 | | // Expand placeholders. |
414 | 0 | for (auto& real_link_command : real_link_commands) { |
415 | 0 | real_link_command = cmStrCat(launcher, real_link_command); |
416 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, |
417 | 0 | real_link_command, vars); |
418 | 0 | } |
419 | | // Restore path conversion to normal shells. |
420 | 0 | this->LocalGenerator->SetLinkScriptShell(false); |
421 | | |
422 | | // Clean all the possible library names and symlinks. |
423 | 0 | this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end()); |
424 | 0 | } |
425 | |
|
426 | 0 | std::vector<std::string> commands1; |
427 | | // Optionally convert the build rule to use a script to avoid long |
428 | | // command lines in the make shell. |
429 | 0 | if (useLinkScript) { |
430 | | // Use a link script. |
431 | 0 | char const* name = (relink ? "drelink.txt" : "dlink.txt"); |
432 | 0 | this->CreateLinkScript(name, real_link_commands, commands1, depends); |
433 | 0 | } else { |
434 | | // No link script. Just use the link rule directly. |
435 | 0 | commands1 = real_link_commands; |
436 | 0 | } |
437 | 0 | this->LocalGenerator->CreateCDCommand( |
438 | 0 | commands1, this->Makefile->GetCurrentBinaryDirectory(), |
439 | 0 | this->LocalGenerator->GetBinaryDirectory()); |
440 | 0 | cm::append(commands, commands1); |
441 | 0 | commands1.clear(); |
442 | | |
443 | | // Compute the list of outputs. |
444 | 0 | std::vector<std::string> outputs(1, targetOutput); |
445 | | |
446 | | // Write the build rule. |
447 | 0 | this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, |
448 | 0 | commands, false); |
449 | | #else |
450 | | static_cast<void>(linkRuleVar); |
451 | | static_cast<void>(relink); |
452 | | #endif |
453 | 0 | } |
454 | | |
455 | | void cmMakefileLibraryTargetGenerator::WriteLibraryRules( |
456 | | std::string const& linkRuleVar, std::string const& extraFlags, bool relink) |
457 | 0 | { |
458 | | // TODO: Merge the methods that call this method to avoid |
459 | | // code duplication. |
460 | 0 | std::vector<std::string> commands; |
461 | | |
462 | | // Get the language to use for linking this library. |
463 | 0 | std::string linkLanguage = |
464 | 0 | this->GeneratorTarget->GetLinkerLanguage(this->GetConfigName()); |
465 | | |
466 | | // Make sure we have a link language. |
467 | 0 | if (linkLanguage.empty()) { |
468 | 0 | cmSystemTools::Error("Cannot determine link language for target \"" + |
469 | 0 | this->GeneratorTarget->GetName() + "\"."); |
470 | 0 | return; |
471 | 0 | } |
472 | | |
473 | 0 | auto linker = this->GeneratorTarget->GetLinkerTool(this->GetConfigName()); |
474 | | |
475 | | // Build list of dependencies. |
476 | 0 | std::vector<std::string> depends; |
477 | 0 | this->AppendLinkDepends(depends, linkLanguage); |
478 | 0 | if (!this->DeviceLinkObject.empty()) { |
479 | 0 | depends.push_back(this->DeviceLinkObject); |
480 | 0 | } |
481 | | |
482 | | // Create set of linking flags. |
483 | 0 | std::string linkFlags; |
484 | 0 | this->LocalGenerator->AppendFlags(linkFlags, extraFlags); |
485 | 0 | this->LocalGenerator->AppendIPOLinkerFlags( |
486 | 0 | linkFlags, this->GeneratorTarget, this->GetConfigName(), linkLanguage); |
487 | | |
488 | | // Add OSX version flags, if any. |
489 | 0 | if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY || |
490 | 0 | this->GeneratorTarget->GetType() == cmStateEnums::MODULE_LIBRARY) { |
491 | 0 | this->AppendOSXVerFlag(linkFlags, linkLanguage, "COMPATIBILITY", true); |
492 | 0 | this->AppendOSXVerFlag(linkFlags, linkLanguage, "CURRENT", false); |
493 | 0 | } |
494 | | |
495 | | // Construct the name of the library. |
496 | 0 | this->GeneratorTarget->GetLibraryNames(this->GetConfigName()); |
497 | | |
498 | | // Construct the full path version of the names. |
499 | 0 | std::string outpath; |
500 | 0 | std::string outpathImp; |
501 | 0 | if (this->GeneratorTarget->IsFrameworkOnApple()) { |
502 | 0 | outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); |
503 | 0 | cmOSXBundleGenerator::SkipParts bundleSkipParts; |
504 | 0 | if (this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) { |
505 | 0 | bundleSkipParts.TextStubs = false; |
506 | 0 | } |
507 | 0 | this->OSXBundleGenerator->CreateFramework(this->TargetNames.Output, |
508 | 0 | outpath, this->GetConfigName(), |
509 | 0 | bundleSkipParts); |
510 | 0 | outpath += '/'; |
511 | 0 | if (!this->TargetNames.ImportLibrary.empty()) { |
512 | 0 | outpathImp = this->GeneratorTarget->GetDirectory( |
513 | 0 | this->GetConfigName(), cmStateEnums::ImportLibraryArtifact); |
514 | 0 | cmSystemTools::MakeDirectory(outpathImp); |
515 | 0 | outpathImp += '/'; |
516 | 0 | } |
517 | 0 | } else if (this->GeneratorTarget->IsCFBundleOnApple()) { |
518 | 0 | outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); |
519 | 0 | this->OSXBundleGenerator->CreateCFBundle(this->TargetNames.Output, outpath, |
520 | 0 | this->GetConfigName()); |
521 | 0 | outpath += '/'; |
522 | 0 | } else if (relink) { |
523 | 0 | outpath = cmStrCat(this->Makefile->GetCurrentBinaryDirectory(), |
524 | 0 | "/CMakeFiles/CMakeRelink.dir"); |
525 | 0 | cmSystemTools::MakeDirectory(outpath); |
526 | 0 | outpath += '/'; |
527 | 0 | if (!this->TargetNames.ImportLibrary.empty()) { |
528 | 0 | outpathImp = outpath; |
529 | 0 | } |
530 | 0 | } else { |
531 | 0 | outpath = this->GeneratorTarget->GetDirectory(this->GetConfigName()); |
532 | 0 | cmSystemTools::MakeDirectory(outpath); |
533 | 0 | outpath += '/'; |
534 | 0 | if (!this->TargetNames.ImportLibrary.empty()) { |
535 | 0 | outpathImp = this->GeneratorTarget->GetDirectory( |
536 | 0 | this->GetConfigName(), cmStateEnums::ImportLibraryArtifact); |
537 | 0 | cmSystemTools::MakeDirectory(outpathImp); |
538 | 0 | outpathImp += '/'; |
539 | 0 | } |
540 | 0 | } |
541 | |
|
542 | 0 | std::string compilePdbOutputPath = |
543 | 0 | this->GeneratorTarget->GetCompilePDBDirectory(this->GetConfigName()); |
544 | 0 | cmSystemTools::MakeDirectory(compilePdbOutputPath); |
545 | |
|
546 | 0 | std::string pdbOutputPath = |
547 | 0 | this->GeneratorTarget->GetPDBDirectory(this->GetConfigName()); |
548 | 0 | cmSystemTools::MakeDirectory(pdbOutputPath); |
549 | 0 | pdbOutputPath += "/"; |
550 | |
|
551 | 0 | std::string targetFullPath = outpath + this->TargetNames.Output; |
552 | 0 | std::string targetFullPathPDB = pdbOutputPath + this->TargetNames.PDB; |
553 | 0 | std::string targetFullPathSO = outpath + this->TargetNames.SharedObject; |
554 | 0 | std::string targetFullPathReal = outpath + this->TargetNames.Real; |
555 | 0 | std::string targetFullPathImport = |
556 | 0 | outpathImp + this->TargetNames.ImportLibrary; |
557 | | |
558 | | // Construct the output path version of the names for use in command |
559 | | // arguments. |
560 | 0 | std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( |
561 | 0 | targetFullPathPDB, cmOutputConverter::SHELL); |
562 | |
|
563 | 0 | std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat( |
564 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPath), |
565 | 0 | cmOutputConverter::SHELL); |
566 | 0 | std::string targetOutPathSO = this->LocalGenerator->ConvertToOutputFormat( |
567 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathSO), |
568 | 0 | cmOutputConverter::SHELL); |
569 | 0 | std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat( |
570 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal), |
571 | 0 | cmOutputConverter::SHELL); |
572 | 0 | std::string targetOutPathImport = |
573 | 0 | this->LocalGenerator->ConvertToOutputFormat( |
574 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport), |
575 | 0 | cmOutputConverter::SHELL); |
576 | |
|
577 | 0 | this->NumberOfProgressActions++; |
578 | 0 | if (!this->NoRuleMessages) { |
579 | 0 | cmLocalUnixMakefileGenerator3::EchoProgress progress; |
580 | 0 | this->MakeEchoProgress(progress); |
581 | | // Add the link message. |
582 | 0 | std::string buildEcho = cmStrCat("Linking ", linkLanguage); |
583 | 0 | switch (this->GeneratorTarget->GetType()) { |
584 | 0 | case cmStateEnums::STATIC_LIBRARY: |
585 | 0 | buildEcho += " static library "; |
586 | 0 | break; |
587 | 0 | case cmStateEnums::SHARED_LIBRARY: |
588 | 0 | buildEcho += " shared library "; |
589 | 0 | break; |
590 | 0 | case cmStateEnums::MODULE_LIBRARY: |
591 | 0 | if (this->GeneratorTarget->IsCFBundleOnApple()) { |
592 | 0 | buildEcho += " CFBundle"; |
593 | 0 | } |
594 | 0 | buildEcho += " shared module "; |
595 | 0 | break; |
596 | 0 | default: |
597 | 0 | buildEcho += " library "; |
598 | 0 | break; |
599 | 0 | } |
600 | 0 | buildEcho += targetOutPath; |
601 | 0 | this->LocalGenerator->AppendEcho( |
602 | 0 | commands, buildEcho, cmLocalUnixMakefileGenerator3::EchoLink, &progress); |
603 | 0 | } |
604 | | |
605 | | // Clean files associated with this library. |
606 | 0 | std::set<std::string> libCleanFiles; |
607 | 0 | libCleanFiles.insert( |
608 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal)); |
609 | |
|
610 | 0 | std::vector<std::string> commands1; |
611 | | // Add a command to remove any existing files for this library. |
612 | | // for static libs only |
613 | 0 | if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { |
614 | 0 | this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles, |
615 | 0 | this->GeneratorTarget, "target"); |
616 | 0 | this->LocalGenerator->CreateCDCommand( |
617 | 0 | commands1, this->Makefile->GetCurrentBinaryDirectory(), |
618 | 0 | this->LocalGenerator->GetBinaryDirectory()); |
619 | 0 | cm::append(commands, commands1); |
620 | 0 | commands1.clear(); |
621 | 0 | } |
622 | |
|
623 | 0 | if (this->TargetNames.Output != this->TargetNames.Real) { |
624 | 0 | libCleanFiles.insert( |
625 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPath)); |
626 | 0 | } |
627 | 0 | if (this->TargetNames.SharedObject != this->TargetNames.Real && |
628 | 0 | this->TargetNames.SharedObject != this->TargetNames.Output) { |
629 | 0 | libCleanFiles.insert( |
630 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathSO)); |
631 | 0 | } |
632 | 0 | if (!this->TargetNames.ImportLibrary.empty()) { |
633 | 0 | libCleanFiles.insert( |
634 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathImport)); |
635 | 0 | std::string implib; |
636 | 0 | if (this->GeneratorTarget->GetImplibGNUtoMS( |
637 | 0 | this->GetConfigName(), targetFullPathImport, implib)) { |
638 | 0 | libCleanFiles.insert( |
639 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(implib)); |
640 | 0 | } |
641 | 0 | } |
642 | | |
643 | | // List the PDB for cleaning only when the whole target is |
644 | | // cleaned. We do not want to delete the .pdb file just before |
645 | | // linking the target. |
646 | 0 | this->CleanFiles.insert( |
647 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathPDB)); |
648 | |
|
649 | | #ifdef _WIN32 |
650 | | // There may be a manifest file for this target. Add it to the |
651 | | // clean set just in case. |
652 | | if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) { |
653 | | libCleanFiles.insert(this->LocalGenerator->MaybeRelativeToCurBinDir( |
654 | | targetFullPath + ".manifest")); |
655 | | } |
656 | | #endif |
657 | | |
658 | | // Add the pre-build and pre-link rules building but not when relinking. |
659 | 0 | if (!relink) { |
660 | 0 | this->LocalGenerator->AppendCustomCommands( |
661 | 0 | commands, this->GeneratorTarget->GetPreBuildCommands(), |
662 | 0 | this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); |
663 | 0 | this->LocalGenerator->AppendCustomCommands( |
664 | 0 | commands, this->GeneratorTarget->GetPreLinkCommands(), |
665 | 0 | this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); |
666 | 0 | } |
667 | | |
668 | | // Determine whether a link script will be used. |
669 | 0 | bool useLinkScript = this->GlobalGenerator->GetUseLinkScript(); |
670 | |
|
671 | 0 | bool useResponseFileForObjects = |
672 | 0 | this->CheckUseResponseFileForObjects(linkLanguage); |
673 | 0 | bool const useResponseFileForLibs = |
674 | 0 | this->CheckUseResponseFileForLibraries(linkLanguage); |
675 | | |
676 | | // For static libraries there might be archiving rules. |
677 | 0 | bool haveStaticLibraryRule = false; |
678 | 0 | cmList archiveCreateCommands; |
679 | 0 | cmList archiveAppendCommands; |
680 | 0 | cmList archiveFinishCommands; |
681 | 0 | std::string::size_type archiveCommandLimit = std::string::npos; |
682 | 0 | if (this->GeneratorTarget->GetType() == cmStateEnums::STATIC_LIBRARY) { |
683 | 0 | haveStaticLibraryRule = this->Makefile->IsDefinitionSet(linkRuleVar); |
684 | 0 | std::string arCreateVar = |
685 | 0 | cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_CREATE"); |
686 | |
|
687 | 0 | arCreateVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( |
688 | 0 | arCreateVar, linkLanguage, this->GetConfigName()); |
689 | |
|
690 | 0 | archiveCreateCommands.assign(this->Makefile->GetDefinition(arCreateVar)); |
691 | |
|
692 | 0 | std::string arAppendVar = |
693 | 0 | cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_APPEND"); |
694 | |
|
695 | 0 | arAppendVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( |
696 | 0 | arAppendVar, linkLanguage, this->GetConfigName()); |
697 | |
|
698 | 0 | archiveAppendCommands.assign(this->Makefile->GetDefinition(arAppendVar)); |
699 | |
|
700 | 0 | std::string arFinishVar = |
701 | 0 | cmStrCat("CMAKE_", linkLanguage, "_ARCHIVE_FINISH"); |
702 | |
|
703 | 0 | arFinishVar = this->GeneratorTarget->GetFeatureSpecificLinkRuleVariable( |
704 | 0 | arFinishVar, linkLanguage, this->GetConfigName()); |
705 | |
|
706 | 0 | archiveFinishCommands.assign(this->Makefile->GetDefinition(arFinishVar)); |
707 | 0 | } |
708 | | |
709 | | // Decide whether to use archiving rules. |
710 | 0 | bool useArchiveRules = !haveStaticLibraryRule && |
711 | 0 | !archiveCreateCommands.empty() && !archiveAppendCommands.empty(); |
712 | 0 | if (useArchiveRules) { |
713 | | // Archiving rules are always run with a link script. |
714 | 0 | useLinkScript = true; |
715 | | |
716 | | // Archiving rules never use a response file. |
717 | 0 | useResponseFileForObjects = false; |
718 | | |
719 | | // Limit the length of individual object lists to less than half of |
720 | | // the command line length limit (leaving half for other flags). |
721 | | // This may result in several calls to the archiver. |
722 | 0 | if (size_t limit = cmSystemTools::CalculateCommandLineLengthLimit()) { |
723 | 0 | archiveCommandLimit = limit / 2; |
724 | 0 | } else { |
725 | 0 | archiveCommandLimit = 8000; |
726 | 0 | } |
727 | 0 | } |
728 | | |
729 | | // Expand the rule variables. |
730 | 0 | auto rulePlaceholderExpander = |
731 | 0 | this->LocalGenerator->CreateRulePlaceholderExpander(cmBuildStep::Link); |
732 | 0 | bool useWatcomQuote = |
733 | 0 | this->Makefile->IsOn(linkRuleVar + "_USE_WATCOM_QUOTE"); |
734 | 0 | cmList real_link_commands; |
735 | 0 | { |
736 | | // Set path conversion for link script shells. |
737 | 0 | this->LocalGenerator->SetLinkScriptShell(useLinkScript); |
738 | | |
739 | | // Collect up flags to link in needed libraries. |
740 | 0 | std::string linkLibs; |
741 | 0 | if (this->GeneratorTarget->GetType() != cmStateEnums::STATIC_LIBRARY) { |
742 | |
|
743 | 0 | std::unique_ptr<cmLinkLineComputer> linkLineComputer = |
744 | 0 | this->CreateLinkLineComputer( |
745 | 0 | this->LocalGenerator, |
746 | 0 | this->LocalGenerator->GetStateSnapshot().GetDirectory()); |
747 | 0 | linkLineComputer->SetForResponse(useResponseFileForLibs); |
748 | 0 | linkLineComputer->SetUseWatcomQuote(useWatcomQuote); |
749 | 0 | linkLineComputer->SetRelink(relink); |
750 | |
|
751 | 0 | this->CreateLinkLibs(linkLineComputer.get(), linkLibs, |
752 | 0 | useResponseFileForLibs, depends, linkLanguage); |
753 | 0 | } |
754 | | |
755 | | // Construct object file lists that may be needed to expand the |
756 | | // rule. |
757 | 0 | std::string buildObjs; |
758 | 0 | this->CreateObjectLists(useLinkScript, useArchiveRules, |
759 | 0 | useResponseFileForObjects, buildObjs, depends, |
760 | 0 | useWatcomQuote, linkLanguage); |
761 | 0 | if (!this->DeviceLinkObject.empty()) { |
762 | 0 | buildObjs += " " + |
763 | 0 | this->LocalGenerator->ConvertToOutputFormat( |
764 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir( |
765 | 0 | this->DeviceLinkObject), |
766 | 0 | cmOutputConverter::SHELL); |
767 | 0 | } |
768 | |
|
769 | 0 | std::string const& aixExports = this->GetAIXExports(this->GetConfigName()); |
770 | | |
771 | | // maybe create .def file from list of objects |
772 | 0 | this->GenDefFile(real_link_commands); |
773 | |
|
774 | 0 | std::string manifests = this->GetManifests(this->GetConfigName()); |
775 | |
|
776 | 0 | cmRulePlaceholderExpander::RuleVariables vars; |
777 | 0 | vars.TargetPDB = targetOutPathPDB.c_str(); |
778 | | |
779 | | // Setup the target version. |
780 | 0 | std::string targetVersionMajor; |
781 | 0 | std::string targetVersionMinor; |
782 | 0 | { |
783 | 0 | std::ostringstream majorStream; |
784 | 0 | std::ostringstream minorStream; |
785 | 0 | int major; |
786 | 0 | int minor; |
787 | 0 | this->GeneratorTarget->GetTargetVersion(major, minor); |
788 | 0 | majorStream << major; |
789 | 0 | minorStream << minor; |
790 | 0 | targetVersionMajor = majorStream.str(); |
791 | 0 | targetVersionMinor = minorStream.str(); |
792 | 0 | } |
793 | 0 | vars.TargetVersionMajor = targetVersionMajor.c_str(); |
794 | 0 | vars.TargetVersionMinor = targetVersionMinor.c_str(); |
795 | |
|
796 | 0 | vars.CMTargetName = this->GeneratorTarget->GetName().c_str(); |
797 | 0 | vars.CMTargetType = |
798 | 0 | cmState::GetTargetTypeName(this->GeneratorTarget->GetType()).c_str(); |
799 | 0 | vars.Language = linkLanguage.c_str(); |
800 | 0 | vars.Linker = linker.c_str(); |
801 | 0 | vars.AIXExports = aixExports.c_str(); |
802 | 0 | vars.Objects = buildObjs.c_str(); |
803 | 0 | std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); |
804 | |
|
805 | 0 | objectDir = this->LocalGenerator->ConvertToOutputFormat( |
806 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(objectDir), |
807 | 0 | cmOutputConverter::SHELL); |
808 | |
|
809 | 0 | vars.ObjectDir = objectDir.c_str(); |
810 | 0 | std::string targetSupportDir = |
811 | 0 | this->GeneratorTarget->GetCMFSupportDirectory(); |
812 | |
|
813 | 0 | targetSupportDir = this->LocalGenerator->ConvertToOutputFormat( |
814 | 0 | this->LocalGenerator->MaybeRelativeToTopBinDir(targetSupportDir), |
815 | 0 | cmOutputConverter::SHELL); |
816 | |
|
817 | 0 | vars.TargetSupportDir = targetSupportDir.c_str(); |
818 | 0 | std::string target = this->LocalGenerator->ConvertToOutputFormat( |
819 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal), |
820 | 0 | cmOutputConverter::SHELL, useWatcomQuote); |
821 | 0 | vars.Target = target.c_str(); |
822 | 0 | vars.LinkLibraries = linkLibs.c_str(); |
823 | 0 | vars.ObjectsQuoted = buildObjs.c_str(); |
824 | 0 | std::string targetOutSOName; |
825 | 0 | if (this->GeneratorTarget->HasSOName(this->GetConfigName()) || |
826 | 0 | this->GeneratorTarget->IsArchivedAIXSharedLibrary()) { |
827 | 0 | vars.SONameFlag = this->Makefile->GetSONameFlag(linkLanguage); |
828 | 0 | targetOutSOName = this->LocalGenerator->ConvertToOutputFormat( |
829 | 0 | this->TargetNames.SharedObject, cmOutputConverter::SHELL); |
830 | 0 | vars.TargetSOName = targetOutSOName.c_str(); |
831 | 0 | } |
832 | 0 | vars.LinkFlags = linkFlags.c_str(); |
833 | 0 | vars.Manifests = manifests.c_str(); |
834 | 0 | vars.Config = this->GetConfigName().c_str(); |
835 | | |
836 | | // Compute the directory portion of the install_name setting. |
837 | 0 | std::string install_name_dir; |
838 | 0 | if (this->GeneratorTarget->GetType() == cmStateEnums::SHARED_LIBRARY) { |
839 | | // Get the install_name directory for the build tree. |
840 | 0 | install_name_dir = this->GeneratorTarget->GetInstallNameDirForBuildTree( |
841 | 0 | this->GetConfigName()); |
842 | | |
843 | | // Set the rule variable replacement value. |
844 | 0 | if (install_name_dir.empty()) { |
845 | 0 | vars.TargetInstallNameDir = ""; |
846 | 0 | } else { |
847 | | // Convert to a path for the native build tool. |
848 | 0 | install_name_dir = this->LocalGenerator->ConvertToOutputFormat( |
849 | 0 | install_name_dir, cmOutputConverter::SHELL); |
850 | 0 | vars.TargetInstallNameDir = install_name_dir.c_str(); |
851 | 0 | } |
852 | 0 | } |
853 | | |
854 | | // Add language-specific flags. |
855 | 0 | std::string langFlags; |
856 | 0 | this->LocalGenerator->AddLanguageFlagsForLinking( |
857 | 0 | langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
858 | |
|
859 | 0 | this->LocalGenerator->AddArchitectureFlags( |
860 | 0 | langFlags, this->GeneratorTarget, linkLanguage, this->GetConfigName()); |
861 | |
|
862 | 0 | vars.LanguageCompileFlags = langFlags.c_str(); |
863 | |
|
864 | 0 | std::string linkerLauncher = |
865 | 0 | this->GetLinkerLauncher(this->GetConfigName()); |
866 | 0 | if (cmNonempty(linkerLauncher)) { |
867 | 0 | vars.Launcher = linkerLauncher.c_str(); |
868 | 0 | } |
869 | |
|
870 | 0 | std::string launcher; |
871 | 0 | std::string val = this->LocalGenerator->GetRuleLauncher( |
872 | 0 | this->GeneratorTarget, "RULE_LAUNCH_LINK", |
873 | 0 | this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE")); |
874 | 0 | if (cmNonempty(val)) { |
875 | 0 | launcher = cmStrCat(val, ' '); |
876 | 0 | } |
877 | | |
878 | | // Construct the main link rule and expand placeholders. |
879 | 0 | rulePlaceholderExpander->SetTargetImpLib(targetOutPathImport); |
880 | 0 | if (useArchiveRules) { |
881 | | // Construct the individual object list strings. |
882 | 0 | std::vector<std::string> object_strings; |
883 | 0 | this->WriteObjectsStrings(object_strings, false, archiveCommandLimit); |
884 | | |
885 | | // Add the cuda device object to the list of archive files. This will |
886 | | // only occur on archives which have CUDA_RESOLVE_DEVICE_SYMBOLS enabled |
887 | 0 | if (!this->DeviceLinkObject.empty()) { |
888 | 0 | object_strings.push_back(this->LocalGenerator->ConvertToOutputFormat( |
889 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir( |
890 | 0 | this->DeviceLinkObject), |
891 | 0 | cmOutputConverter::SHELL)); |
892 | 0 | } |
893 | | |
894 | | // Create the archive with the first set of objects. |
895 | 0 | auto osi = object_strings.begin(); |
896 | 0 | { |
897 | 0 | vars.Objects = osi->c_str(); |
898 | 0 | for (std::string const& acc : archiveCreateCommands) { |
899 | 0 | std::string cmd = launcher + acc; |
900 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, |
901 | 0 | cmd, vars); |
902 | 0 | real_link_commands.push_back(std::move(cmd)); |
903 | 0 | } |
904 | 0 | } |
905 | | // Append to the archive with the other object sets. |
906 | 0 | for (++osi; osi != object_strings.end(); ++osi) { |
907 | 0 | vars.Objects = osi->c_str(); |
908 | 0 | for (std::string const& aac : archiveAppendCommands) { |
909 | 0 | std::string cmd = launcher + aac; |
910 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, |
911 | 0 | cmd, vars); |
912 | 0 | real_link_commands.push_back(std::move(cmd)); |
913 | 0 | } |
914 | 0 | } |
915 | | // Finish the archive. |
916 | 0 | vars.Objects = ""; |
917 | 0 | for (std::string const& afc : archiveFinishCommands) { |
918 | 0 | std::string cmd = launcher + afc; |
919 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, cmd, |
920 | 0 | vars); |
921 | | // If there is no ranlib the command will be ":". Skip it. |
922 | 0 | if (!cmd.empty() && cmd[0] != ':') { |
923 | 0 | real_link_commands.push_back(std::move(cmd)); |
924 | 0 | } |
925 | 0 | } |
926 | 0 | } else { |
927 | | // Get the set of commands. |
928 | 0 | std::string linkRule = this->GetLinkRule(linkRuleVar); |
929 | 0 | real_link_commands.append(linkRule); |
930 | 0 | if (this->UseLWYU) { |
931 | 0 | cmValue lwyuCheck = |
932 | 0 | this->Makefile->GetDefinition("CMAKE_LINK_WHAT_YOU_USE_CHECK"); |
933 | 0 | if (lwyuCheck) { |
934 | 0 | std::string cmakeCommand = cmStrCat( |
935 | 0 | this->LocalGenerator->ConvertToOutputFormat( |
936 | 0 | cmSystemTools::GetCMakeCommand(), cmLocalGenerator::SHELL), |
937 | 0 | " -E __run_co_compile --lwyu="); |
938 | 0 | cmakeCommand += this->LocalGenerator->EscapeForShell(*lwyuCheck); |
939 | 0 | cmakeCommand += cmStrCat(" --source=", targetOutPathReal); |
940 | 0 | real_link_commands.push_back(std::move(cmakeCommand)); |
941 | 0 | } |
942 | 0 | } |
943 | | |
944 | | // Expand placeholders. |
945 | 0 | for (auto& real_link_command : real_link_commands) { |
946 | 0 | real_link_command = cmStrCat(launcher, real_link_command); |
947 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, |
948 | 0 | real_link_command, vars); |
949 | 0 | } |
950 | 0 | } |
951 | | |
952 | | // Restore path conversion to normal shells. |
953 | 0 | this->LocalGenerator->SetLinkScriptShell(false); |
954 | 0 | } |
955 | | |
956 | | // Optionally convert the build rule to use a script to avoid long |
957 | | // command lines in the make shell. |
958 | 0 | if (useLinkScript) { |
959 | | // Use a link script. |
960 | 0 | char const* name = (relink ? "relink.txt" : "link.txt"); |
961 | 0 | this->CreateLinkScript(name, real_link_commands, commands1, depends); |
962 | 0 | } else { |
963 | | // No link script. Just use the link rule directly. |
964 | 0 | commands1 = real_link_commands; |
965 | 0 | } |
966 | 0 | this->LocalGenerator->CreateCDCommand( |
967 | 0 | commands1, this->Makefile->GetCurrentBinaryDirectory(), |
968 | 0 | this->LocalGenerator->GetBinaryDirectory()); |
969 | 0 | cm::append(commands, commands1); |
970 | 0 | commands1.clear(); |
971 | | |
972 | | // Add a rule to create necessary symlinks for the library. |
973 | | // Frameworks are handled by cmOSXBundleGenerator. |
974 | 0 | if (targetOutPath != targetOutPathReal && |
975 | 0 | !this->GeneratorTarget->IsFrameworkOnApple()) { |
976 | 0 | std::string symlink = |
977 | 0 | cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_library ", targetOutPathReal, |
978 | 0 | ' ', targetOutPathSO, ' ', targetOutPath); |
979 | 0 | commands1.push_back(std::move(symlink)); |
980 | 0 | this->LocalGenerator->CreateCDCommand( |
981 | 0 | commands1, this->Makefile->GetCurrentBinaryDirectory(), |
982 | 0 | this->LocalGenerator->GetBinaryDirectory()); |
983 | 0 | cm::append(commands, commands1); |
984 | 0 | commands1.clear(); |
985 | 0 | } |
986 | | |
987 | | // Add the post-build rules when building but not when relinking. |
988 | 0 | if (!relink) { |
989 | 0 | this->LocalGenerator->AppendCustomCommands( |
990 | 0 | commands, this->GeneratorTarget->GetPostBuildCommands(), |
991 | 0 | this->GeneratorTarget, this->LocalGenerator->GetBinaryDirectory()); |
992 | 0 | } |
993 | | |
994 | | // Compute the list of outputs. |
995 | 0 | std::vector<std::string> outputs; |
996 | 0 | outputs.reserve(3); |
997 | 0 | outputs.push_back(targetFullPathReal); |
998 | 0 | if (this->TargetNames.SharedObject != this->TargetNames.Real) { |
999 | 0 | outputs.push_back(targetFullPathSO); |
1000 | 0 | } |
1001 | 0 | if (this->TargetNames.Output != this->TargetNames.SharedObject && |
1002 | 0 | this->TargetNames.Output != this->TargetNames.Real) { |
1003 | 0 | outputs.push_back(targetFullPath); |
1004 | 0 | } |
1005 | | |
1006 | | // Write the build rule. |
1007 | 0 | this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, |
1008 | 0 | commands, false); |
1009 | | |
1010 | | // Add rule to generate text-based stubs, if required |
1011 | 0 | if (this->GeneratorTarget->IsApple() && |
1012 | 0 | this->GeneratorTarget->HasImportLibrary(this->GetConfigName())) { |
1013 | 0 | auto genStubsRule = |
1014 | 0 | this->Makefile->GetDefinition("CMAKE_CREATE_TEXT_STUBS"); |
1015 | 0 | cmList genStubs_commands{ genStubsRule }; |
1016 | 0 | this->LocalGenerator->CreateCDCommand( |
1017 | 0 | genStubs_commands, this->Makefile->GetCurrentBinaryDirectory(), |
1018 | 0 | this->LocalGenerator->GetBinaryDirectory()); |
1019 | |
|
1020 | 0 | std::string TBDFullPath = |
1021 | 0 | cmStrCat(outpathImp, this->TargetNames.ImportOutput); |
1022 | 0 | std::string TBDFullPathReal = |
1023 | 0 | cmStrCat(outpathImp, this->TargetNames.ImportReal); |
1024 | 0 | std::string TBDFullPathSO = |
1025 | 0 | cmStrCat(outpathImp, this->TargetNames.ImportLibrary); |
1026 | | |
1027 | | // Expand placeholders. |
1028 | 0 | cmRulePlaceholderExpander::RuleVariables vars; |
1029 | 0 | std::string target = this->LocalGenerator->ConvertToOutputFormat( |
1030 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(targetFullPathReal), |
1031 | 0 | cmOutputConverter::SHELL, useWatcomQuote); |
1032 | 0 | vars.Target = target.c_str(); |
1033 | 0 | std::string TBDOutPathReal = this->LocalGenerator->ConvertToOutputFormat( |
1034 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathReal), |
1035 | 0 | cmOutputConverter::SHELL, useWatcomQuote); |
1036 | 0 | rulePlaceholderExpander->SetTargetImpLib(TBDOutPathReal); |
1037 | 0 | for (std::string& command : genStubs_commands) { |
1038 | 0 | rulePlaceholderExpander->ExpandRuleVariables(this->LocalGenerator, |
1039 | 0 | command, vars); |
1040 | 0 | } |
1041 | 0 | outputs.clear(); |
1042 | 0 | outputs.push_back(TBDFullPathReal); |
1043 | 0 | if (this->TargetNames.ImportLibrary != this->TargetNames.ImportReal) { |
1044 | 0 | outputs.push_back(TBDFullPathSO); |
1045 | 0 | } |
1046 | 0 | if (this->TargetNames.ImportOutput != this->TargetNames.ImportLibrary && |
1047 | 0 | this->TargetNames.ImportOutput != this->TargetNames.ImportReal) { |
1048 | 0 | outputs.push_back(TBDFullPath); |
1049 | 0 | } |
1050 | 0 | this->ExtraFiles.insert(TBDFullPath); |
1051 | |
|
1052 | 0 | depends.clear(); |
1053 | 0 | depends.push_back(targetFullPathReal); |
1054 | | |
1055 | | // Add a rule to create necessary symlinks for the library. |
1056 | | // Frameworks are handled by cmOSXBundleGenerator. |
1057 | 0 | if (TBDFullPath != TBDFullPathReal && |
1058 | 0 | !this->GeneratorTarget->IsFrameworkOnApple()) { |
1059 | 0 | auto TBDOutPathSO = this->LocalGenerator->ConvertToOutputFormat( |
1060 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathSO), |
1061 | 0 | cmOutputConverter::SHELL, useWatcomQuote); |
1062 | 0 | auto TBDOutPath = this->LocalGenerator->ConvertToOutputFormat( |
1063 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPath), |
1064 | 0 | cmOutputConverter::SHELL, useWatcomQuote); |
1065 | |
|
1066 | 0 | std::string symlink = |
1067 | 0 | cmStrCat("$(CMAKE_COMMAND) -E cmake_symlink_library ", TBDOutPathReal, |
1068 | 0 | ' ', TBDOutPathSO, ' ', TBDOutPath); |
1069 | 0 | commands1.push_back(std::move(symlink)); |
1070 | 0 | this->LocalGenerator->CreateCDCommand( |
1071 | 0 | commands1, this->Makefile->GetCurrentBinaryDirectory(), |
1072 | 0 | this->LocalGenerator->GetBinaryDirectory()); |
1073 | 0 | cm::append(genStubs_commands, commands1); |
1074 | 0 | commands1.clear(); |
1075 | 0 | } |
1076 | |
|
1077 | 0 | this->WriteMakeRule(*this->BuildFileStream, nullptr, outputs, depends, |
1078 | 0 | genStubs_commands, false); |
1079 | | |
1080 | | // clean actions for apple specific outputs |
1081 | | // clean actions for ImportLibrary are already specified |
1082 | 0 | if (this->TargetNames.ImportReal != this->TargetNames.ImportLibrary) { |
1083 | 0 | libCleanFiles.insert( |
1084 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPathReal)); |
1085 | 0 | } |
1086 | 0 | if (this->TargetNames.ImportOutput != this->TargetNames.ImportReal && |
1087 | 0 | this->TargetNames.ImportOutput != this->TargetNames.ImportLibrary) { |
1088 | 0 | libCleanFiles.insert( |
1089 | 0 | this->LocalGenerator->MaybeRelativeToCurBinDir(TBDFullPath)); |
1090 | 0 | } |
1091 | 0 | } |
1092 | | |
1093 | | // Write the main driver rule to build everything in this target. |
1094 | 0 | this->WriteTargetDriverRule(targetFullPath, relink); |
1095 | | |
1096 | | // Clean all the possible library names and symlinks. |
1097 | 0 | this->CleanFiles.insert(libCleanFiles.begin(), libCleanFiles.end()); |
1098 | 0 | } |