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