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