Coverage Report

Created: 2026-07-14 07:09

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