Coverage Report

Created: 2026-02-09 06:05

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