Coverage Report

Created: 2026-02-09 06:05

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