Coverage Report

Created: 2026-07-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmComputeLinkInformation.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 "cmComputeLinkInformation.h"
4
5
#include <algorithm>
6
#include <sstream>
7
#include <utility>
8
9
#include <cm/memory>
10
#include <cm/optional>
11
#include <cm/string_view>
12
#include <cmext/algorithm>
13
#include <cmext/string_view>
14
15
#include "cmsys/String.h"
16
17
#include "cmComputeLinkDepends.h"
18
#include "cmGeneratorTarget.h"
19
#include "cmGlobalGenerator.h"
20
#include "cmLinkItem.h"
21
#include "cmList.h"
22
#include "cmListFileCache.h"
23
#include "cmLocalGenerator.h"
24
#include "cmMakefile.h"
25
#include "cmMessageType.h"
26
#include "cmOrderDirectories.h"
27
#include "cmPlaceholderExpander.h"
28
#include "cmSourceFile.h"
29
#include "cmState.h"
30
#include "cmStateTypes.h"
31
#include "cmStringAlgorithms.h"
32
#include "cmSystemTools.h"
33
#include "cmTarget.h"
34
#include "cmTargetTypes.h"
35
#include "cmValue.h"
36
#include "cmXcFramework.h"
37
#include "cmake.h"
38
39
// #define CM_COMPUTE_LINK_INFO_DEBUG
40
41
/*
42
Notes about linking on various platforms:
43
44
------------------------------------------------------------------------------
45
46
Linux, FreeBSD, macOS, Sun, Windows:
47
48
Linking to libraries using the full path works fine.
49
50
------------------------------------------------------------------------------
51
52
On AIX, more work is needed.
53
54
  The "-bnoipath" option is needed.  From "man ld":
55
56
    Note: If you specify a shared object, or an archive file
57
    containing a shared object, with an absolute or relative path
58
    name, instead of with the -lName flag, the path name is
59
    included in the import file ID string in the loader section of
60
    the output file. You can override this behavior with the
61
    -bnoipath option.
62
63
      noipath
64
65
        For shared objects listed on the command-line, rather than
66
        specified with the -l flag, use a null path component when
67
        listing the shared object in the loader section of the
68
        output file. A null path component is always used for
69
        shared objects specified with the -l flag. This option
70
        does not affect the specification of a path component by
71
        using a line beginning with #! in an import file. The
72
        default is the ipath option.
73
74
  This prevents the full path specified on the compile line from being
75
  compiled directly into the binary.
76
77
  By default the linker places -L paths in the embedded runtime path.
78
  In order to implement CMake's RPATH interface correctly, we need the
79
  -blibpath:Path option.  From "man ld":
80
81
      libpath:Path
82
83
        Uses Path as the library path when writing the loader section
84
        of the output file. Path is neither checked for validity nor
85
        used when searching for libraries specified by the -l flag.
86
        Path overrides any library paths generated when the -L flag is
87
        used.
88
89
        If you do not specify any -L flags, or if you specify the
90
        nolibpath option, the default library path information is
91
        written in the loader section of the output file. The default
92
        library path information is the value of the LIBPATH
93
        environment variable if it is defined, and /usr/lib:/lib,
94
        otherwise.
95
96
  We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
97
  and not break when the user sets LIBPATH.  Then if we want to add an
98
  rpath we insert it into the option before /usr/lib.
99
100
------------------------------------------------------------------------------
101
102
On HP-UX, more work is needed.  There are differences between
103
versions.
104
105
ld: 92453-07 linker linker ld B.10.33 990520
106
107
  Linking with a full path works okay for static and shared libraries.
108
  The linker seems to always put the full path to where the library
109
  was found in the binary whether using a full path or -lfoo syntax.
110
  Transitive link dependencies work just fine due to the full paths.
111
112
  It has the "-l:libfoo.sl" option.  The +nodefaultrpath is accepted
113
  but not documented and does not seem to do anything.  There is no
114
  +forceload option.
115
116
ld: 92453-07 linker ld HP Itanium(R) B.12.41  IPF/IPF
117
118
  Linking with a full path works okay for static libraries.
119
120
  Linking with a full path works okay for shared libraries.  However
121
  dependent (transitive) libraries of those linked directly must be
122
  either found with an rpath stored in the direct dependencies or
123
  found in -L paths as if they were specified with "-l:libfoo.sl"
124
  (really "-l:<soname>").  The search matches that of the dynamic
125
  loader but only with -L paths.  In other words, if we have an
126
  executable that links to shared library bar which links to shared
127
  library foo, the link line for the exe must contain
128
129
    /dir/with/bar/libbar.sl -L/dir/with/foo
130
131
  It does not matter whether the exe wants to link to foo directly or
132
  whether /dir/with/foo/libfoo.sl is listed.  The -L path must still
133
  be present.  It should match the runtime path computed for the
134
  executable taking all directly and transitively linked libraries
135
  into account.
136
137
  The "+nodefaultrpath" option should be used to avoid getting -L
138
  paths in the rpath unless we add our own rpath with +b.  This means
139
  that skip-build-rpath should use this option.
140
141
  See documentation in "man ld", "man dld.so", and
142
  http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
143
144
    +[no]defaultrpath
145
      +defaultrpath is the default.  Include any paths that are
146
      specified with -L in the embedded path, unless you specify the
147
      +b option.  If you use +b, only the path list specified by +b is
148
      in the embedded path.
149
150
      The +nodefaultrpath option removes all library paths that were
151
      specified with the -L option from the embedded path.  The linker
152
      searches the library paths specified by the -L option at link
153
      time.  At run time, the only library paths searched are those
154
      specified by the environment variables LD_LIBRARY_PATH and
155
      SHLIB_PATH, library paths specified by the +b linker option, and
156
      finally the default library paths.
157
158
    +rpathfirst
159
      This option will cause the paths specified in RPATH (embedded
160
      path) to be used before the paths specified in LD_LIBRARY_PATH
161
      or SHLIB_PATH, in searching for shared libraries.  This changes
162
      the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
163
      RPATH (embedded path).
164
165
------------------------------------------------------------------------------
166
Notes about dependent (transitive) shared libraries:
167
168
On non-Windows systems shared libraries may have transitive
169
dependencies.  In order to support LINK_INTERFACE_LIBRARIES we must
170
support linking to a shared library without listing all the libraries
171
to which it links.  Some linkers want to be able to find the
172
transitive dependencies (dependent libraries) of shared libraries
173
listed on the command line.
174
175
  - On Windows, DLLs are not directly linked, and the import libraries
176
    have no transitive dependencies.
177
178
  - On Mac OS X 10.5 and above transitive dependencies are not needed.
179
180
  - On Mac OS X 10.4 and below we need to actually list the dependencies.
181
    Otherwise when using -isysroot for universal binaries it cannot
182
    find the dependent libraries.  Listing them on the command line
183
    tells the linker where to find them, but unfortunately also links
184
    the library.
185
186
  - On HP-UX, the linker wants to find the transitive dependencies of
187
    shared libraries in the -L paths even if the dependent libraries
188
    are given on the link line.
189
190
  - On AIX the transitive dependencies are not needed.
191
192
  - On SGI, the linker wants to find the transitive dependencies of
193
    shared libraries in the -L paths if they are not given on the link
194
    line.  Transitive linking can be disabled using the options
195
196
      -no_transitive_link -Wl,-no_transitive_link
197
198
    which disable it.  Both options must be given when invoking the
199
    linker through the compiler.
200
201
  - On Sun, the linker wants to find the transitive dependencies of
202
    shared libraries in the -L paths if they are not given on the link
203
    line.
204
205
  - On Linux, FreeBSD, and QNX:
206
207
    The linker wants to find the transitive dependencies of shared
208
    libraries in the "-rpath-link" paths option if they have not been
209
    given on the link line.  The option is like rpath but just for
210
    link time:
211
212
      -Wl,-rpath-link,"/path1:/path2"
213
214
For -rpath-link, we need a separate runtime path ordering pass
215
including just the dependent libraries that are not linked.
216
217
For -L paths on non-HP, we can do the same thing as with rpath-link
218
but put the results in -L paths.  The paths should be listed at the
219
end to avoid conflicting with user search paths (?).
220
221
For -L paths on HP, we should do a runtime path ordering pass with
222
all libraries, both linked and non-linked.  Even dependent
223
libraries that are also linked need to be listed in -L paths.
224
225
In our implementation we add all dependent libraries to the runtime
226
path computation.  Then the auto-generated RPATH will find everything.
227
228
------------------------------------------------------------------------------
229
Notes about shared libraries with not builtin soname:
230
231
Some UNIX shared libraries may be created with no builtin soname.  On
232
some platforms such libraries cannot be linked using the path to their
233
location because the linker will copy the path into the field used to
234
find the library at runtime.
235
236
  Apple:    ../libfoo.dylib  ==>  libfoo.dylib  # ok, uses install_name
237
  SGI:      ../libfoo.so     ==>  libfoo.so     # ok
238
  AIX:      ../libfoo.so     ==>  libfoo.so     # ok
239
  Linux:    ../libfoo.so     ==>  ../libfoo.so  # bad
240
  HP-UX:    ../libfoo.so     ==>  ../libfoo.so  # bad
241
  Sun:      ../libfoo.so     ==>  ../libfoo.so  # bad
242
  FreeBSD:  ../libfoo.so     ==>  ../libfoo.so  # bad
243
244
In order to link these libraries we need to use the old-style split
245
into -L.. and -lfoo options.  This should be fairly safe because most
246
problems with -lfoo options were related to selecting shared libraries
247
instead of static but in this case we want the shared lib.  Link
248
directory ordering needs to be done to make sure these shared
249
libraries are found first.  There should be very few restrictions
250
because this need be done only for shared libraries without soname-s.
251
252
*/
253
254
cmComputeLinkInformation::cmComputeLinkInformation(
255
  cmGeneratorTarget const* target, std::string const& config)
256
  // Store context information.
257
0
  : Target(target)
258
0
  , Makefile(target->Target->GetMakefile())
259
0
  , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
260
0
  , CMakeInstance(this->GlobalGenerator->GetCMakeInstance())
261
  // The configuration being linked.
262
0
  , Config(config)
263
0
{
264
  // Check whether to recognize OpenBSD-style library versioned names.
265
0
  this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
266
0
    "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
267
268
  // Allocate internals.
269
0
  this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>(
270
0
    this->GlobalGenerator, target, "linker search path");
271
0
  this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>(
272
0
    this->GlobalGenerator, target, "runtime search path");
273
274
  // Get the language used for linking this target.
275
0
  this->LinkLanguage = this->Target->GetLinkerLanguage(config);
276
0
  if (this->LinkLanguage.empty()) {
277
    // The Compute method will do nothing, so skip the rest of the
278
    // initialization.
279
0
    return;
280
0
  }
281
282
  // Check whether we should skip dependencies on shared library files.
283
0
  this->LinkDependsNoShared =
284
0
    this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
285
286
  // On platforms without import libraries there may be a special flag
287
  // to use when creating a plugin (module) that obtains symbols from
288
  // the program that will load it.
289
0
  if (!this->Target->IsDLLPlatform() &&
290
0
      this->Target->GetType() == cm::TargetType::MODULE_LIBRARY) {
291
0
    std::string loader_flag_var =
292
0
      cmStrCat("CMAKE_SHARED_MODULE_LOADER_", this->LinkLanguage, "_FLAG");
293
0
    this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
294
0
  }
295
296
  // Get options needed to link libraries.
297
0
  if (cmValue flag = this->Makefile->GetDefinition(
298
0
        cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_FLAG"))) {
299
0
    this->LibLinkFlag = *flag;
300
0
  } else {
301
0
    this->LibLinkFlag =
302
0
      this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
303
0
  }
304
0
  if (cmValue flag = this->Makefile->GetDefinition(
305
0
        cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_FILE_FLAG"))) {
306
0
    this->LibLinkFileFlag = *flag;
307
0
  } else {
308
0
    this->LibLinkFileFlag =
309
0
      this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
310
0
  }
311
0
  if (cmValue suffix = this->Makefile->GetDefinition(
312
0
        cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_SUFFIX"))) {
313
0
    this->LibLinkSuffix = *suffix;
314
0
  } else {
315
0
    this->LibLinkSuffix =
316
0
      this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
317
0
  }
318
0
  if (cmValue flag = this->Makefile->GetDefinition(
319
0
        cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_OBJECT_FILE_FLAG"))) {
320
0
    this->ObjLinkFileFlag = *flag;
321
0
  } else {
322
0
    this->ObjLinkFileFlag =
323
0
      this->Makefile->GetSafeDefinition("CMAKE_LINK_OBJECT_FILE_FLAG");
324
0
  }
325
326
  // Get options needed to specify RPATHs.
327
0
  this->RuntimeUseChrpath = false;
328
0
  if (this->Target->GetType() != cm::TargetType::STATIC_LIBRARY) {
329
0
    char const* tType =
330
0
      ((this->Target->GetType() == cm::TargetType::EXECUTABLE)
331
0
         ? "EXECUTABLE"
332
0
         : "SHARED_LIBRARY");
333
0
    std::string rtVar =
334
0
      cmStrCat("CMAKE_", tType, "_RUNTIME_", this->LinkLanguage, "_FLAG");
335
0
    std::string rtSepVar = cmStrCat(rtVar, "_SEP");
336
0
    this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
337
0
    this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
338
0
    this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
339
0
      "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
340
341
0
    this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
342
343
    // Get options needed to help find dependent libraries.
344
0
    std::string rlVar =
345
0
      cmStrCat("CMAKE_", tType, "_RPATH_LINK_", this->LinkLanguage, "_FLAG");
346
0
    this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
347
0
  }
348
349
  // Check if we need to include the runtime search path at link time.
350
0
  {
351
0
    std::string var = cmStrCat("CMAKE_SHARED_LIBRARY_LINK_",
352
0
                               this->LinkLanguage, "_WITH_RUNTIME_PATH");
353
0
    this->LinkWithRuntimePath = this->Makefile->IsOn(var);
354
0
  }
355
356
  // Define some Feature descriptors to handle standard library and object link
357
0
  if (!this->GetLibLinkFileFlag().empty()) {
358
0
    this->LibraryFeatureDescriptors.emplace(
359
0
      "__CMAKE_LINK_LIBRARY",
360
0
      LibraryFeatureDescriptor{
361
0
        "__CMAKE_LINK_LIBRARY",
362
0
        cmStrCat(this->GetLibLinkFileFlag(), "<LIBRARY>") });
363
0
  }
364
0
  if (!this->GetObjLinkFileFlag().empty()) {
365
0
    this->LibraryFeatureDescriptors.emplace(
366
0
      "__CMAKE_LINK_OBJECT",
367
0
      LibraryFeatureDescriptor{
368
0
        "__CMAKE_LINK_OBJECT",
369
0
        cmStrCat(this->GetObjLinkFileFlag(), "<LIBRARY>") });
370
0
  }
371
0
  if (!this->LoaderFlag->empty()) {
372
    // Define a Feature descriptor for the link of an executable with exports
373
0
    this->LibraryFeatureDescriptors.emplace(
374
0
      "__CMAKE_LINK_EXECUTABLE",
375
0
      LibraryFeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE",
376
0
                                cmStrCat(*this->LoaderFlag, "<LIBRARY>") });
377
0
  }
378
  // To link framework using a full path
379
0
  this->LibraryFeatureDescriptors.emplace(
380
0
    "__CMAKE_LINK_FRAMEWORK",
381
0
    LibraryFeatureDescriptor{ "__CMAKE_LINK_FRAMEWORK", "<LIBRARY>" });
382
  // To link xcframework using a full path
383
0
  this->LibraryFeatureDescriptors.emplace(
384
0
    "__CMAKE_LINK_XCFRAMEWORK",
385
0
    LibraryFeatureDescriptor{ "__CMAKE_LINK_XCFRAMEWORK", "<LIBRARY>" });
386
387
  // Check the platform policy for missing soname case.
388
0
  this->NoSONameUsesPath =
389
0
    this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
390
391
  // Get link type information.
392
0
  this->ComputeLinkTypeInfo();
393
394
  // Setup the link item parser.
395
0
  this->ComputeItemParserInfo();
396
397
  // Setup framework support.
398
0
  this->ComputeFrameworkInfo();
399
400
  // Choose a mode for dealing with shared library dependencies.
401
0
  this->SharedDependencyMode = SharedDepModeNone;
402
0
  if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
403
0
    this->SharedDependencyMode = SharedDepModeLink;
404
0
  } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
405
0
    this->SharedDependencyMode = SharedDepModeLibDir;
406
0
  } else if (!this->RPathLinkFlag.empty()) {
407
0
    this->SharedDependencyMode = SharedDepModeDir;
408
0
    this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>(
409
0
      this->GlobalGenerator, target, "dependent library path");
410
0
  }
411
412
  // Add the search path entries requested by the user to path ordering.
413
0
  std::vector<std::string> directories;
414
0
  this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
415
0
  this->OrderLinkerSearchPath->AddUserDirectories(directories);
416
0
  this->OrderRuntimeSearchPath->AddUserDirectories(directories);
417
418
  // Set up the implicit link directories.
419
0
  this->LoadImplicitLinkInfo();
420
0
  this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
421
0
  this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
422
0
  if (this->OrderDependentRPath) {
423
0
    this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
424
0
    this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
425
0
  }
426
0
}
427
428
0
cmComputeLinkInformation::~cmComputeLinkInformation() = default;
429
430
namespace {
431
std::string const& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT;
432
}
433
434
void cmComputeLinkInformation::AppendValues(
435
  std::string& result, std::vector<BT<std::string>>& values)
436
0
{
437
0
  for (BT<std::string>& p : values) {
438
0
    if (result.empty()) {
439
0
      result.append(" ");
440
0
    }
441
442
0
    result.append(p.Value);
443
0
  }
444
0
}
445
446
cmComputeLinkInformation::ItemVector const&
447
cmComputeLinkInformation::GetItems() const
448
0
{
449
0
  return this->Items;
450
0
}
451
452
std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
453
  const
454
0
{
455
0
  return this->OrderLinkerSearchPath->GetOrderedDirectories();
456
0
}
457
458
std::vector<BT<std::string>>
459
cmComputeLinkInformation::GetDirectoriesWithBacktraces()
460
0
{
461
0
  std::vector<BT<std::string>> directoriesWithBacktraces;
462
463
0
  std::vector<BT<std::string>> targetLinkDirectories =
464
0
    this->Target->GetLinkDirectories(this->Config, this->LinkLanguage);
465
466
0
  std::vector<std::string> const& orderedDirectories = this->GetDirectories();
467
0
  for (std::string const& dir : orderedDirectories) {
468
0
    auto result = std::find(targetLinkDirectories.begin(),
469
0
                            targetLinkDirectories.end(), dir);
470
0
    if (result != targetLinkDirectories.end()) {
471
0
      directoriesWithBacktraces.emplace_back(std::move(*result));
472
0
    } else {
473
0
      directoriesWithBacktraces.emplace_back(dir);
474
0
    }
475
0
  }
476
477
0
  return directoriesWithBacktraces;
478
0
}
479
480
std::string cmComputeLinkInformation::GetRPathLinkString() const
481
0
{
482
  // If there is no separate linker runtime search flag (-rpath-link)
483
  // there is no reason to compute a string.
484
0
  if (!this->OrderDependentRPath) {
485
0
    return "";
486
0
  }
487
488
  // Construct the linker runtime search path. These MUST NOT contain tokens
489
  // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
490
0
  return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
491
0
}
492
493
std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const
494
0
{
495
0
  return this->Depends;
496
0
}
497
498
std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
499
  const
500
0
{
501
0
  return this->FrameworkPaths;
502
0
}
503
504
std::set<std::string> const&
505
cmComputeLinkInformation::GetFrameworkPathsEmitted() const
506
0
{
507
0
  return this->FrameworkPathsEmitted;
508
0
}
509
510
std::vector<std::string> const&
511
cmComputeLinkInformation::GetXcFrameworkHeaderPaths() const
512
0
{
513
0
  return this->XcFrameworkHeaderPaths;
514
0
}
515
516
std::set<cmGeneratorTarget const*> const&
517
cmComputeLinkInformation::GetSharedLibrariesLinked() const
518
0
{
519
0
  return this->SharedLibrariesLinked;
520
0
}
521
522
std::vector<cmGeneratorTarget const*> const&
523
cmComputeLinkInformation::GetExternalObjectTargets() const
524
0
{
525
0
  return this->ExternalObjectTargets;
526
0
}
527
528
bool cmComputeLinkInformation::Compute()
529
0
{
530
  // Skip targets that do not link or have link-like information consumers may
531
  // need (namely modules).
532
0
  if (!(this->Target->GetType() == cm::TargetType::EXECUTABLE ||
533
0
        this->Target->GetType() == cm::TargetType::SHARED_LIBRARY ||
534
0
        this->Target->GetType() == cm::TargetType::MODULE_LIBRARY ||
535
0
        this->Target->GetType() == cm::TargetType::STATIC_LIBRARY ||
536
0
        (this->Target->CanCompileSources() &&
537
0
         (this->Target->HaveCxxModuleSupport(this->Config) ==
538
0
            cmGeneratorTarget::Cxx20SupportLevel::Supported ||
539
0
          this->Target->HaveFortranSources())))) {
540
0
    return false;
541
0
  }
542
543
  // We require a link language for the target.
544
0
  if (this->LinkLanguage.empty()) {
545
0
    cmSystemTools::Error(
546
0
      "CMake can not determine linker language for target: " +
547
0
      this->Target->GetName());
548
0
    return false;
549
0
  }
550
551
0
  LinkLibrariesStrategy strategy = LinkLibrariesStrategy::REORDER_MINIMALLY;
552
0
  if (cmValue s = this->Target->GetProperty("LINK_LIBRARIES_STRATEGY")) {
553
0
    if (*s == "REORDER_MINIMALLY"_s) {
554
0
      strategy = LinkLibrariesStrategy::REORDER_MINIMALLY;
555
0
    } else if (*s == "REORDER_FREELY"_s) {
556
0
      strategy = LinkLibrariesStrategy::REORDER_FREELY;
557
0
    } else {
558
0
      this->CMakeInstance->IssueMessage(
559
0
        MessageType::FATAL_ERROR,
560
0
        cmStrCat("LINK_LIBRARIES_STRATEGY value '", *s,
561
0
                 "' is not recognized."),
562
0
        this->Target->GetBacktrace());
563
0
      return false;
564
0
    }
565
0
  }
566
567
  // Compute the ordered link line items.
568
0
  cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage,
569
0
                           strategy);
570
0
  cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
571
0
  FeatureDescriptor const* currentFeature = nullptr;
572
573
  // Add the link line items.
574
0
  for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) {
575
0
    if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::Group) {
576
0
      auto const& groupFeature = this->GetGroupFeature(linkEntry.Feature);
577
0
      if (groupFeature.Supported) {
578
0
        if (linkEntry.Item.Value == "</LINK_GROUP>" && currentFeature) {
579
          // emit feature suffix, if any
580
0
          if (!currentFeature->Suffix.empty()) {
581
0
            this->Items.emplace_back(
582
0
              BT<std::string>{ currentFeature->Suffix,
583
0
                               this->Items.back().Value.Backtrace },
584
0
              ItemIsPath::No);
585
0
          }
586
0
          currentFeature = nullptr;
587
0
        }
588
0
        this->Items.emplace_back(
589
0
          BT<std::string>{ linkEntry.Item.Value == "<LINK_GROUP>"
590
0
                             ? groupFeature.Prefix
591
0
                             : groupFeature.Suffix,
592
0
                           linkEntry.Item.Backtrace },
593
0
          ItemIsPath::No);
594
0
      }
595
0
      continue;
596
0
    }
597
598
0
    if (currentFeature && linkEntry.Feature != currentFeature->Name) {
599
      // emit feature suffix, if any
600
0
      if (!currentFeature->Suffix.empty()) {
601
0
        this->Items.emplace_back(
602
0
          BT<std::string>{ currentFeature->Suffix,
603
0
                           this->Items.back().Value.Backtrace },
604
0
          ItemIsPath::No);
605
0
      }
606
0
      currentFeature = nullptr;
607
0
    }
608
609
0
    if (linkEntry.Feature != DEFAULT &&
610
0
        (!currentFeature || linkEntry.Feature != currentFeature->Name)) {
611
0
      if (!this->AddLibraryFeature(linkEntry.Feature)) {
612
0
        continue;
613
0
      }
614
0
      currentFeature = this->FindLibraryFeature(linkEntry.Feature);
615
      // emit feature prefix, if any
616
0
      if (!currentFeature->Prefix.empty()) {
617
0
        this->Items.emplace_back(
618
0
          BT<std::string>{ currentFeature->Prefix, linkEntry.Item.Backtrace },
619
0
          ItemIsPath::No);
620
0
      }
621
0
    }
622
623
0
    if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::SharedDep) {
624
0
      this->AddSharedDepItem(linkEntry);
625
0
    } else {
626
0
      this->AddItem(linkEntry);
627
0
    }
628
0
  }
629
630
0
  if (currentFeature) {
631
    // emit feature suffix, if any
632
0
    if (!currentFeature->Suffix.empty()) {
633
0
      this->Items.emplace_back(
634
0
        BT<std::string>{ currentFeature->Suffix,
635
0
                         this->Items.back().Value.Backtrace },
636
0
        ItemIsPath::No);
637
0
    }
638
0
  }
639
640
  // Restore the target link type so the correct system runtime
641
  // libraries are found.
642
0
  cmValue lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
643
0
  if (lss.IsOn()) {
644
0
    this->SetCurrentLinkType(LinkStatic);
645
0
  } else {
646
0
    this->SetCurrentLinkType(this->StartLinkType);
647
0
  }
648
649
  // Add implicit language runtime libraries and directories.
650
0
  this->AddImplicitLinkInfo();
651
652
  // Record targets referenced by $<TARGET_OBJECTS:...> sources.
653
0
  this->AddExternalObjectTargets();
654
655
0
  return true;
656
0
}
657
658
namespace {
659
void FinalizeFeatureFormat(std::string& format, std::string const& activeTag,
660
                           std::string const& otherTag)
661
0
{
662
0
  auto pos = format.find(otherTag);
663
0
  if (pos != std::string::npos) {
664
0
    format.erase(pos, format.find('}', pos) - pos + 1);
665
0
  }
666
0
  pos = format.find(activeTag);
667
0
  if (pos != std::string::npos) {
668
0
    format.erase(pos, activeTag.length());
669
0
    pos = format.find('}', pos);
670
0
    if (pos != std::string::npos) {
671
0
      format.erase(pos, 1);
672
0
    }
673
0
  }
674
0
}
675
676
bool IsValidFeatureFormat(std::string const& format)
677
0
{
678
0
  return format.find("<LIBRARY>") != std::string::npos ||
679
0
    format.find("<LIB_ITEM>") != std::string::npos ||
680
0
    format.find("<LINK_ITEM>") != std::string::npos;
681
0
}
682
683
class FeaturePlaceHolderExpander : public cmPlaceholderExpander
684
{
685
public:
686
  FeaturePlaceHolderExpander(std::string const* library,
687
                             std::string const* libItem = nullptr,
688
                             std::string const* linkItem = nullptr)
689
0
    : Library(library)
690
0
    , LibItem(libItem)
691
0
    , LinkItem(linkItem)
692
0
  {
693
0
  }
694
695
private:
696
  std::string ExpandVariable(std::string const& variable) override
697
0
  {
698
0
    if (this->Library && variable == "LIBRARY") {
699
0
      return *this->Library;
700
0
    }
701
0
    if (this->LibItem && variable == "LIB_ITEM") {
702
0
      return *this->LibItem;
703
0
    }
704
0
    if (this->LinkItem && variable == "LINK_ITEM") {
705
0
      return *this->LinkItem;
706
0
    }
707
708
0
    return variable;
709
0
  }
710
711
  std::string const* Library = nullptr;
712
  std::string const* LibItem = nullptr;
713
  std::string const* LinkItem = nullptr;
714
};
715
}
716
717
cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
718
  std::string name, std::string itemFormat)
719
0
  : Name(std::move(name))
720
0
  , Supported(true)
721
0
  , ItemPathFormat(std::move(itemFormat))
722
0
  , ItemNameFormat(this->ItemPathFormat)
723
0
{
724
0
}
725
cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
726
  std::string name, std::string itemPathFormat, std::string itemNameFormat)
727
0
  : Name(std::move(name))
728
0
  , Supported(true)
729
0
  , ItemPathFormat(std::move(itemPathFormat))
730
0
  , ItemNameFormat(std::move(itemNameFormat))
731
0
{
732
0
}
733
cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
734
  std::string name, std::string prefix, std::string itemPathFormat,
735
  std::string itemNameFormat, std::string suffix)
736
0
  : Name(std::move(name))
737
0
  , Supported(true)
738
0
  , Prefix(std::move(prefix))
739
0
  , Suffix(std::move(suffix))
740
0
  , ItemPathFormat(std::move(itemPathFormat))
741
0
  , ItemNameFormat(std::move(itemNameFormat))
742
0
{
743
0
}
744
cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
745
  std::string name, std::string prefix, std::string suffix, bool)
746
0
  : Name(std::move(name))
747
0
  , Supported(true)
748
0
  , Prefix(std::move(prefix))
749
0
  , Suffix(std::move(suffix))
750
0
{
751
0
}
752
753
std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
754
  std::string const& library, ItemIsPath isPath) const
755
0
{
756
0
  auto format =
757
0
    isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
758
759
  // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns with library path
760
0
  FeaturePlaceHolderExpander expander(&library, &library, &library);
761
0
  return expander.ExpandVariables(format);
762
0
}
763
std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
764
  std::string const& library, std::string const& libItem,
765
  std::string const& linkItem, ItemIsPath isPath) const
766
0
{
767
0
  auto format =
768
0
    isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
769
770
  // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns
771
0
  FeaturePlaceHolderExpander expander(&library, &libItem, &linkItem);
772
0
  return expander.ExpandVariables(format);
773
0
}
774
775
cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
776
  std::string name, std::string itemFormat)
777
0
  : FeatureDescriptor(std::move(name), std::move(itemFormat))
778
0
{
779
0
}
780
cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
781
  std::string name, std::string itemPathFormat, std::string itemNameFormat)
782
0
  : FeatureDescriptor(std::move(name), std::move(itemPathFormat),
783
0
                      std::move(itemNameFormat))
784
0
{
785
0
}
786
cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
787
  std::string name, std::string prefix, std::string itemPathFormat,
788
  std::string itemNameFormat, std::string suffix)
789
0
  : FeatureDescriptor(std::move(name), std::move(prefix),
790
0
                      std::move(itemPathFormat), std::move(itemNameFormat),
791
0
                      std::move(suffix))
792
0
{
793
0
}
794
795
bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature)
796
0
{
797
0
  auto it = this->LibraryFeatureDescriptors.find(feature);
798
0
  if (it != this->LibraryFeatureDescriptors.end()) {
799
0
    return it->second.Supported;
800
0
  }
801
802
0
  auto featureName =
803
0
    cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_USING_", feature);
804
0
  cmValue featureSupported =
805
0
    this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
806
0
  if (!featureSupported) {
807
    // language specific variable is not defined, fallback to the more generic
808
    // one
809
0
    featureName = cmStrCat("CMAKE_LINK_LIBRARY_USING_", feature);
810
0
    featureSupported =
811
0
      this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
812
0
  }
813
0
  if (!featureSupported.IsOn()) {
814
0
    this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
815
816
0
    this->CMakeInstance->IssueMessage(
817
0
      MessageType::FATAL_ERROR,
818
0
      cmStrCat(
819
0
        "Feature '", feature,
820
0
        "', specified through generator-expression '$<LINK_LIBRARY>' to "
821
0
        "link target '",
822
0
        this->Target->GetName(), "', is not supported for the '",
823
0
        this->LinkLanguage, "' link language."),
824
0
      this->Target->GetBacktrace());
825
826
0
    return false;
827
0
  }
828
829
0
  cmValue langFeature = this->Makefile->GetDefinition(featureName);
830
0
  if (!langFeature) {
831
0
    this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
832
833
0
    this->CMakeInstance->IssueMessage(
834
0
      MessageType::FATAL_ERROR,
835
0
      cmStrCat(
836
0
        "Feature '", feature,
837
0
        "', specified through generator-expression '$<LINK_LIBRARY>' to "
838
0
        "link target '",
839
0
        this->Target->GetName(), "', is not defined for the '",
840
0
        this->LinkLanguage, "' link language."),
841
0
      this->Target->GetBacktrace());
842
843
0
    return false;
844
0
  }
845
846
0
  auto items = cmExpandListWithBacktrace(
847
0
    *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
848
849
0
  if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) ||
850
0
      (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) {
851
0
    this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
852
0
    this->CMakeInstance->IssueMessage(
853
0
      MessageType::FATAL_ERROR,
854
0
      cmStrCat("Feature '", feature, "', specified by variable '", featureName,
855
0
               "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
856
0
               "\"<LINK_ITEM>\" patterns "
857
0
               "are missing) and cannot be used to link target '",
858
0
               this->Target->GetName(), "'."),
859
0
      this->Target->GetBacktrace());
860
861
0
    return false;
862
0
  }
863
864
  // now, handle possible "PATH{}" and "NAME{}" patterns
865
0
  if (items.size() == 1) {
866
0
    items.push_back(items.front());
867
0
    FinalizeFeatureFormat(items[0].Value, "PATH{", "NAME{");
868
0
    FinalizeFeatureFormat(items[1].Value, "NAME{", "PATH{");
869
0
  } else if (items.size() == 3) {
870
0
    items.insert(items.begin() + 1, items[1]);
871
0
    FinalizeFeatureFormat(items[1].Value, "PATH{", "NAME{");
872
0
    FinalizeFeatureFormat(items[2].Value, "NAME{", "PATH{");
873
0
  } else {
874
0
    this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
875
0
    this->CMakeInstance->IssueMessage(
876
0
      MessageType::FATAL_ERROR,
877
0
      cmStrCat("Feature '", feature, "', specified by variable '", featureName,
878
0
               "', is malformed (wrong number of elements) and cannot be used "
879
0
               "to link target '",
880
0
               this->Target->GetName(), "'."),
881
0
      this->Target->GetBacktrace());
882
883
0
    return false;
884
0
  }
885
0
  if ((items.size() == 2 && !IsValidFeatureFormat(items[0].Value)) ||
886
0
      (items.size() == 4 && !IsValidFeatureFormat(items[1].Value))) {
887
    // PATH{} has wrong format
888
0
    this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
889
0
    this->CMakeInstance->IssueMessage(
890
0
      MessageType::FATAL_ERROR,
891
0
      cmStrCat("Feature '", feature, "', specified by variable '", featureName,
892
0
               "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
893
0
               "\"<LINK_ITEM>\" patterns "
894
0
               "are missing for \"PATH{}\" alternative) and cannot be used to "
895
0
               "link target '",
896
0
               this->Target->GetName(), "'."),
897
0
      this->Target->GetBacktrace());
898
899
0
    return false;
900
0
  }
901
0
  if ((items.size() == 2 && !IsValidFeatureFormat(items[1].Value)) ||
902
0
      (items.size() == 4 && !IsValidFeatureFormat(items[2].Value))) {
903
    // NAME{} has wrong format
904
0
    this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
905
0
    this->CMakeInstance->IssueMessage(
906
0
      MessageType::FATAL_ERROR,
907
0
      cmStrCat("Feature '", feature, "', specified by variable '", featureName,
908
0
               "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
909
0
               "\"<LINK_ITEM>\" patterns "
910
0
               "are missing for \"NAME{}\" alternative) and cannot be used to "
911
0
               "link target '",
912
0
               this->Target->GetName(), "'."),
913
0
      this->Target->GetBacktrace());
914
915
0
    return false;
916
0
  }
917
918
  // replace LINKER: pattern
919
0
  this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
920
921
0
  if (items.size() == 2) {
922
0
    this->LibraryFeatureDescriptors.emplace(
923
0
      feature,
924
0
      LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value });
925
0
  } else {
926
0
    this->LibraryFeatureDescriptors.emplace(
927
0
      feature,
928
0
      LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value,
929
0
                                items[2].Value, items[3].Value });
930
0
  }
931
932
0
  return true;
933
0
}
934
935
cmComputeLinkInformation::FeatureDescriptor const&
936
cmComputeLinkInformation::GetLibraryFeature(std::string const& feature) const
937
0
{
938
0
  return this->LibraryFeatureDescriptors.find(feature)->second;
939
0
}
940
cmComputeLinkInformation::FeatureDescriptor const*
941
cmComputeLinkInformation::FindLibraryFeature(std::string const& feature) const
942
0
{
943
0
  auto it = this->LibraryFeatureDescriptors.find(feature);
944
0
  if (it == this->LibraryFeatureDescriptors.end()) {
945
0
    return nullptr;
946
0
  }
947
948
0
  return &it->second;
949
0
}
950
951
cmComputeLinkInformation::GroupFeatureDescriptor::GroupFeatureDescriptor(
952
  std::string name, std::string prefix, std::string suffix)
953
0
  : FeatureDescriptor(std::move(name), std::move(prefix), std::move(suffix),
954
0
                      true)
955
0
{
956
0
}
957
958
cmComputeLinkInformation::FeatureDescriptor const&
959
cmComputeLinkInformation::GetGroupFeature(std::string const& feature)
960
0
{
961
0
  auto it = this->GroupFeatureDescriptors.find(feature);
962
0
  if (it != this->GroupFeatureDescriptors.end()) {
963
0
    return it->second;
964
0
  }
965
966
0
  auto featureName =
967
0
    cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_GROUP_USING_", feature);
968
0
  cmValue featureSupported =
969
0
    this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
970
0
  if (!featureSupported) {
971
    // language specific variable is not defined, fallback to the more generic
972
    // one
973
0
    featureName = cmStrCat("CMAKE_LINK_GROUP_USING_", feature);
974
0
    featureSupported =
975
0
      this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
976
0
  }
977
0
  if (!featureSupported.IsOn()) {
978
0
    this->CMakeInstance->IssueMessage(
979
0
      MessageType::FATAL_ERROR,
980
0
      cmStrCat("Feature '", feature,
981
0
               "', specified through generator-expression '$<LINK_GROUP>' to "
982
0
               "link target '",
983
0
               this->Target->GetName(), "', is not supported for the '",
984
0
               this->LinkLanguage, "' link language."),
985
0
      this->Target->GetBacktrace());
986
0
    return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
987
0
      .first->second;
988
0
  }
989
990
0
  cmValue langFeature = this->Makefile->GetDefinition(featureName);
991
0
  if (!langFeature) {
992
0
    this->CMakeInstance->IssueMessage(
993
0
      MessageType::FATAL_ERROR,
994
0
      cmStrCat("Feature '", feature,
995
0
               "', specified through generator-expression '$<LINK_GROUP>' to "
996
0
               "link target '",
997
0
               this->Target->GetName(), "', is not defined for the '",
998
0
               this->LinkLanguage, "' link language."),
999
0
      this->Target->GetBacktrace());
1000
0
    return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1001
0
      .first->second;
1002
0
  }
1003
1004
0
  auto items = cmExpandListWithBacktrace(
1005
0
    *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
1006
1007
  // replace LINKER: pattern
1008
0
  this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
1009
1010
0
  if (items.size() == 2) {
1011
0
    return this->GroupFeatureDescriptors
1012
0
      .emplace(
1013
0
        feature,
1014
0
        GroupFeatureDescriptor{ feature, items[0].Value, items[1].Value })
1015
0
      .first->second;
1016
0
  }
1017
1018
0
  this->CMakeInstance->IssueMessage(
1019
0
    MessageType::FATAL_ERROR,
1020
0
    cmStrCat("Feature '", feature, "', specified by variable '", featureName,
1021
0
             "', is malformed (wrong number of elements) and cannot be used "
1022
0
             "to link target '",
1023
0
             this->Target->GetName(), "'."),
1024
0
    this->Target->GetBacktrace());
1025
0
  return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1026
0
    .first->second;
1027
0
}
1028
1029
void cmComputeLinkInformation::AddExternalObjectTargets()
1030
0
{
1031
0
  std::vector<cmSourceFile const*> externalObjects;
1032
0
  this->Target->GetExternalObjects(externalObjects, this->Config);
1033
0
  std::set<std::string> emitted;
1034
0
  for (auto const* externalObject : externalObjects) {
1035
0
    std::string const& objLib = externalObject->GetObjectLibrary();
1036
0
    if (objLib.empty()) {
1037
0
      continue;
1038
0
    }
1039
0
    if (emitted.insert(objLib).second) {
1040
0
      cmLinkItem const& objItem =
1041
0
        this->Target->ResolveLinkItem(BT<std::string>(objLib));
1042
0
      if (objItem.Target) {
1043
0
        this->ExternalObjectTargets.emplace_back(objItem.Target);
1044
0
      }
1045
0
    }
1046
0
  }
1047
0
}
1048
1049
void cmComputeLinkInformation::AddImplicitLinkInfo()
1050
0
{
1051
  // The link closure lists all languages whose implicit info is needed.
1052
0
  cmGeneratorTarget::LinkClosure const* lc =
1053
0
    this->Target->GetLinkClosure(this->Config);
1054
0
  for (std::string const& li : lc->Languages) {
1055
1056
0
    if (li == "CUDA" || li == "HIP") {
1057
      // These need to go before the other implicit link information
1058
      // as they could require symbols from those other library
1059
      // Currently restricted as CUDA and HIP are the only languages
1060
      // we have documented runtime behavior controls for
1061
0
      this->AddRuntimeLinkLibrary(li);
1062
0
    }
1063
1064
    // Skip those of the linker language.  They are implicit.
1065
0
    if (li != this->LinkLanguage) {
1066
0
      this->AddImplicitLinkInfo(li);
1067
0
    }
1068
0
  }
1069
0
}
1070
1071
void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
1072
0
{
1073
0
  std::string const& runtimeLibrary =
1074
0
    this->Target->GetRuntimeLinkLibrary(lang, this->Config);
1075
0
  if (runtimeLibrary.empty()) {
1076
0
    return;
1077
0
  }
1078
0
  if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(cmStrCat(
1079
0
        "CMAKE_", lang, "_RUNTIME_LIBRARY_LINK_OPTIONS_", runtimeLibrary))) {
1080
0
    cmList libs{ *runtimeLinkOptions };
1081
0
    for (auto const& i : libs) {
1082
0
      if (!cm::contains(this->ImplicitLinkLibs, i)) {
1083
0
        this->AddItem({ i });
1084
0
      }
1085
0
    }
1086
0
  }
1087
0
}
1088
1089
namespace {
1090
std::string const gcc_s = "gcc_s";
1091
std::string const gcc_s_asneeded = "gcc_s_asneeded";
1092
}
1093
1094
void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
1095
0
{
1096
0
  auto const impliedByLinkerLanguage = [this](std::string const& lib) -> bool {
1097
0
    if (cm::contains(this->ImplicitLinkLibs, lib)) {
1098
0
      return true;
1099
0
    }
1100
    // As of GCC 16, `gcc` implies `gcc_s_asneeded` but `g++` implies `gcc_s`.
1101
    // Accept them interchangeably when linking mixed C and C++ binaries.
1102
0
    if ((lib == gcc_s_asneeded &&
1103
0
         cm::contains(this->ImplicitLinkLibs, gcc_s)) ||
1104
0
        (lib == gcc_s &&
1105
0
         cm::contains(this->ImplicitLinkLibs, gcc_s_asneeded))) {
1106
0
      return true;
1107
0
    }
1108
0
    return false;
1109
0
  };
1110
1111
  // Add libraries for this language that are not implied by the
1112
  // linker language.
1113
0
  std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
1114
0
  if (cmValue libs = this->Makefile->GetDefinition(libVar)) {
1115
0
    cmList libsList{ *libs };
1116
0
    for (std::string const& i : libsList) {
1117
0
      if (!impliedByLinkerLanguage(i)) {
1118
0
        this->AddItem({ i });
1119
0
      }
1120
0
    }
1121
0
  }
1122
1123
  // Add linker search paths for this language that are not
1124
  // implied by the linker language.
1125
0
  std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
1126
0
  if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
1127
0
    cmList dirsList{ *dirs };
1128
0
    this->OrderLinkerSearchPath->AddLanguageDirectories(dirsList);
1129
0
  }
1130
0
}
1131
1132
void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
1133
0
{
1134
0
  cmGeneratorTarget const* tgt = entry.Target;
1135
0
  BT<std::string> const& item = entry.Item;
1136
1137
  // Compute the proper name to use to link this library.
1138
0
  std::string const& config = this->Config;
1139
0
  bool impexe = (tgt && tgt->IsExecutableWithExports());
1140
0
  if (impexe && !tgt->HasImportLibrary(config) && !this->LoaderFlag) {
1141
    // Skip linking to executables on platforms with no import
1142
    // libraries or loader flags.
1143
0
    return;
1144
0
  }
1145
1146
0
  if (tgt && tgt->IsLinkable()) {
1147
    // This is a CMake target.  Ask the target for its real name.
1148
0
    if (impexe && this->LoaderFlag) {
1149
      // This link item is an executable that may provide symbols
1150
      // used by this target.  A special flag is needed on this
1151
      // platform.  Add it now using a special feature.
1152
0
      cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
1153
0
        ? cmStateEnums::ImportLibraryArtifact
1154
0
        : cmStateEnums::RuntimeBinaryArtifact;
1155
0
      std::string exe = tgt->GetFullPath(config, artifact, true);
1156
0
      this->Items.emplace_back(
1157
0
        BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt, nullptr,
1158
0
        this->FindLibraryFeature(entry.Feature == DEFAULT
1159
0
                                   ? "__CMAKE_LINK_EXECUTABLE"
1160
0
                                   : entry.Feature));
1161
0
      this->Depends.push_back(std::move(exe));
1162
0
    } else if (tgt->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
1163
      // Add the interface library as an item so it can be considered as part
1164
      // of COMPATIBLE_INTERFACE_ enforcement.  The generators will ignore
1165
      // this for the actual link line.
1166
0
      this->Items.emplace_back(std::string(), ItemIsPath::No, tgt);
1167
1168
      // Also add the item the interface specifies to be used in its place.
1169
0
      std::string const& libName = tgt->GetImportedLibName(config);
1170
0
      if (!libName.empty()) {
1171
0
        this->AddItem(BT<std::string>(libName, item.Backtrace));
1172
0
      }
1173
0
    } else if (tgt->GetType() == cm::TargetType::OBJECT_LIBRARY) {
1174
0
      this->Items.emplace_back(item, ItemIsPath::No, tgt);
1175
0
    } else if (this->GlobalGenerator->IsXcode() &&
1176
0
               !tgt->GetImportedXcFrameworkPath(config).empty()) {
1177
0
      this->Items.emplace_back(
1178
0
        tgt->GetImportedXcFrameworkPath(config), ItemIsPath::Yes, tgt, nullptr,
1179
0
        this->FindLibraryFeature(entry.Feature == DEFAULT
1180
0
                                   ? "__CMAKE_LINK_XCFRAMEWORK"
1181
0
                                   : entry.Feature));
1182
0
    } else {
1183
      // Decide whether to use an import library.
1184
0
      cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
1185
0
        ? cmStateEnums::ImportLibraryArtifact
1186
0
        : cmStateEnums::RuntimeBinaryArtifact;
1187
1188
      // Pass the full path to the target file.
1189
0
      BT<std::string> lib = BT<std::string>(
1190
0
        tgt->GetFullPath(config, artifact, true), item.Backtrace);
1191
0
      if (tgt->IsAIX() && cmHasLiteralSuffix(lib.Value, "-NOTFOUND") &&
1192
0
          artifact == cmStateEnums::ImportLibraryArtifact) {
1193
        // This is an imported executable on AIX that has ENABLE_EXPORTS
1194
        // but not IMPORTED_IMPLIB.  CMake used to produce and accept such
1195
        // imported executables on AIX before we taught it to use linker
1196
        // import files.  For compatibility, simply skip linking to this
1197
        // executable as we did before.  It works with runtime linking.
1198
0
        return;
1199
0
      }
1200
0
      if (!this->LinkDependsNoShared ||
1201
0
          tgt->GetType() != cm::TargetType::SHARED_LIBRARY) {
1202
0
        this->Depends.push_back(lib.Value);
1203
0
      }
1204
1205
0
      LinkEntry libEntry{ entry };
1206
0
      libEntry.Item = lib;
1207
0
      this->AddTargetItem(libEntry);
1208
0
      if (tgt->IsApple() && tgt->HasImportLibrary(config)) {
1209
        // Use the library rather than the tbd file for runpath computation
1210
0
        this->AddLibraryRuntimeInfo(
1211
0
          tgt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, true),
1212
0
          tgt);
1213
0
      } else {
1214
0
        this->AddLibraryRuntimeInfo(lib.Value, tgt);
1215
0
      }
1216
0
      if (tgt && tgt->GetType() == cm::TargetType::SHARED_LIBRARY &&
1217
0
          this->Target->IsDLLPlatform()) {
1218
0
        this->AddRuntimeDLL(tgt);
1219
0
      }
1220
0
    }
1221
1222
0
    auto xcFrameworkPath = tgt->GetImportedXcFrameworkPath(config);
1223
0
    if (!xcFrameworkPath.empty()) {
1224
0
      auto plist = cmParseXcFrameworkPlist(xcFrameworkPath, *this->Makefile,
1225
0
                                           item.Backtrace);
1226
0
      if (!plist) {
1227
0
        return;
1228
0
      }
1229
0
      if (auto const* library =
1230
0
            plist->SelectSuitableLibrary(*this->Makefile, item.Backtrace)) {
1231
0
        if (!library->HeadersPath.empty()) {
1232
0
          this->AddXcFrameworkHeaderPath(cmStrCat(xcFrameworkPath, '/',
1233
0
                                                  library->LibraryIdentifier,
1234
0
                                                  '/', library->HeadersPath));
1235
0
        }
1236
0
      } else {
1237
0
        return;
1238
0
      }
1239
0
    }
1240
0
  } else {
1241
    // This is not a CMake target.  Use the name given.
1242
0
    if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) ||
1243
0
        (entry.Feature == DEFAULT &&
1244
0
         cmSystemTools::IsPathToFramework(item.Value) &&
1245
0
         this->Target->IsApple())) {
1246
      // This is a framework.
1247
0
      this->AddFrameworkItem(entry);
1248
0
    } else if (cmHasSuffix(entry.Feature, "XCFRAMEWORK"_s) ||
1249
0
               (entry.Feature == DEFAULT &&
1250
0
                cmSystemTools::IsPathToXcFramework(item.Value) &&
1251
0
                this->Target->IsApple())) {
1252
      // This is a framework.
1253
0
      this->AddXcFrameworkItem(entry);
1254
0
    } else if (cmSystemTools::FileIsFullPath(item.Value)) {
1255
0
      if (cmSystemTools::FileIsDirectory(item.Value)) {
1256
        // This is a directory.
1257
0
        this->DropDirectoryItem(item);
1258
0
      } else {
1259
        // Use the full path given to the library file.
1260
0
        this->Depends.push_back(item.Value);
1261
0
        this->AddFullItem(entry);
1262
0
        this->AddLibraryRuntimeInfo(item.Value);
1263
0
      }
1264
0
    } else if (entry.Kind != cmComputeLinkDepends::LinkEntry::Object) {
1265
      // This is a library or option specified by the user.
1266
0
      this->AddUserItem(entry);
1267
0
    }
1268
0
  }
1269
0
}
1270
1271
void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry)
1272
0
{
1273
0
  BT<std::string> const& item = entry.Item;
1274
0
  cmGeneratorTarget const* tgt = entry.Target;
1275
1276
  // Record dependencies on DLLs.
1277
0
  if (tgt && tgt->GetType() == cm::TargetType::SHARED_LIBRARY &&
1278
0
      this->Target->IsDLLPlatform() &&
1279
0
      this->SharedDependencyMode != SharedDepModeLink) {
1280
0
    this->AddRuntimeDLL(tgt);
1281
0
  }
1282
1283
  // If dropping shared library dependencies, ignore them.
1284
0
  if (this->SharedDependencyMode == SharedDepModeNone) {
1285
0
    return;
1286
0
  }
1287
1288
  // The user may have incorrectly named an item.  Skip items that are
1289
  // not full paths to shared libraries.
1290
0
  if (tgt) {
1291
    // The target will provide a full path.  Make sure it is a shared
1292
    // library.
1293
0
    if (tgt->GetType() != cm::TargetType::SHARED_LIBRARY) {
1294
0
      return;
1295
0
    }
1296
0
  } else {
1297
    // Skip items that are not full paths.  We will not be able to
1298
    // reliably specify them.
1299
0
    if (!cmSystemTools::FileIsFullPath(item.Value)) {
1300
0
      return;
1301
0
    }
1302
1303
    // Get the name of the library from the file name.
1304
0
    std::string file = cmSystemTools::GetFilenameName(item.Value);
1305
0
    if (!this->ExtractSharedLibraryName.find(file)) {
1306
      // This is not the name of a shared library.
1307
0
      return;
1308
0
    }
1309
0
  }
1310
1311
  // If in linking mode, just link to the shared library.
1312
0
  if (this->SharedDependencyMode == SharedDepModeLink ||
1313
      // For an imported shared library without a known runtime artifact,
1314
      // such as a CUDA stub, a library file named with the real soname
1315
      // may not be available at all, so '-rpath-link' cannot help linkers
1316
      // find it to satisfy '--no-allow-shlib-undefined' recursively.
1317
      // Pass this dependency to the linker explicitly just in case.
1318
      // If the linker also uses '--as-needed' behavior, this will not
1319
      // add an unnecessary direct dependency.
1320
0
      (tgt && tgt->IsImported() &&
1321
0
       !tgt->HasKnownRuntimeArtifactLocation(this->Config) &&
1322
0
       this->Target->LinkerEnforcesNoAllowShLibUndefined(this->Config))) {
1323
0
    this->AddItem(entry);
1324
0
    return;
1325
0
  }
1326
1327
  // Get a full path to the dependent shared library.
1328
  // Add it to the runtime path computation so that the target being
1329
  // linked will be able to find it.
1330
0
  std::string lib;
1331
0
  if (tgt) {
1332
0
    cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
1333
0
      ? cmStateEnums::ImportLibraryArtifact
1334
0
      : cmStateEnums::RuntimeBinaryArtifact;
1335
0
    lib = tgt->GetFullPath(this->Config, artifact);
1336
0
    if (tgt->IsApple() && tgt->HasImportLibrary(this->Config)) {
1337
      // Use the library rather than the tbd file for runpath computation
1338
0
      this->AddLibraryRuntimeInfo(
1339
0
        tgt->GetFullPath(this->Config, cmStateEnums::RuntimeBinaryArtifact,
1340
0
                         true),
1341
0
        tgt);
1342
0
    } else {
1343
0
      this->AddLibraryRuntimeInfo(lib, tgt);
1344
0
    }
1345
0
  } else {
1346
0
    lib = item.Value;
1347
0
    this->AddLibraryRuntimeInfo(lib);
1348
0
  }
1349
1350
  // Check if we need to include the dependent shared library in other
1351
  // path ordering.
1352
0
  cmOrderDirectories* order = nullptr;
1353
0
  if (this->SharedDependencyMode == SharedDepModeLibDir &&
1354
0
      !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
1355
    // Add the item to the linker search path.
1356
0
    order = this->OrderLinkerSearchPath.get();
1357
0
  } else if (this->SharedDependencyMode == SharedDepModeDir) {
1358
    // Add the item to the separate dependent library search path.
1359
0
    order = this->OrderDependentRPath.get();
1360
0
  }
1361
0
  if (order) {
1362
0
    if (tgt) {
1363
0
      std::string soName = tgt->GetSOName(this->Config);
1364
0
      char const* soname = soName.empty() ? nullptr : soName.c_str();
1365
0
      order->AddRuntimeLibrary(lib, soname);
1366
0
    } else {
1367
0
      order->AddRuntimeLibrary(lib);
1368
0
    }
1369
0
  }
1370
0
}
1371
1372
void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
1373
0
{
1374
0
  if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
1375
0
      this->RuntimeDLLs.end()) {
1376
0
    this->RuntimeDLLs.emplace_back(tgt);
1377
0
  }
1378
0
}
1379
1380
void cmComputeLinkInformation::ComputeLinkTypeInfo()
1381
0
{
1382
  // Check whether archives may actually be shared libraries.
1383
0
  this->ArchivesMayBeShared =
1384
0
    this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1385
0
      "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
1386
1387
  // First assume we cannot do link type stuff.
1388
0
  this->LinkTypeEnabled = false;
1389
1390
  // Lookup link type selection flags.
1391
0
  cmValue static_link_type_flag = nullptr;
1392
0
  cmValue shared_link_type_flag = nullptr;
1393
0
  char const* target_type_str = nullptr;
1394
0
  switch (this->Target->GetType()) {
1395
0
    case cm::TargetType::EXECUTABLE:
1396
0
      target_type_str = "EXE";
1397
0
      break;
1398
0
    case cm::TargetType::SHARED_LIBRARY:
1399
0
      target_type_str = "SHARED_LIBRARY";
1400
0
      break;
1401
0
    case cm::TargetType::MODULE_LIBRARY:
1402
0
      target_type_str = "SHARED_MODULE";
1403
0
      break;
1404
0
    default:
1405
0
      break;
1406
0
  }
1407
0
  if (target_type_str) {
1408
0
    std::string static_link_type_flag_var =
1409
0
      cmStrCat("CMAKE_", target_type_str, "_LINK_STATIC_", this->LinkLanguage,
1410
0
               "_FLAGS");
1411
0
    static_link_type_flag =
1412
0
      this->Makefile->GetDefinition(static_link_type_flag_var);
1413
1414
0
    std::string shared_link_type_flag_var =
1415
0
      cmStrCat("CMAKE_", target_type_str, "_LINK_DYNAMIC_", this->LinkLanguage,
1416
0
               "_FLAGS");
1417
0
    shared_link_type_flag =
1418
0
      this->Makefile->GetDefinition(shared_link_type_flag_var);
1419
0
  }
1420
1421
  // We can support link type switching only if all needed flags are
1422
  // known.
1423
0
  if (cmNonempty(static_link_type_flag) && cmNonempty(shared_link_type_flag)) {
1424
0
    this->LinkTypeEnabled = true;
1425
0
    this->StaticLinkTypeFlag = *static_link_type_flag;
1426
0
    this->SharedLinkTypeFlag = *shared_link_type_flag;
1427
0
  }
1428
1429
  // Lookup the starting link type from the target (linked statically?).
1430
0
  cmValue lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
1431
0
  this->StartLinkType = lss.IsOn() ? LinkStatic : LinkShared;
1432
0
  this->CurrentLinkType = this->StartLinkType;
1433
0
}
1434
1435
void cmComputeLinkInformation::ComputeItemParserInfo()
1436
0
{
1437
  // Get possible library name prefixes.
1438
0
  cmMakefile* mf = this->Makefile;
1439
0
  this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
1440
0
  this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
1441
1442
  // Import library names should be matched and treated as shared
1443
  // libraries for the purposes of linking.
1444
0
  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
1445
0
                         LinkShared);
1446
0
  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
1447
0
                         LinkStatic);
1448
0
  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
1449
0
                         LinkShared);
1450
0
  this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
1451
0
                         LinkUnknown);
1452
0
  if (cmValue linkSuffixes =
1453
0
        mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
1454
0
    cmList linkSuffixList{ *linkSuffixes };
1455
0
    for (auto const& i : linkSuffixList) {
1456
0
      this->AddLinkExtension(i, LinkUnknown);
1457
0
    }
1458
0
  }
1459
0
  if (cmValue sharedSuffixes =
1460
0
        mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
1461
0
    cmList sharedSuffixList{ *sharedSuffixes };
1462
0
    for (std::string const& i : sharedSuffixList) {
1463
0
      this->AddLinkExtension(i, LinkShared);
1464
0
    }
1465
0
  }
1466
1467
  // Compute a regex to match link extensions.
1468
0
  std::string libext =
1469
0
    this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
1470
1471
  // Create regex to remove any library extension.
1472
0
  std::string reg("(.*)");
1473
0
  reg += libext;
1474
0
  this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
1475
1476
  // Create a regex to match a library name.  Match index 1 will be
1477
  // the prefix if it exists and empty otherwise.  Match index 2 will
1478
  // be the library name.  Match index 3 will be the library
1479
  // extension.
1480
0
  reg = "^(";
1481
0
  for (std::string const& p : this->LinkPrefixes) {
1482
0
    reg += p;
1483
0
    reg += '|';
1484
0
  }
1485
0
  reg += ")([^/:]*)";
1486
1487
  // Create a regex to match any library name.
1488
0
  std::string reg_any = cmStrCat(reg, libext);
1489
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
1490
  fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
1491
#endif
1492
0
  this->ExtractAnyLibraryName.compile(reg_any);
1493
1494
  // Create a regex to match static library names.
1495
0
  if (!this->StaticLinkExtensions.empty()) {
1496
0
    std::string reg_static = cmStrCat(
1497
0
      reg, this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic));
1498
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
1499
    fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
1500
#endif
1501
0
    this->ExtractStaticLibraryName.compile(reg_static);
1502
0
  }
1503
1504
  // Create a regex to match shared library names.
1505
0
  if (!this->SharedLinkExtensions.empty()) {
1506
0
    std::string reg_shared = reg;
1507
0
    this->SharedRegexString =
1508
0
      this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
1509
0
    reg_shared += this->SharedRegexString;
1510
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
1511
    fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
1512
#endif
1513
0
    this->ExtractSharedLibraryName.compile(reg_shared);
1514
0
  }
1515
0
}
1516
1517
void cmComputeLinkInformation::AddLinkPrefix(std::string const& p)
1518
0
{
1519
0
  if (!p.empty()) {
1520
0
    this->LinkPrefixes.insert(p);
1521
0
  }
1522
0
}
1523
1524
void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
1525
                                                LinkType type)
1526
0
{
1527
0
  if (!e.empty()) {
1528
0
    if (type == LinkStatic) {
1529
0
      this->StaticLinkExtensions.emplace_back(e);
1530
0
    }
1531
0
    if (type == LinkShared) {
1532
0
      this->SharedLinkExtensions.emplace_back(e);
1533
0
    }
1534
0
    this->LinkExtensions.emplace_back(e);
1535
0
  }
1536
0
}
1537
1538
// XXX(clang-tidy): This method's const-ness is platform dependent, so we
1539
// cannot make it `const` as `clang-tidy` wants us to.
1540
// NOLINTNEXTLINE(readability-make-member-function-const)
1541
std::string cmComputeLinkInformation::CreateExtensionRegex(
1542
  std::vector<std::string> const& exts, LinkType type)
1543
0
{
1544
  // Build a list of extension choices.
1545
0
  std::string libext = "(";
1546
0
  char const* sep = "";
1547
0
  for (std::string const& i : exts) {
1548
    // Separate this choice from the previous one.
1549
0
    libext += sep;
1550
0
    sep = "|";
1551
1552
    // Store this extension choice with the "." escaped.
1553
0
    libext += "\\";
1554
#if defined(_WIN32) && !defined(__CYGWIN__)
1555
    libext += this->NoCaseExpression(i);
1556
#else
1557
0
    libext += i;
1558
0
#endif
1559
0
  }
1560
1561
  // Finish the list.
1562
0
  libext += ')';
1563
1564
  // Add an optional OpenBSD-style version or major.minor.version component.
1565
0
  if (this->IsOpenBSD || type == LinkShared) {
1566
0
    libext += "(\\.[0-9]+)*";
1567
0
  }
1568
1569
0
  libext += '$';
1570
0
  return libext;
1571
0
}
1572
1573
std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
1574
0
{
1575
0
  std::string ret;
1576
0
  ret.reserve(str.size() * 4);
1577
0
  for (char c : str) {
1578
0
    if (c == '.') {
1579
0
      ret += c;
1580
0
    } else {
1581
0
      ret += '[';
1582
0
      ret += static_cast<char>(cmsysString_tolower(c));
1583
0
      ret += static_cast<char>(cmsysString_toupper(c));
1584
0
      ret += ']';
1585
0
    }
1586
0
  }
1587
0
  return ret;
1588
0
}
1589
1590
void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
1591
0
{
1592
  // If we are changing the current link type add the flag to tell the
1593
  // linker about it.
1594
0
  if (this->CurrentLinkType != lt) {
1595
0
    this->CurrentLinkType = lt;
1596
1597
0
    if (this->LinkTypeEnabled) {
1598
0
      switch (this->CurrentLinkType) {
1599
0
        case LinkStatic:
1600
0
          this->Items.emplace_back(this->StaticLinkTypeFlag, ItemIsPath::No);
1601
0
          break;
1602
0
        case LinkShared:
1603
0
          this->Items.emplace_back(this->SharedLinkTypeFlag, ItemIsPath::No);
1604
0
          break;
1605
0
        default:
1606
0
          break;
1607
0
      }
1608
0
    }
1609
0
  }
1610
0
}
1611
1612
void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
1613
0
{
1614
  // This is called to handle a link item that is a full path to a target.
1615
  // If the target is not a static library make sure the link type is
1616
  // shared.  This is because dynamic-mode linking can handle both
1617
  // shared and static libraries but static-mode can handle only
1618
  // static libraries.  If a previous user item changed the link type
1619
  // to static we need to make sure it is back to shared.
1620
0
  BT<std::string> const& item = entry.Item;
1621
0
  cmGeneratorTarget const* target = entry.Target;
1622
1623
0
  if (target->GetType() != cm::TargetType::STATIC_LIBRARY) {
1624
0
    this->SetCurrentLinkType(LinkShared);
1625
0
  }
1626
1627
  // Keep track of shared library targets linked.
1628
0
  if (target->GetType() == cm::TargetType::SHARED_LIBRARY) {
1629
0
    this->SharedLibrariesLinked.insert(target);
1630
0
  }
1631
1632
  // Handle case of an imported shared library with no soname.
1633
0
  if (this->NoSONameUsesPath &&
1634
0
      target->IsImportedSharedLibWithoutSOName(this->Config)) {
1635
0
    this->AddSharedLibNoSOName(entry);
1636
0
    return;
1637
0
  }
1638
1639
0
  bool const isImportedFrameworkFolderOnApple =
1640
0
    target->IsImportedFrameworkFolderOnApple(this->Config);
1641
0
  if (target->IsFrameworkOnApple() || isImportedFrameworkFolderOnApple) {
1642
    // Add the framework directory and the framework item itself
1643
0
    auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
1644
0
      item.Value, cmGlobalGenerator::FrameworkFormat::Extended);
1645
0
    if (!fwDescriptor) {
1646
0
      this->CMakeInstance->IssueMessage(
1647
0
        MessageType::FATAL_ERROR,
1648
0
        cmStrCat("Could not parse framework path \"", item.Value,
1649
0
                 "\" linked by target ", this->Target->GetName(), '.'),
1650
0
        item.Backtrace);
1651
0
      return;
1652
0
    }
1653
0
    if (!fwDescriptor->Directory.empty()) {
1654
      // Add the directory portion to the framework search path.
1655
0
      this->AddFrameworkPath(fwDescriptor->Directory);
1656
0
    }
1657
1658
0
    if (this->GlobalGenerator->IsXcode()) {
1659
0
      if (isImportedFrameworkFolderOnApple) {
1660
0
        if (entry.Feature == DEFAULT) {
1661
0
          this->AddLibraryFeature("FRAMEWORK");
1662
0
          this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr,
1663
0
                                   this->FindLibraryFeature("FRAMEWORK"));
1664
0
        } else {
1665
0
          this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr,
1666
0
                                   this->FindLibraryFeature(entry.Feature));
1667
0
        }
1668
0
      } else {
1669
0
        this->Items.emplace_back(
1670
0
          item, ItemIsPath::Yes, target, nullptr,
1671
0
          this->FindLibraryFeature(entry.Feature == DEFAULT
1672
0
                                     ? "__CMAKE_LINK_FRAMEWORK"
1673
0
                                     : entry.Feature));
1674
0
      }
1675
0
    } else {
1676
0
      if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
1677
0
        this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
1678
0
                                 target, nullptr,
1679
0
                                 this->FindLibraryFeature(entry.Feature));
1680
0
      } else if (entry.Feature == DEFAULT &&
1681
0
                 isImportedFrameworkFolderOnApple) {
1682
0
        this->AddLibraryFeature("FRAMEWORK");
1683
0
        this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
1684
0
                                 target, nullptr,
1685
0
                                 this->FindLibraryFeature("FRAMEWORK"));
1686
0
      } else {
1687
0
        this->Items.emplace_back(
1688
0
          item, ItemIsPath::Yes, target, nullptr,
1689
0
          this->FindLibraryFeature(entry.Feature == DEFAULT
1690
0
                                     ? "__CMAKE_LINK_LIBRARY"
1691
0
                                     : entry.Feature));
1692
0
      }
1693
0
    }
1694
0
  } else {
1695
    // Now add the full path to the library.
1696
0
    this->Items.emplace_back(
1697
0
      item, ItemIsPath::Yes, target, nullptr,
1698
0
      this->FindLibraryFeature(
1699
0
        entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature));
1700
0
  }
1701
0
}
1702
1703
void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry)
1704
0
{
1705
0
  BT<std::string> const& item = entry.Item;
1706
1707
  // Check for the implicit link directory special case.
1708
0
  if (this->CheckImplicitDirItem(entry)) {
1709
0
    return;
1710
0
  }
1711
1712
  // Check for case of shared library with no builtin soname.
1713
0
  if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(entry)) {
1714
0
    return;
1715
0
  }
1716
1717
  // This is called to handle a link item that is a full path.
1718
  // If the target is not a static library make sure the link type is
1719
  // shared.  This is because dynamic-mode linking can handle both
1720
  // shared and static libraries but static-mode can handle only
1721
  // static libraries.  If a previous user item changed the link type
1722
  // to static we need to make sure it is back to shared.
1723
0
  if (this->LinkTypeEnabled) {
1724
0
    std::string name = cmSystemTools::GetFilenameName(item.Value);
1725
0
    if (this->ExtractSharedLibraryName.find(name)) {
1726
0
      this->SetCurrentLinkType(LinkShared);
1727
0
    } else if (!this->ExtractStaticLibraryName.find(item.Value)) {
1728
      // We cannot determine the type.  Assume it is the target's
1729
      // default type.
1730
0
      this->SetCurrentLinkType(this->StartLinkType);
1731
0
    }
1732
0
  }
1733
1734
  // Now add the full path to the library.
1735
0
  this->Items.emplace_back(
1736
0
    item, ItemIsPath::Yes, nullptr, entry.ObjectSource,
1737
0
    this->FindLibraryFeature(
1738
0
      entry.Feature == DEFAULT
1739
0
        ? (entry.Kind == cmComputeLinkDepends::LinkEntry::Object
1740
0
             ? "__CMAKE_LINK_OBJECT"
1741
0
             : "__CMAKE_LINK_LIBRARY")
1742
0
        : entry.Feature));
1743
0
}
1744
1745
bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry)
1746
0
{
1747
0
  BT<std::string> const& item = entry.Item;
1748
1749
  // We only switch to a pathless item if the link type may be
1750
  // enforced.  Fortunately only platforms that support link types
1751
  // seem to have magic per-architecture implicit link directories.
1752
0
  if (!this->LinkTypeEnabled) {
1753
0
    return false;
1754
0
  }
1755
1756
  // Check if this item is in an implicit link directory.
1757
0
  std::string dir = cmSystemTools::GetFilenamePath(item.Value);
1758
0
  if (!cm::contains(this->ImplicitLinkDirs, dir)) {
1759
    // Only libraries in implicit link directories are converted to
1760
    // pathless items.
1761
0
    return false;
1762
0
  }
1763
1764
  // Only apply the policy below if the library file is one that can
1765
  // be found by the linker.
1766
0
  std::string file = cmSystemTools::GetFilenameName(item.Value);
1767
0
  if (!this->ExtractAnyLibraryName.find(file)) {
1768
0
    return false;
1769
0
  }
1770
1771
0
  return false;
1772
0
}
1773
1774
void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry)
1775
0
{
1776
  // This is called to handle a link item that does not match a CMake
1777
  // target and is not a full path.  We check here if it looks like a
1778
  // library file name to automatically request the proper link type
1779
  // from the linker.  For example:
1780
  //
1781
  //   foo       ==>  -lfoo
1782
  //   libfoo.a  ==>  -Wl,-Bstatic -lfoo
1783
1784
0
  cm::string_view const LINKER{ "LINKER:" };
1785
0
  BT<std::string> const& item = entry.Item;
1786
1787
0
  if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') {
1788
    // Pass flags through untouched.
1789
1790
    // Restore the target link type since this item does not specify
1791
    // one.
1792
0
    this->SetCurrentLinkType(this->StartLinkType);
1793
1794
    // Use the item verbatim.
1795
0
    this->Items.emplace_back(item, ItemIsPath::No);
1796
0
    return;
1797
0
  }
1798
1799
0
  if (cmHasPrefix(item.Value, LINKER)) {
1800
0
    std::vector<BT<std::string>> linkerFlag{ 1, item };
1801
0
    this->Target->ResolveLinkerWrapper(linkerFlag, this->GetLinkLanguage(),
1802
0
                                       /* joinItems = */ true);
1803
0
    if (!linkerFlag.empty()) {
1804
0
      this->Items.emplace_back(linkerFlag.front(), ItemIsPath::No);
1805
0
    }
1806
0
    return;
1807
0
  }
1808
1809
  // Parse out the prefix, base, and suffix components of the
1810
  // library name.  If the name matches that of a shared or static
1811
  // library then set the link type accordingly.
1812
  //
1813
  // Search for shared library names first because some platforms
1814
  // have shared libraries with names that match the static library
1815
  // pattern.  For example cygwin and msys use the convention
1816
  // libfoo.dll.a for import libraries and libfoo.a for static
1817
  // libraries.  On AIX a library with the name libfoo.a can be
1818
  // shared!
1819
0
  std::string lib;
1820
0
  if (this->ExtractSharedLibraryName.find(item.Value)) {
1821
// This matches a shared library file name.
1822
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
1823
    fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
1824
            this->ExtractSharedLibraryName.match(1).c_str(),
1825
            this->ExtractSharedLibraryName.match(2).c_str(),
1826
            this->ExtractSharedLibraryName.match(3).c_str());
1827
#endif
1828
    // Set the link type to shared.
1829
0
    this->SetCurrentLinkType(LinkShared);
1830
1831
    // Use just the library name so the linker will search.
1832
0
    lib = this->ExtractSharedLibraryName.match(2);
1833
0
  } else if (this->ExtractStaticLibraryName.find(item.Value)) {
1834
// This matches a static library file name.
1835
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
1836
    fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
1837
            this->ExtractStaticLibraryName.match(1).c_str(),
1838
            this->ExtractStaticLibraryName.match(2).c_str(),
1839
            this->ExtractStaticLibraryName.match(3).c_str());
1840
#endif
1841
    // Set the link type to static.
1842
0
    this->SetCurrentLinkType(LinkStatic);
1843
1844
    // Use just the library name so the linker will search.
1845
0
    lib = this->ExtractStaticLibraryName.match(2);
1846
0
  } else if (this->ExtractAnyLibraryName.find(item.Value)) {
1847
// This matches a library file name.
1848
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
1849
    fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
1850
            this->ExtractAnyLibraryName.match(1).c_str(),
1851
            this->ExtractAnyLibraryName.match(2).c_str(),
1852
            this->ExtractAnyLibraryName.match(3).c_str());
1853
#endif
1854
    // Restore the target link type since this item does not specify
1855
    // one.
1856
0
    this->SetCurrentLinkType(this->StartLinkType);
1857
1858
    // Use just the library name so the linker will search.
1859
0
    lib = this->ExtractAnyLibraryName.match(2);
1860
0
  } else {
1861
    // We must ask the linker to search for a library with this name.
1862
    // Restore the target link type since this item does not specify
1863
    // one.
1864
0
    this->SetCurrentLinkType(this->StartLinkType);
1865
0
    lib = item.Value;
1866
0
  }
1867
1868
  // Create an option to ask the linker to search for the library.
1869
0
  auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
1870
1871
0
  if (entry.Feature != DEFAULT) {
1872
0
    auto const& feature = this->GetLibraryFeature(entry.Feature);
1873
0
    this->Items.emplace_back(
1874
0
      BT<std::string>(
1875
0
        feature.GetDecoratedItem(cmStrCat(lib, this->LibLinkSuffix),
1876
0
                                 item.Value, out, ItemIsPath::No),
1877
0
        item.Backtrace),
1878
0
      ItemIsPath::No);
1879
0
  } else {
1880
0
    this->Items.emplace_back(BT<std::string>(out, item.Backtrace),
1881
0
                             ItemIsPath::No);
1882
0
  }
1883
1884
  // Here we could try to find the library the linker will find and
1885
  // add a runtime information entry for it.  It would probably not be
1886
  // reliable and we want to encourage use of full paths for library
1887
  // specification.
1888
0
}
1889
1890
void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
1891
0
{
1892
0
  std::string const& item = entry.Item.Value;
1893
1894
  // Try to separate the framework name and path.
1895
0
  auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
1896
0
    item,
1897
0
    entry.Feature == DEFAULT ? cmGlobalGenerator::FrameworkFormat::Relaxed
1898
0
                             : cmGlobalGenerator::FrameworkFormat::Extended);
1899
0
  if (!fwDescriptor) {
1900
0
    std::ostringstream e;
1901
0
    e << "Could not parse framework path \"" << item << "\" linked by target "
1902
0
      << this->Target->GetName() << '.';
1903
0
    cmSystemTools::Error(e.str());
1904
0
    return;
1905
0
  }
1906
1907
0
  std::string const& fw_path = fwDescriptor->Directory;
1908
0
  if (!fw_path.empty()) {
1909
    // Add the directory portion to the framework search path.
1910
0
    this->AddFrameworkPath(fw_path);
1911
0
  }
1912
1913
  // add runtime information
1914
0
  this->AddLibraryRuntimeInfo(fwDescriptor->GetFullPath());
1915
1916
0
  if (entry.Feature == DEFAULT) {
1917
    // ensure FRAMEWORK feature is loaded
1918
0
    this->AddLibraryFeature("FRAMEWORK");
1919
0
  }
1920
1921
0
  if (this->GlobalGenerator->IsXcode()) {
1922
    // Add framework path - it will be handled by Xcode after it's added to
1923
    // "Link Binary With Libraries" build phase
1924
0
    this->Items.emplace_back(item, ItemIsPath::Yes, nullptr, nullptr,
1925
0
                             this->FindLibraryFeature(entry.Feature == DEFAULT
1926
0
                                                        ? "FRAMEWORK"
1927
0
                                                        : entry.Feature));
1928
0
  } else {
1929
0
    this->Items.emplace_back(
1930
0
      fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr, nullptr,
1931
0
      this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK"
1932
0
                                                        : entry.Feature));
1933
0
  }
1934
0
}
1935
1936
void cmComputeLinkInformation::AddXcFrameworkItem(LinkEntry const& entry)
1937
0
{
1938
0
  auto plist = cmParseXcFrameworkPlist(entry.Item.Value, *this->Makefile,
1939
0
                                       entry.Item.Backtrace);
1940
0
  if (!plist) {
1941
0
    return;
1942
0
  }
1943
1944
0
  if (auto const* lib =
1945
0
        plist->SelectSuitableLibrary(*this->Makefile, entry.Item.Backtrace)) {
1946
0
    if (this->GlobalGenerator->IsXcode()) {
1947
0
      this->Items.emplace_back(
1948
0
        entry.Item.Value, ItemIsPath::Yes, nullptr, nullptr,
1949
0
        this->FindLibraryFeature(entry.Feature == DEFAULT
1950
0
                                   ? "__CMAKE_LINK_XCFRAMEWORK"
1951
0
                                   : entry.Feature));
1952
0
    } else {
1953
0
      auto libraryPath = cmStrCat(
1954
0
        entry.Item.Value, '/', lib->LibraryIdentifier, '/', lib->LibraryPath);
1955
0
      LinkEntry libraryEntry(
1956
0
        BT<std::string>(libraryPath, entry.Item.Backtrace), entry.Target);
1957
1958
0
      if (cmSystemTools::IsPathToFramework(libraryPath) &&
1959
0
          this->Target->IsApple()) {
1960
        // This is a framework.
1961
0
        this->AddFrameworkItem(libraryEntry);
1962
0
      } else {
1963
0
        this->Depends.push_back(libraryPath);
1964
0
        this->AddFullItem(libraryEntry);
1965
0
        this->AddLibraryRuntimeInfo(libraryPath);
1966
0
        if (!lib->HeadersPath.empty()) {
1967
0
          this->AddXcFrameworkHeaderPath(cmStrCat(entry.Item.Value, '/',
1968
0
                                                  lib->LibraryIdentifier, '/',
1969
0
                                                  lib->HeadersPath));
1970
0
        }
1971
0
      }
1972
0
    }
1973
0
  }
1974
0
}
1975
1976
void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item)
1977
0
{
1978
  // A full path to a directory was found as a link item.  Warn the
1979
  // user.
1980
0
  this->CMakeInstance->IssueMessage(
1981
0
    MessageType::WARNING,
1982
0
    cmStrCat("Target \"", this->Target->GetName(),
1983
0
             "\" requests linking to directory \"", item.Value,
1984
0
             "\".  Targets may link only to libraries.  CMake is dropping "
1985
0
             "the item."),
1986
0
    item.Backtrace);
1987
0
}
1988
1989
void cmComputeLinkInformation::ComputeFrameworkInfo()
1990
0
{
1991
  // Avoid adding implicit framework paths.
1992
0
  cmList implicitDirs;
1993
1994
  // Get platform-wide implicit directories.
1995
0
  implicitDirs.assign(this->Makefile->GetDefinition(
1996
0
    "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"));
1997
1998
  // Get language-specific implicit directories.
1999
0
  std::string implicitDirVar = cmStrCat(
2000
0
    "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES");
2001
0
  implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar));
2002
2003
0
  this->FrameworkPathsEmitted.insert(implicitDirs.begin(), implicitDirs.end());
2004
0
}
2005
2006
void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
2007
0
{
2008
0
  if (this->FrameworkPathsEmitted.insert(p).second) {
2009
0
    this->FrameworkPaths.push_back(p);
2010
0
  }
2011
0
}
2012
2013
void cmComputeLinkInformation::AddXcFrameworkHeaderPath(std::string const& p)
2014
0
{
2015
0
  this->XcFrameworkHeaderPaths.push_back(p);
2016
0
}
2017
2018
bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry)
2019
0
{
2020
  // This platform will use the path to a library as its soname if the
2021
  // library is given via path and was not built with an soname.  If
2022
  // this is a shared library that might be the case.
2023
0
  std::string file = cmSystemTools::GetFilenameName(entry.Item.Value);
2024
0
  if (this->ExtractSharedLibraryName.find(file)) {
2025
    // If we can guess the soname fairly reliably then assume the
2026
    // library has one.  Otherwise assume the library has no builtin
2027
    // soname.
2028
0
    std::string soname;
2029
0
    if (!cmSystemTools::GuessLibrarySOName(entry.Item.Value, soname)) {
2030
0
      this->AddSharedLibNoSOName(entry);
2031
0
      return true;
2032
0
    }
2033
0
  }
2034
0
  return false;
2035
0
}
2036
2037
void cmComputeLinkInformation::AddSharedLibNoSOName(LinkEntry const& entry)
2038
0
{
2039
  // We have a full path to a shared library with no soname.  We need
2040
  // to ask the linker to locate the item because otherwise the path
2041
  // we give to it will be embedded in the target linked.  Then at
2042
  // runtime the dynamic linker will search for the library using the
2043
  // path instead of just the name.
2044
0
  LinkEntry fileEntry{ entry };
2045
0
  fileEntry.Item = cmSystemTools::GetFilenameName(entry.Item.Value);
2046
0
  this->AddUserItem(fileEntry);
2047
2048
  // Make sure the link directory ordering will find the library.
2049
0
  this->OrderLinkerSearchPath->AddLinkLibrary(entry.Item.Value);
2050
0
}
2051
2052
void cmComputeLinkInformation::LoadImplicitLinkInfo()
2053
0
{
2054
  // Get platform-wide implicit directories.
2055
0
  cmList implicitDirs{ this->Makefile->GetDefinition(
2056
0
    "CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES") };
2057
2058
  // Append library architecture to all implicit platform directories
2059
  // and add them to the set
2060
0
  if (cmValue libraryArch =
2061
0
        this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
2062
0
    for (auto const& i : implicitDirs) {
2063
0
      this->ImplicitLinkDirs.insert(cmStrCat(i, '/', *libraryArch));
2064
0
    }
2065
0
  }
2066
2067
  // Get language-specific implicit directories.
2068
0
  std::string implicitDirVar =
2069
0
    cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES");
2070
0
  implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar));
2071
2072
  // Store implicit link directories.
2073
0
  this->ImplicitLinkDirs.insert(implicitDirs.begin(), implicitDirs.end());
2074
2075
  // Get language-specific implicit libraries.
2076
0
  std::string implicitLibVar =
2077
0
    cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES");
2078
0
  cmList implicitLibs{ this->Makefile->GetDefinition(implicitLibVar) };
2079
2080
  // Store implicit link libraries.
2081
0
  for (auto const& item : implicitLibs) {
2082
    // Items starting in '-' but not '-l' are flags, not libraries,
2083
    // and should not be filtered by this implicit list.
2084
0
    if (item[0] != '-' || item[1] == 'l') {
2085
0
      this->ImplicitLinkLibs.insert(item);
2086
0
    }
2087
0
  }
2088
2089
  // Get platform specific rpath link directories
2090
0
  cmList::append(this->RuntimeLinkDirs,
2091
0
                 this->Makefile->GetDefinition("CMAKE_PLATFORM_RUNTIME_PATH"));
2092
0
}
2093
2094
std::vector<std::string> const&
2095
cmComputeLinkInformation::GetRuntimeSearchPath() const
2096
0
{
2097
0
  return this->OrderRuntimeSearchPath->GetOrderedDirectories();
2098
0
}
2099
2100
void cmComputeLinkInformation::AddLibraryRuntimeInfo(
2101
  std::string const& fullPath, cmGeneratorTarget const* target)
2102
0
{
2103
  // Ignore targets on Apple where install_name is not @rpath.
2104
  // The dependenty library can be found with other means such as
2105
  // @loader_path or full paths.
2106
0
  if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2107
0
    if (!target->HasMacOSXRpathInstallNameDir(this->Config)) {
2108
0
      return;
2109
0
    }
2110
0
  }
2111
2112
  // Libraries with unknown type must be handled using just the file
2113
  // on disk.
2114
0
  if (target->GetType() == cm::TargetType::UNKNOWN_LIBRARY) {
2115
0
    this->AddLibraryRuntimeInfo(fullPath);
2116
0
    return;
2117
0
  }
2118
2119
  // Skip targets that are not shared libraries (modules cannot be linked).
2120
0
  if (target->GetType() != cm::TargetType::SHARED_LIBRARY) {
2121
0
    return;
2122
0
  }
2123
2124
  // Skip targets that do not have a known runtime artifact.
2125
0
  if (!target->HasKnownRuntimeArtifactLocation(this->Config)) {
2126
0
    return;
2127
0
  }
2128
2129
  // Try to get the soname of the library.  Only files with this name
2130
  // could possibly conflict.
2131
0
  std::string soName = target->GetSOName(this->Config);
2132
0
  char const* soname = soName.empty() ? nullptr : soName.c_str();
2133
2134
  // Include this library in the runtime path ordering.
2135
0
  this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
2136
0
  if (this->LinkWithRuntimePath) {
2137
0
    this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
2138
0
  }
2139
0
}
2140
2141
void cmComputeLinkInformation::AddLibraryRuntimeInfo(
2142
  std::string const& fullPath)
2143
0
{
2144
  // Get the name of the library from the file name.
2145
0
  bool is_shared_library = false;
2146
0
  std::string file = cmSystemTools::GetFilenameName(fullPath);
2147
2148
0
  if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2149
    // Check that @rpath is part of the install name.
2150
    // If it isn't, return.
2151
0
    std::string soname;
2152
0
    if (!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) {
2153
0
      return;
2154
0
    }
2155
2156
0
    if (soname.find("@rpath") == std::string::npos) {
2157
0
      return;
2158
0
    }
2159
0
  }
2160
2161
0
  is_shared_library = this->ExtractSharedLibraryName.find(file);
2162
2163
0
  if (!is_shared_library) {
2164
    // On some platforms (AIX) a shared library may look static.
2165
0
    if (this->ArchivesMayBeShared) {
2166
0
      if (this->ExtractStaticLibraryName.find(file)) {
2167
        // This is the name of a shared library or archive.
2168
0
        is_shared_library = true;
2169
0
      }
2170
0
    }
2171
0
  }
2172
2173
  // It could be an Apple framework
2174
0
  if (!is_shared_library) {
2175
0
    is_shared_library =
2176
0
      this->GlobalGenerator
2177
0
        ->SplitFrameworkPath(fullPath,
2178
0
                             cmGlobalGenerator::FrameworkFormat::Strict)
2179
0
        .has_value();
2180
0
  }
2181
2182
0
  if (!is_shared_library) {
2183
0
    return;
2184
0
  }
2185
2186
  // Include this library in the runtime path ordering.
2187
0
  this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
2188
0
  if (this->LinkWithRuntimePath) {
2189
0
    this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
2190
0
  }
2191
0
}
2192
2193
static void cmCLI_ExpandListUnique(std::string const& str,
2194
                                   std::vector<std::string>& out,
2195
                                   std::set<std::string>& emitted)
2196
0
{
2197
0
  cmList tmp{ str };
2198
0
  for (std::string const& i : tmp) {
2199
0
    if (emitted.insert(i).second) {
2200
0
      out.push_back(i);
2201
0
    }
2202
0
  }
2203
0
}
2204
2205
void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
2206
                                        bool for_install) const
2207
0
{
2208
  // Select whether to generate runtime search directories.
2209
0
  bool outputRuntime =
2210
0
    !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->RuntimeFlag.empty();
2211
2212
  // Select whether to generate an rpath for the install tree or the
2213
  // build tree.
2214
0
  bool linking_for_install =
2215
0
    (for_install ||
2216
0
     this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
2217
0
  bool use_install_rpath =
2218
0
    (outputRuntime && this->Target->HaveInstallTreeRPATH(this->Config) &&
2219
0
     linking_for_install);
2220
0
  bool use_build_rpath =
2221
0
    (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
2222
0
     !linking_for_install);
2223
0
  bool use_link_rpath = outputRuntime && linking_for_install &&
2224
0
    !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
2225
0
    this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
2226
2227
  // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree.
2228
0
  std::string const& originToken = this->Makefile->GetSafeDefinition(
2229
0
    "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN");
2230
0
  std::string targetOutputDir = this->Target->GetDirectory(this->Config);
2231
0
  bool use_relative_build_rpath =
2232
0
    this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") &&
2233
0
    !originToken.empty() && !targetOutputDir.empty();
2234
2235
  // Construct the RPATH.
2236
0
  std::set<std::string> emitted;
2237
0
  if (use_install_rpath) {
2238
0
    std::string install_rpath;
2239
0
    this->Target->GetInstallRPATH(this->Config, install_rpath);
2240
0
    cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
2241
0
  }
2242
0
  if (use_build_rpath) {
2243
    // Add directories explicitly specified by user
2244
0
    std::string build_rpath;
2245
0
    if (this->Target->GetBuildRPATH(this->Config, build_rpath)) {
2246
      // This will not resolve entries to use $ORIGIN, the user is expected
2247
      // to do that if necessary.
2248
0
      cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
2249
0
    }
2250
0
  }
2251
0
  if (use_build_rpath || use_link_rpath) {
2252
0
    std::string rootPath;
2253
0
    if (cmValue sysrootLink =
2254
0
          this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
2255
0
      rootPath = *sysrootLink;
2256
0
    } else {
2257
0
      rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
2258
0
    }
2259
0
    cmValue stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
2260
0
    std::string const& installPrefix =
2261
0
      this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2262
0
    cmSystemTools::ConvertToUnixSlashes(rootPath);
2263
0
    std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
2264
0
    std::string const& topBinaryDir =
2265
0
      this->CMakeInstance->GetHomeOutputDirectory();
2266
0
    for (std::string const& ri : rdirs) {
2267
      // Put this directory in the rpath if using build-tree rpath
2268
      // support or if using the link path as an rpath.
2269
0
      if (use_build_rpath) {
2270
0
        std::string d = ri;
2271
0
        if (!rootPath.empty() && rootPath != "/" && cmHasPrefix(d, rootPath)) {
2272
0
          d.erase(0, rootPath.size());
2273
0
        } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
2274
0
          d.erase(0, (*stagePath).size());
2275
0
          d = cmStrCat(installPrefix, '/', d);
2276
0
          cmSystemTools::ConvertToUnixSlashes(d);
2277
0
        } else if (use_relative_build_rpath) {
2278
          // If expansion of the $ORIGIN token is supported and permitted per
2279
          // policy, use relative paths in the RPATH.
2280
0
          if (cmSystemTools::ComparePath(d, topBinaryDir) ||
2281
0
              cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
2282
0
            d = cmSystemTools::RelativePath(targetOutputDir, d);
2283
0
            if (!d.empty()) {
2284
0
              d = cmStrCat(originToken, '/', d);
2285
0
            } else {
2286
0
              d = originToken;
2287
0
            }
2288
0
          }
2289
0
        }
2290
0
        if (emitted.insert(d).second) {
2291
0
          runtimeDirs.push_back(std::move(d));
2292
0
        }
2293
0
      } else if (use_link_rpath) {
2294
        // Do not add any path inside the source or build tree.
2295
0
        std::string const& topSourceDir =
2296
0
          this->CMakeInstance->GetHomeDirectory();
2297
0
        if (!cmSystemTools::ComparePath(ri, topSourceDir) &&
2298
0
            !cmSystemTools::ComparePath(ri, topBinaryDir) &&
2299
0
            !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
2300
0
            !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
2301
0
          std::string d = ri;
2302
0
          if (!rootPath.empty() && rootPath != "/" &&
2303
0
              cmHasPrefix(d, rootPath)) {
2304
0
            d.erase(0, rootPath.size());
2305
0
          } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
2306
0
            d.erase(0, (*stagePath).size());
2307
0
            d = cmStrCat(installPrefix, '/', d);
2308
0
            cmSystemTools::ConvertToUnixSlashes(d);
2309
0
          }
2310
0
          if (emitted.insert(d).second) {
2311
0
            runtimeDirs.push_back(std::move(d));
2312
0
          }
2313
0
        }
2314
0
      }
2315
0
    }
2316
0
  }
2317
2318
  // Add runtime paths required by the toolchains' runtime libraries.
2319
  // This is done even when skipping RPATH entries modeled by CMake.
2320
  // However, INSTALL_REMOVE_ENVIRONMENT_RPATH tells us to exclude
2321
  // toolchain-defined RPATH entries from installation.
2322
0
  bool const removeEnvironmentRPath = for_install &&
2323
0
    this->Target->GetPropertyAsBool("INSTALL_REMOVE_ENVIRONMENT_RPATH");
2324
0
  if (!removeEnvironmentRPath) {
2325
0
    cmGeneratorTarget::LinkClosure const* lc =
2326
0
      this->Target->GetLinkClosure(this->Config);
2327
0
    for (std::string const& li : lc->Languages) {
2328
0
      std::string useVar = cmStrCat(
2329
0
        "CMAKE_", li, "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH");
2330
0
      if (this->Makefile->IsOn(useVar)) {
2331
0
        std::string dirVar =
2332
0
          cmStrCat("CMAKE_", li, "_IMPLICIT_LINK_DIRECTORIES");
2333
0
        if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
2334
0
          cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
2335
0
        }
2336
0
      }
2337
0
    }
2338
0
  }
2339
2340
  // Add runtime paths required by the platform to always be present.
2341
  // This is done even when skipping RPATH entries modeled by CMake.
2342
0
  cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted);
2343
0
}
2344
2345
std::string cmComputeLinkInformation::GetRPathString(bool for_install) const
2346
0
{
2347
  // Get the directories to use.
2348
0
  std::vector<std::string> runtimeDirs;
2349
0
  this->GetRPath(runtimeDirs, for_install);
2350
2351
  // Concatenate the paths.
2352
0
  std::string rpath = cmJoin(runtimeDirs, this->GetRuntimeSep());
2353
2354
  // If the rpath will be replaced at install time, prepare space.
2355
0
  if (!for_install && this->RuntimeUseChrpath) {
2356
0
    if (!rpath.empty()) {
2357
      // Add one trailing separator so the linker does not reuse the
2358
      // rpath .dynstr entry for a symbol name that happens to match
2359
      // the end of the rpath string.
2360
0
      rpath += this->GetRuntimeSep();
2361
0
    }
2362
2363
    // Make sure it is long enough to hold the replacement value.
2364
0
    std::string::size_type minLength = this->GetChrpathString().length();
2365
0
    while (rpath.length() < minLength) {
2366
0
      rpath += this->GetRuntimeSep();
2367
0
    }
2368
0
  }
2369
2370
0
  return rpath;
2371
0
}
2372
2373
std::string cmComputeLinkInformation::GetChrpathString() const
2374
0
{
2375
0
  if (!this->RuntimeUseChrpath) {
2376
0
    return "";
2377
0
  }
2378
2379
0
  return this->GetRPathString(true);
2380
0
}