Merge branch 'release-3.29'
[kiteware-cmake.git] / Source / cmComputeLinkInformation.cxx
blobb631610e9793cf8abf03e1f7764ecf61c1c95267
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"
5 #include <algorithm>
6 #include <cctype>
7 #include <sstream>
8 #include <utility>
10 #include <cm/memory>
11 #include <cm/optional>
12 #include <cmext/algorithm>
13 #include <cmext/string_view>
15 #include "cmComputeLinkDepends.h"
16 #include "cmGeneratorTarget.h"
17 #include "cmGlobalGenerator.h"
18 #include "cmLinkItem.h"
19 #include "cmList.h"
20 #include "cmListFileCache.h"
21 #include "cmLocalGenerator.h"
22 #include "cmMakefile.h"
23 #include "cmMessageType.h"
24 #include "cmOrderDirectories.h"
25 #include "cmPlaceholderExpander.h"
26 #include "cmPolicies.h"
27 #include "cmSourceFile.h"
28 #include "cmState.h"
29 #include "cmStateTypes.h"
30 #include "cmStringAlgorithms.h"
31 #include "cmSystemTools.h"
32 #include "cmTarget.h"
33 #include "cmValue.h"
34 #include "cmXcFramework.h"
35 #include "cmake.h"
37 // #define CM_COMPUTE_LINK_INFO_DEBUG
40 Notes about linking on various platforms:
42 ------------------------------------------------------------------------------
44 Linux, FreeBSD, macOS, Sun, Windows:
46 Linking to libraries using the full path works fine.
48 ------------------------------------------------------------------------------
50 On AIX, more work is needed.
52 The "-bnoipath" option is needed. From "man ld":
54 Note: If you specify a shared object, or an archive file
55 containing a shared object, with an absolute or relative path
56 name, instead of with the -lName flag, the path name is
57 included in the import file ID string in the loader section of
58 the output file. You can override this behavior with the
59 -bnoipath option.
61 noipath
63 For shared objects listed on the command-line, rather than
64 specified with the -l flag, use a null path component when
65 listing the shared object in the loader section of the
66 output file. A null path component is always used for
67 shared objects specified with the -l flag. This option
68 does not affect the specification of a path component by
69 using a line beginning with #! in an import file. The
70 default is the ipath option.
72 This prevents the full path specified on the compile line from being
73 compiled directly into the binary.
75 By default the linker places -L paths in the embedded runtime path.
76 In order to implement CMake's RPATH interface correctly, we need the
77 -blibpath:Path option. From "man ld":
79 libpath:Path
81 Uses Path as the library path when writing the loader section
82 of the output file. Path is neither checked for validity nor
83 used when searching for libraries specified by the -l flag.
84 Path overrides any library paths generated when the -L flag is
85 used.
87 If you do not specify any -L flags, or if you specify the
88 nolibpath option, the default library path information is
89 written in the loader section of the output file. The default
90 library path information is the value of the LIBPATH
91 environment variable if it is defined, and /usr/lib:/lib,
92 otherwise.
94 We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
95 and not break when the user sets LIBPATH. Then if we want to add an
96 rpath we insert it into the option before /usr/lib.
98 ------------------------------------------------------------------------------
100 On HP-UX, more work is needed. There are differences between
101 versions.
103 ld: 92453-07 linker linker ld B.10.33 990520
105 Linking with a full path works okay for static and shared libraries.
106 The linker seems to always put the full path to where the library
107 was found in the binary whether using a full path or -lfoo syntax.
108 Transitive link dependencies work just fine due to the full paths.
110 It has the "-l:libfoo.sl" option. The +nodefaultrpath is accepted
111 but not documented and does not seem to do anything. There is no
112 +forceload option.
114 ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
116 Linking with a full path works okay for static libraries.
118 Linking with a full path works okay for shared libraries. However
119 dependent (transitive) libraries of those linked directly must be
120 either found with an rpath stored in the direct dependencies or
121 found in -L paths as if they were specified with "-l:libfoo.sl"
122 (really "-l:<soname>"). The search matches that of the dynamic
123 loader but only with -L paths. In other words, if we have an
124 executable that links to shared library bar which links to shared
125 library foo, the link line for the exe must contain
127 /dir/with/bar/libbar.sl -L/dir/with/foo
129 It does not matter whether the exe wants to link to foo directly or
130 whether /dir/with/foo/libfoo.sl is listed. The -L path must still
131 be present. It should match the runtime path computed for the
132 executable taking all directly and transitively linked libraries
133 into account.
135 The "+nodefaultrpath" option should be used to avoid getting -L
136 paths in the rpath unless we add our own rpath with +b. This means
137 that skip-build-rpath should use this option.
139 See documentation in "man ld", "man dld.so", and
140 http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
142 +[no]defaultrpath
143 +defaultrpath is the default. Include any paths that are
144 specified with -L in the embedded path, unless you specify the
145 +b option. If you use +b, only the path list specified by +b is
146 in the embedded path.
148 The +nodefaultrpath option removes all library paths that were
149 specified with the -L option from the embedded path. The linker
150 searches the library paths specified by the -L option at link
151 time. At run time, the only library paths searched are those
152 specified by the environment variables LD_LIBRARY_PATH and
153 SHLIB_PATH, library paths specified by the +b linker option, and
154 finally the default library paths.
156 +rpathfirst
157 This option will cause the paths specified in RPATH (embedded
158 path) to be used before the paths specified in LD_LIBRARY_PATH
159 or SHLIB_PATH, in searching for shared libraries. This changes
160 the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
161 RPATH (embedded path).
163 ------------------------------------------------------------------------------
164 Notes about dependent (transitive) shared libraries:
166 On non-Windows systems shared libraries may have transitive
167 dependencies. In order to support LINK_INTERFACE_LIBRARIES we must
168 support linking to a shared library without listing all the libraries
169 to which it links. Some linkers want to be able to find the
170 transitive dependencies (dependent libraries) of shared libraries
171 listed on the command line.
173 - On Windows, DLLs are not directly linked, and the import libraries
174 have no transitive dependencies.
176 - On Mac OS X 10.5 and above transitive dependencies are not needed.
178 - On Mac OS X 10.4 and below we need to actually list the dependencies.
179 Otherwise when using -isysroot for universal binaries it cannot
180 find the dependent libraries. Listing them on the command line
181 tells the linker where to find them, but unfortunately also links
182 the library.
184 - On HP-UX, the linker wants to find the transitive dependencies of
185 shared libraries in the -L paths even if the dependent libraries
186 are given on the link line.
188 - On AIX the transitive dependencies are not needed.
190 - On SGI, the linker wants to find the transitive dependencies of
191 shared libraries in the -L paths if they are not given on the link
192 line. Transitive linking can be disabled using the options
194 -no_transitive_link -Wl,-no_transitive_link
196 which disable it. Both options must be given when invoking the
197 linker through the compiler.
199 - On Sun, the linker wants to find the transitive dependencies of
200 shared libraries in the -L paths if they are not given on the link
201 line.
203 - On Linux, FreeBSD, and QNX:
205 The linker wants to find the transitive dependencies of shared
206 libraries in the "-rpath-link" paths option if they have not been
207 given on the link line. The option is like rpath but just for
208 link time:
210 -Wl,-rpath-link,"/path1:/path2"
212 For -rpath-link, we need a separate runtime path ordering pass
213 including just the dependent libraries that are not linked.
215 For -L paths on non-HP, we can do the same thing as with rpath-link
216 but put the results in -L paths. The paths should be listed at the
217 end to avoid conflicting with user search paths (?).
219 For -L paths on HP, we should do a runtime path ordering pass with
220 all libraries, both linked and non-linked. Even dependent
221 libraries that are also linked need to be listed in -L paths.
223 In our implementation we add all dependent libraries to the runtime
224 path computation. Then the auto-generated RPATH will find everything.
226 ------------------------------------------------------------------------------
227 Notes about shared libraries with not builtin soname:
229 Some UNIX shared libraries may be created with no builtin soname. On
230 some platforms such libraries cannot be linked using the path to their
231 location because the linker will copy the path into the field used to
232 find the library at runtime.
234 Apple: ../libfoo.dylib ==> libfoo.dylib # ok, uses install_name
235 SGI: ../libfoo.so ==> libfoo.so # ok
236 AIX: ../libfoo.so ==> libfoo.so # ok
237 Linux: ../libfoo.so ==> ../libfoo.so # bad
238 HP-UX: ../libfoo.so ==> ../libfoo.so # bad
239 Sun: ../libfoo.so ==> ../libfoo.so # bad
240 FreeBSD: ../libfoo.so ==> ../libfoo.so # bad
242 In order to link these libraries we need to use the old-style split
243 into -L.. and -lfoo options. This should be fairly safe because most
244 problems with -lfoo options were related to selecting shared libraries
245 instead of static but in this case we want the shared lib. Link
246 directory ordering needs to be done to make sure these shared
247 libraries are found first. There should be very few restrictions
248 because this need be done only for shared libraries without soname-s.
252 cmComputeLinkInformation::cmComputeLinkInformation(
253 const cmGeneratorTarget* target, const std::string& config)
254 // Store context information.
255 : Target(target)
256 , Makefile(target->Target->GetMakefile())
257 , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
258 , CMakeInstance(this->GlobalGenerator->GetCMakeInstance())
259 // The configuration being linked.
260 , Config(config)
262 // Check whether to recognize OpenBSD-style library versioned names.
263 this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
264 "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
266 // Allocate internals.
267 this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>(
268 this->GlobalGenerator, target, "linker search path");
269 this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>(
270 this->GlobalGenerator, target, "runtime search path");
272 // Get the language used for linking this target.
273 this->LinkLanguage = this->Target->GetLinkerLanguage(config);
274 if (this->LinkLanguage.empty()) {
275 // The Compute method will do nothing, so skip the rest of the
276 // initialization.
277 return;
280 // Check whether we should skip dependencies on shared library files.
281 this->LinkDependsNoShared =
282 this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
284 // On platforms without import libraries there may be a special flag
285 // to use when creating a plugin (module) that obtains symbols from
286 // the program that will load it.
287 if (!this->Target->IsDLLPlatform() &&
288 this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
289 std::string loader_flag_var =
290 cmStrCat("CMAKE_SHARED_MODULE_LOADER_", this->LinkLanguage, "_FLAG");
291 this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
294 // Get options needed to link libraries.
295 if (cmValue flag = this->Makefile->GetDefinition(
296 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_FLAG"))) {
297 this->LibLinkFlag = *flag;
298 } else {
299 this->LibLinkFlag =
300 this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
302 if (cmValue flag = this->Makefile->GetDefinition(
303 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_FILE_FLAG"))) {
304 this->LibLinkFileFlag = *flag;
305 } else {
306 this->LibLinkFileFlag =
307 this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
309 if (cmValue suffix = this->Makefile->GetDefinition(
310 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_SUFFIX"))) {
311 this->LibLinkSuffix = *suffix;
312 } else {
313 this->LibLinkSuffix =
314 this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
316 if (cmValue flag = this->Makefile->GetDefinition(
317 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_OBJECT_FILE_FLAG"))) {
318 this->ObjLinkFileFlag = *flag;
319 } else {
320 this->ObjLinkFileFlag =
321 this->Makefile->GetSafeDefinition("CMAKE_LINK_OBJECT_FILE_FLAG");
324 // Get options needed to specify RPATHs.
325 this->RuntimeUseChrpath = false;
326 if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
327 const char* tType = ((this->Target->GetType() == cmStateEnums::EXECUTABLE)
328 ? "EXECUTABLE"
329 : "SHARED_LIBRARY");
330 std::string rtVar =
331 cmStrCat("CMAKE_", tType, "_RUNTIME_", this->LinkLanguage, "_FLAG");
332 std::string rtSepVar = cmStrCat(rtVar, "_SEP");
333 this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
334 this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
335 this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
336 "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
338 this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
340 // Get options needed to help find dependent libraries.
341 std::string rlVar =
342 cmStrCat("CMAKE_", tType, "_RPATH_LINK_", this->LinkLanguage, "_FLAG");
343 this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
346 // Check if we need to include the runtime search path at link time.
348 std::string var = cmStrCat("CMAKE_SHARED_LIBRARY_LINK_",
349 this->LinkLanguage, "_WITH_RUNTIME_PATH");
350 this->LinkWithRuntimePath = this->Makefile->IsOn(var);
353 // Define some Feature descriptors to handle standard library and object link
354 if (!this->GetLibLinkFileFlag().empty()) {
355 this->LibraryFeatureDescriptors.emplace(
356 "__CMAKE_LINK_LIBRARY",
357 LibraryFeatureDescriptor{
358 "__CMAKE_LINK_LIBRARY",
359 cmStrCat(this->GetLibLinkFileFlag(), "<LIBRARY>") });
361 if (!this->GetObjLinkFileFlag().empty()) {
362 this->LibraryFeatureDescriptors.emplace(
363 "__CMAKE_LINK_OBJECT",
364 LibraryFeatureDescriptor{
365 "__CMAKE_LINK_OBJECT",
366 cmStrCat(this->GetObjLinkFileFlag(), "<LIBRARY>") });
368 if (!this->LoaderFlag->empty()) {
369 // Define a Feature descriptor for the link of an executable with exports
370 this->LibraryFeatureDescriptors.emplace(
371 "__CMAKE_LINK_EXECUTABLE",
372 LibraryFeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE",
373 cmStrCat(*this->LoaderFlag, "<LIBRARY>") });
375 // To link framework using a full path
376 this->LibraryFeatureDescriptors.emplace(
377 "__CMAKE_LINK_FRAMEWORK",
378 LibraryFeatureDescriptor{ "__CMAKE_LINK_FRAMEWORK", "<LIBRARY>" });
379 // To link xcframework using a full path
380 this->LibraryFeatureDescriptors.emplace(
381 "__CMAKE_LINK_XCFRAMEWORK",
382 LibraryFeatureDescriptor{ "__CMAKE_LINK_XCFRAMEWORK", "<LIBRARY>" });
384 // Check the platform policy for missing soname case.
385 this->NoSONameUsesPath =
386 this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
388 // Get link type information.
389 this->ComputeLinkTypeInfo();
391 // Setup the link item parser.
392 this->ComputeItemParserInfo();
394 // Setup framework support.
395 this->ComputeFrameworkInfo();
397 // Choose a mode for dealing with shared library dependencies.
398 this->SharedDependencyMode = SharedDepModeNone;
399 if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
400 this->SharedDependencyMode = SharedDepModeLink;
401 } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
402 this->SharedDependencyMode = SharedDepModeLibDir;
403 } else if (!this->RPathLinkFlag.empty()) {
404 this->SharedDependencyMode = SharedDepModeDir;
405 this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>(
406 this->GlobalGenerator, target, "dependent library path");
409 // Add the search path entries requested by the user to path ordering.
410 std::vector<std::string> directories;
411 this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
412 this->OrderLinkerSearchPath->AddUserDirectories(directories);
413 this->OrderRuntimeSearchPath->AddUserDirectories(directories);
415 // Set up the implicit link directories.
416 this->LoadImplicitLinkInfo();
417 this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
418 this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
419 if (this->OrderDependentRPath) {
420 this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
421 this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
424 // Decide whether to enable compatible library search path mode.
425 // There exists code that effectively does
427 // /path/to/libA.so -lB
429 // where -lB is meant to link to /path/to/libB.so. This is broken
430 // because it specified -lB without specifying a link directory (-L)
431 // in which to search for B. This worked in CMake 2.4 and below
432 // because -L/path/to would be added by the -L/-l split for A. In
433 // order to support such projects we need to add the directories
434 // containing libraries linked with a full path to the -L path.
435 this->OldLinkDirMode =
436 this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
437 if (this->OldLinkDirMode) {
438 // Construct a mask to not bother with this behavior for link
439 // directories already specified by the user.
440 this->OldLinkDirMask.insert(directories.begin(), directories.end());
443 this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
444 "CMAKE_POLICY_WARNING_CMP0060");
447 cmComputeLinkInformation::~cmComputeLinkInformation() = default;
449 namespace {
450 const std::string& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT;
453 void cmComputeLinkInformation::AppendValues(
454 std::string& result, std::vector<BT<std::string>>& values)
456 for (BT<std::string>& p : values) {
457 if (result.empty()) {
458 result.append(" ");
461 result.append(p.Value);
465 cmComputeLinkInformation::ItemVector const&
466 cmComputeLinkInformation::GetItems() const
468 return this->Items;
471 std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
472 const
474 return this->OrderLinkerSearchPath->GetOrderedDirectories();
477 std::vector<BT<std::string>>
478 cmComputeLinkInformation::GetDirectoriesWithBacktraces()
480 std::vector<BT<std::string>> directoriesWithBacktraces;
482 std::vector<BT<std::string>> targetLinkDirectores =
483 this->Target->GetLinkDirectories(this->Config, this->LinkLanguage);
485 const std::vector<std::string>& orderedDirectories = this->GetDirectories();
486 for (const std::string& dir : orderedDirectories) {
487 auto result =
488 std::find(targetLinkDirectores.begin(), targetLinkDirectores.end(), dir);
489 if (result != targetLinkDirectores.end()) {
490 directoriesWithBacktraces.emplace_back(std::move(*result));
491 } else {
492 directoriesWithBacktraces.emplace_back(dir);
496 return directoriesWithBacktraces;
499 std::string cmComputeLinkInformation::GetRPathLinkString() const
501 // If there is no separate linker runtime search flag (-rpath-link)
502 // there is no reason to compute a string.
503 if (!this->OrderDependentRPath) {
504 return "";
507 // Construct the linker runtime search path. These MUST NOT contain tokens
508 // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
509 return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
512 std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const
514 return this->Depends;
517 std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
518 const
520 return this->FrameworkPaths;
523 std::set<std::string> const&
524 cmComputeLinkInformation::GetFrameworkPathsEmitted() const
526 return this->FrameworkPathsEmitted;
529 std::vector<std::string> const&
530 cmComputeLinkInformation::GetXcFrameworkHeaderPaths() const
532 return this->XcFrameworkHeaderPaths;
535 const std::set<const cmGeneratorTarget*>&
536 cmComputeLinkInformation::GetSharedLibrariesLinked() const
538 return this->SharedLibrariesLinked;
541 const std::vector<const cmGeneratorTarget*>&
542 cmComputeLinkInformation::GetExternalObjectTargets() const
544 return this->ExternalObjectTargets;
547 bool cmComputeLinkInformation::Compute()
549 // Skip targets that do not link or have link-like information consumers may
550 // need (namely modules).
551 if (!(this->Target->GetType() == cmStateEnums::EXECUTABLE ||
552 this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
553 this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
554 this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
555 (this->Target->CanCompileSources() &&
556 (this->Target->HaveCxxModuleSupport(this->Config) ==
557 cmGeneratorTarget::Cxx20SupportLevel::Supported ||
558 this->Target->HaveFortranSources())))) {
559 return false;
562 // We require a link language for the target.
563 if (this->LinkLanguage.empty()) {
564 cmSystemTools::Error(
565 "CMake can not determine linker language for target: " +
566 this->Target->GetName());
567 return false;
570 // Compute the ordered link line items.
571 cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage);
572 cld.SetOldLinkDirMode(this->OldLinkDirMode);
573 cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
574 FeatureDescriptor const* currentFeature = nullptr;
576 // Add the link line items.
577 for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) {
578 if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::Group) {
579 const auto& groupFeature = this->GetGroupFeature(linkEntry.Feature);
580 if (groupFeature.Supported) {
581 if (linkEntry.Item.Value == "</LINK_GROUP>" &&
582 currentFeature != nullptr) {
583 // emit feature suffix, if any
584 if (!currentFeature->Suffix.empty()) {
585 this->Items.emplace_back(
586 BT<std::string>{ currentFeature->Suffix,
587 this->Items.back().Value.Backtrace },
588 ItemIsPath::No);
590 currentFeature = nullptr;
592 this->Items.emplace_back(
593 BT<std::string>{ linkEntry.Item.Value == "<LINK_GROUP>"
594 ? groupFeature.Prefix
595 : groupFeature.Suffix,
596 linkEntry.Item.Backtrace },
597 ItemIsPath::No);
599 continue;
602 if (currentFeature != nullptr &&
603 linkEntry.Feature != currentFeature->Name) {
604 // emit feature suffix, if any
605 if (!currentFeature->Suffix.empty()) {
606 this->Items.emplace_back(
607 BT<std::string>{ currentFeature->Suffix,
608 this->Items.back().Value.Backtrace },
609 ItemIsPath::No);
611 currentFeature = nullptr;
614 if (linkEntry.Feature != DEFAULT &&
615 (currentFeature == nullptr ||
616 linkEntry.Feature != currentFeature->Name)) {
617 if (!this->AddLibraryFeature(linkEntry.Feature)) {
618 continue;
620 currentFeature = this->FindLibraryFeature(linkEntry.Feature);
621 // emit feature prefix, if any
622 if (!currentFeature->Prefix.empty()) {
623 this->Items.emplace_back(
624 BT<std::string>{ currentFeature->Prefix, linkEntry.Item.Backtrace },
625 ItemIsPath::No);
629 if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::SharedDep) {
630 this->AddSharedDepItem(linkEntry);
631 } else {
632 this->AddItem(linkEntry);
636 if (currentFeature != nullptr) {
637 // emit feature suffix, if any
638 if (!currentFeature->Suffix.empty()) {
639 this->Items.emplace_back(
640 BT<std::string>{ currentFeature->Suffix,
641 this->Items.back().Value.Backtrace },
642 ItemIsPath::No);
646 // Restore the target link type so the correct system runtime
647 // libraries are found.
648 cmValue lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
649 if (lss.IsOn()) {
650 this->SetCurrentLinkType(LinkStatic);
651 } else {
652 this->SetCurrentLinkType(this->StartLinkType);
655 // Finish listing compatibility paths.
656 if (this->OldLinkDirMode) {
657 // For CMake 2.4 bug-compatibility we need to consider the output
658 // directories of targets linked in another configuration as link
659 // directories.
660 std::set<cmGeneratorTarget const*> const& wrongItems =
661 cld.GetOldWrongConfigItems();
662 for (cmGeneratorTarget const* tgt : wrongItems) {
663 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
664 ? cmStateEnums::ImportLibraryArtifact
665 : cmStateEnums::RuntimeBinaryArtifact;
666 this->OldLinkDirItems.push_back(
667 tgt->GetFullPath(this->Config, artifact, true));
671 // Finish setting up linker search directories.
672 if (!this->FinishLinkerSearchDirectories()) {
673 return false;
676 // Add implicit language runtime libraries and directories.
677 this->AddImplicitLinkInfo();
679 if (!this->CMP0060WarnItems.empty()) {
680 std::ostringstream w;
681 /* clang-format off */
682 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0060) << "\n"
683 "Some library files are in directories implicitly searched by "
684 "the linker when invoked for " << this->LinkLanguage << ":\n"
685 " " << cmJoin(this->CMP0060WarnItems, "\n ") << "\n"
686 "For compatibility with older versions of CMake, the generated "
687 "link line will ask the linker to search for these by library "
688 "name."
690 /* clang-format on */
691 this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
692 this->Target->GetBacktrace());
695 // Record targets referenced by $<TARGET_OBJECTS:...> sources.
696 this->AddExternalObjectTargets();
698 return true;
701 namespace {
702 void FinalizeFeatureFormat(std::string& format, const std::string& activeTag,
703 const std::string& otherTag)
705 auto pos = format.find(otherTag);
706 if (pos != std::string::npos) {
707 format.erase(pos, format.find('}', pos) - pos + 1);
709 pos = format.find(activeTag);
710 if (pos != std::string::npos) {
711 format.erase(pos, activeTag.length());
712 pos = format.find('}', pos);
713 if (pos != std::string::npos) {
714 format.erase(pos, 1);
719 bool IsValidFeatureFormat(const std::string& format)
721 return format.find("<LIBRARY>") != std::string::npos ||
722 format.find("<LIB_ITEM>") != std::string::npos ||
723 format.find("<LINK_ITEM>") != std::string::npos;
726 class FeaturePlaceHolderExpander : public cmPlaceholderExpander
728 public:
729 FeaturePlaceHolderExpander(const std::string* library,
730 const std::string* libItem = nullptr,
731 const std::string* linkItem = nullptr)
732 : Library(library)
733 , LibItem(libItem)
734 , LinkItem(linkItem)
738 private:
739 std::string ExpandVariable(std::string const& variable) override
741 if (this->Library != nullptr && variable == "LIBRARY") {
742 return *this->Library;
744 if (this->LibItem != nullptr && variable == "LIB_ITEM") {
745 return *this->LibItem;
747 if (this->LinkItem != nullptr && variable == "LINK_ITEM") {
748 return *this->LinkItem;
751 return variable;
754 const std::string* Library = nullptr;
755 const std::string* LibItem = nullptr;
756 const std::string* LinkItem = nullptr;
760 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
761 std::string name, std::string itemFormat)
762 : Name(std::move(name))
763 , Supported(true)
764 , ItemPathFormat(std::move(itemFormat))
765 , ItemNameFormat(this->ItemPathFormat)
768 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
769 std::string name, std::string itemPathFormat, std::string itemNameFormat)
770 : Name(std::move(name))
771 , Supported(true)
772 , ItemPathFormat(std::move(itemPathFormat))
773 , ItemNameFormat(std::move(itemNameFormat))
776 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
777 std::string name, std::string prefix, std::string itemPathFormat,
778 std::string itemNameFormat, std::string suffix)
779 : Name(std::move(name))
780 , Supported(true)
781 , Prefix(std::move(prefix))
782 , Suffix(std::move(suffix))
783 , ItemPathFormat(std::move(itemPathFormat))
784 , ItemNameFormat(std::move(itemNameFormat))
787 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
788 std::string name, std::string prefix, std::string suffix, bool)
789 : Name(std::move(name))
790 , Supported(true)
791 , Prefix(std::move(prefix))
792 , Suffix(std::move(suffix))
796 std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
797 std::string const& library, ItemIsPath isPath) const
799 auto format =
800 isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
802 // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns with library path
803 FeaturePlaceHolderExpander expander(&library, &library, &library);
804 return expander.ExpandVariables(format);
806 std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
807 std::string const& library, std::string const& libItem,
808 std::string const& linkItem, ItemIsPath isPath) const
810 auto format =
811 isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
813 // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns
814 FeaturePlaceHolderExpander expander(&library, &libItem, &linkItem);
815 return expander.ExpandVariables(format);
818 cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
819 std::string name, std::string itemFormat)
820 : FeatureDescriptor(std::move(name), std::move(itemFormat))
823 cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
824 std::string name, std::string itemPathFormat, std::string itemNameFormat)
825 : FeatureDescriptor(std::move(name), std::move(itemPathFormat),
826 std::move(itemNameFormat))
829 cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
830 std::string name, std::string prefix, std::string itemPathFormat,
831 std::string itemNameFormat, std::string suffix)
832 : FeatureDescriptor(std::move(name), std::move(prefix),
833 std::move(itemPathFormat), std::move(itemNameFormat),
834 std::move(suffix))
838 bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature)
840 auto it = this->LibraryFeatureDescriptors.find(feature);
841 if (it != this->LibraryFeatureDescriptors.end()) {
842 return it->second.Supported;
845 auto featureName =
846 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_USING_", feature);
847 cmValue featureSupported =
848 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
849 if (!featureSupported) {
850 // language specific variable is not defined, fallback to the more generic
851 // one
852 featureName = cmStrCat("CMAKE_LINK_LIBRARY_USING_", feature);
853 featureSupported =
854 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
856 if (!featureSupported.IsOn()) {
857 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
859 this->CMakeInstance->IssueMessage(
860 MessageType::FATAL_ERROR,
861 cmStrCat(
862 "Feature '", feature,
863 "', specified through generator-expression '$<LINK_LIBRARY>' to "
864 "link target '",
865 this->Target->GetName(), "', is not supported for the '",
866 this->LinkLanguage, "' link language."),
867 this->Target->GetBacktrace());
869 return false;
872 cmValue langFeature = this->Makefile->GetDefinition(featureName);
873 if (!langFeature) {
874 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
876 this->CMakeInstance->IssueMessage(
877 MessageType::FATAL_ERROR,
878 cmStrCat(
879 "Feature '", feature,
880 "', specified through generator-expression '$<LINK_LIBRARY>' to "
881 "link target '",
882 this->Target->GetName(), "', is not defined for the '",
883 this->LinkLanguage, "' link language."),
884 this->Target->GetBacktrace());
886 return false;
889 auto items = cmExpandListWithBacktrace(
890 *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
892 if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) ||
893 (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) {
894 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
895 this->CMakeInstance->IssueMessage(
896 MessageType::FATAL_ERROR,
897 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
898 "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
899 "\"<LINK_ITEM>\" patterns "
900 "are missing) and cannot be used to link target '",
901 this->Target->GetName(), "'."),
902 this->Target->GetBacktrace());
904 return false;
907 // now, handle possible "PATH{}" and "NAME{}" patterns
908 if (items.size() == 1) {
909 items.push_back(items.front());
910 FinalizeFeatureFormat(items[0].Value, "PATH{", "NAME{");
911 FinalizeFeatureFormat(items[1].Value, "NAME{", "PATH{");
912 } else if (items.size() == 3) {
913 items.insert(items.begin() + 1, items[1]);
914 FinalizeFeatureFormat(items[1].Value, "PATH{", "NAME{");
915 FinalizeFeatureFormat(items[2].Value, "NAME{", "PATH{");
916 } else {
917 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
918 this->CMakeInstance->IssueMessage(
919 MessageType::FATAL_ERROR,
920 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
921 "', is malformed (wrong number of elements) and cannot be used "
922 "to link target '",
923 this->Target->GetName(), "'."),
924 this->Target->GetBacktrace());
926 return false;
928 if ((items.size() == 2 && !IsValidFeatureFormat(items[0].Value)) ||
929 (items.size() == 4 && !IsValidFeatureFormat(items[1].Value))) {
930 // PATH{} has wrong format
931 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
932 this->CMakeInstance->IssueMessage(
933 MessageType::FATAL_ERROR,
934 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
935 "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
936 "\"<LINK_ITEM>\" patterns "
937 "are missing for \"PATH{}\" alternative) and cannot be used to "
938 "link target '",
939 this->Target->GetName(), "'."),
940 this->Target->GetBacktrace());
942 return false;
944 if ((items.size() == 2 && !IsValidFeatureFormat(items[1].Value)) ||
945 (items.size() == 4 && !IsValidFeatureFormat(items[2].Value))) {
946 // NAME{} has wrong format
947 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
948 this->CMakeInstance->IssueMessage(
949 MessageType::FATAL_ERROR,
950 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
951 "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
952 "\"<LINK_ITEM>\" patterns "
953 "are missing for \"NAME{}\" alternative) and cannot be used to "
954 "link target '",
955 this->Target->GetName(), "'."),
956 this->Target->GetBacktrace());
958 return false;
961 // replace LINKER: pattern
962 this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
964 if (items.size() == 2) {
965 this->LibraryFeatureDescriptors.emplace(
966 feature,
967 LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value });
968 } else {
969 this->LibraryFeatureDescriptors.emplace(
970 feature,
971 LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value,
972 items[2].Value, items[3].Value });
975 return true;
978 cmComputeLinkInformation::FeatureDescriptor const&
979 cmComputeLinkInformation::GetLibraryFeature(std::string const& feature) const
981 return this->LibraryFeatureDescriptors.find(feature)->second;
983 cmComputeLinkInformation::FeatureDescriptor const*
984 cmComputeLinkInformation::FindLibraryFeature(std::string const& feature) const
986 auto it = this->LibraryFeatureDescriptors.find(feature);
987 if (it == this->LibraryFeatureDescriptors.end()) {
988 return nullptr;
991 return &it->second;
994 cmComputeLinkInformation::GroupFeatureDescriptor::GroupFeatureDescriptor(
995 std::string name, std::string prefix, std::string suffix)
996 : FeatureDescriptor(std::move(name), std::move(prefix), std::move(suffix),
997 true)
1001 cmComputeLinkInformation::FeatureDescriptor const&
1002 cmComputeLinkInformation::GetGroupFeature(std::string const& feature)
1004 auto it = this->GroupFeatureDescriptors.find(feature);
1005 if (it != this->GroupFeatureDescriptors.end()) {
1006 return it->second;
1009 auto featureName =
1010 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_GROUP_USING_", feature);
1011 cmValue featureSupported =
1012 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
1013 if (!featureSupported) {
1014 // language specific variable is not defined, fallback to the more generic
1015 // one
1016 featureName = cmStrCat("CMAKE_LINK_GROUP_USING_", feature);
1017 featureSupported =
1018 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
1020 if (!featureSupported.IsOn()) {
1021 this->CMakeInstance->IssueMessage(
1022 MessageType::FATAL_ERROR,
1023 cmStrCat("Feature '", feature,
1024 "', specified through generator-expression '$<LINK_GROUP>' to "
1025 "link target '",
1026 this->Target->GetName(), "', is not supported for the '",
1027 this->LinkLanguage, "' link language."),
1028 this->Target->GetBacktrace());
1029 return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1030 .first->second;
1033 cmValue langFeature = this->Makefile->GetDefinition(featureName);
1034 if (!langFeature) {
1035 this->CMakeInstance->IssueMessage(
1036 MessageType::FATAL_ERROR,
1037 cmStrCat("Feature '", feature,
1038 "', specified through generator-expression '$<LINK_GROUP>' to "
1039 "link target '",
1040 this->Target->GetName(), "', is not defined for the '",
1041 this->LinkLanguage, "' link language."),
1042 this->Target->GetBacktrace());
1043 return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1044 .first->second;
1047 auto items = cmExpandListWithBacktrace(
1048 *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
1050 // replace LINKER: pattern
1051 this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
1053 if (items.size() == 2) {
1054 return this->GroupFeatureDescriptors
1055 .emplace(
1056 feature,
1057 GroupFeatureDescriptor{ feature, items[0].Value, items[1].Value })
1058 .first->second;
1061 this->CMakeInstance->IssueMessage(
1062 MessageType::FATAL_ERROR,
1063 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
1064 "', is malformed (wrong number of elements) and cannot be used "
1065 "to link target '",
1066 this->Target->GetName(), "'."),
1067 this->Target->GetBacktrace());
1068 return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1069 .first->second;
1072 void cmComputeLinkInformation::AddExternalObjectTargets()
1074 std::vector<cmSourceFile const*> externalObjects;
1075 this->Target->GetExternalObjects(externalObjects, this->Config);
1076 std::set<std::string> emitted;
1077 for (auto const* externalObject : externalObjects) {
1078 std::string const& objLib = externalObject->GetObjectLibrary();
1079 if (objLib.empty()) {
1080 continue;
1082 if (emitted.insert(objLib).second) {
1083 cmLinkItem const& objItem =
1084 this->Target->ResolveLinkItem(BT<std::string>(objLib));
1085 if (objItem.Target) {
1086 this->ExternalObjectTargets.emplace_back(objItem.Target);
1092 void cmComputeLinkInformation::AddImplicitLinkInfo()
1094 // The link closure lists all languages whose implicit info is needed.
1095 cmGeneratorTarget::LinkClosure const* lc =
1096 this->Target->GetLinkClosure(this->Config);
1097 for (std::string const& li : lc->Languages) {
1099 if (li == "CUDA" || li == "HIP") {
1100 // These need to go before the other implicit link information
1101 // as they could require symbols from those other library
1102 // Currently restricted as CUDA and HIP are the only languages
1103 // we have documented runtime behavior controls for
1104 this->AddRuntimeLinkLibrary(li);
1107 // Skip those of the linker language. They are implicit.
1108 if (li != this->LinkLanguage) {
1109 this->AddImplicitLinkInfo(li);
1114 void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
1116 std::string const& runtimeLibrary =
1117 this->Target->GetRuntimeLinkLibrary(lang, this->Config);
1118 if (runtimeLibrary.empty()) {
1119 return;
1121 if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(cmStrCat(
1122 "CMAKE_", lang, "_RUNTIME_LIBRARY_LINK_OPTIONS_", runtimeLibrary))) {
1123 cmList libs{ *runtimeLinkOptions };
1124 for (auto const& i : libs) {
1125 if (!cm::contains(this->ImplicitLinkLibs, i)) {
1126 this->AddItem({ i });
1132 void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
1134 // Add libraries for this language that are not implied by the
1135 // linker language.
1136 std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
1137 if (cmValue libs = this->Makefile->GetDefinition(libVar)) {
1138 cmList libsList{ *libs };
1139 for (auto const& i : libsList) {
1140 if (!cm::contains(this->ImplicitLinkLibs, i)) {
1141 this->AddItem({ i });
1146 // Add linker search paths for this language that are not
1147 // implied by the linker language.
1148 std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
1149 if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
1150 cmList dirsList{ *dirs };
1151 this->OrderLinkerSearchPath->AddLanguageDirectories(dirsList);
1155 void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
1157 cmGeneratorTarget const* tgt = entry.Target;
1158 BT<std::string> const& item = entry.Item;
1160 // Compute the proper name to use to link this library.
1161 const std::string& config = this->Config;
1162 bool impexe = (tgt && tgt->IsExecutableWithExports());
1163 if (impexe && !tgt->HasImportLibrary(config) && !this->LoaderFlag) {
1164 // Skip linking to executables on platforms with no import
1165 // libraries or loader flags.
1166 return;
1169 if (tgt && tgt->IsLinkable()) {
1170 // This is a CMake target. Ask the target for its real name.
1171 if (impexe && this->LoaderFlag) {
1172 // This link item is an executable that may provide symbols
1173 // used by this target. A special flag is needed on this
1174 // platform. Add it now using a special feature.
1175 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
1176 ? cmStateEnums::ImportLibraryArtifact
1177 : cmStateEnums::RuntimeBinaryArtifact;
1178 std::string exe = tgt->GetFullPath(config, artifact, true);
1179 this->Items.emplace_back(
1180 BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt, nullptr,
1181 this->FindLibraryFeature(entry.Feature == DEFAULT
1182 ? "__CMAKE_LINK_EXECUTABLE"
1183 : entry.Feature));
1184 this->Depends.push_back(std::move(exe));
1185 } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1186 // Add the interface library as an item so it can be considered as part
1187 // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore
1188 // this for the actual link line.
1189 this->Items.emplace_back(std::string(), ItemIsPath::No, tgt);
1191 // Also add the item the interface specifies to be used in its place.
1192 std::string const& libName = tgt->GetImportedLibName(config);
1193 if (!libName.empty()) {
1194 this->AddItem(BT<std::string>(libName, item.Backtrace));
1196 } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1197 this->Items.emplace_back(item, ItemIsPath::No, tgt);
1198 } else if (this->GlobalGenerator->IsXcode() &&
1199 !tgt->GetImportedXcFrameworkPath(config).empty()) {
1200 this->Items.emplace_back(
1201 tgt->GetImportedXcFrameworkPath(config), ItemIsPath::Yes, tgt, nullptr,
1202 this->FindLibraryFeature(entry.Feature == DEFAULT
1203 ? "__CMAKE_LINK_XCFRAMEWORK"
1204 : entry.Feature));
1205 } else {
1206 // Decide whether to use an import library.
1207 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
1208 ? cmStateEnums::ImportLibraryArtifact
1209 : cmStateEnums::RuntimeBinaryArtifact;
1211 // Pass the full path to the target file.
1212 BT<std::string> lib = BT<std::string>(
1213 tgt->GetFullPath(config, artifact, true), item.Backtrace);
1214 if (tgt->IsAIX() && cmHasLiteralSuffix(lib.Value, "-NOTFOUND") &&
1215 artifact == cmStateEnums::ImportLibraryArtifact) {
1216 // This is an imported executable on AIX that has ENABLE_EXPORTS
1217 // but not IMPORTED_IMPLIB. CMake used to produce and accept such
1218 // imported executables on AIX before we taught it to use linker
1219 // import files. For compatibility, simply skip linking to this
1220 // executable as we did before. It works with runtime linking.
1221 return;
1223 if (!this->LinkDependsNoShared ||
1224 tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
1225 this->Depends.push_back(lib.Value);
1228 LinkEntry libEntry{ entry };
1229 libEntry.Item = lib;
1230 this->AddTargetItem(libEntry);
1231 if (tgt->IsApple() && tgt->HasImportLibrary(config)) {
1232 // Use the library rather than the tbd file for runpath computation
1233 this->AddLibraryRuntimeInfo(
1234 tgt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, true),
1235 tgt);
1236 } else {
1237 this->AddLibraryRuntimeInfo(lib.Value, tgt);
1239 if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
1240 this->Target->IsDLLPlatform()) {
1241 this->AddRuntimeDLL(tgt);
1245 auto xcFrameworkPath = tgt->GetImportedXcFrameworkPath(config);
1246 if (!xcFrameworkPath.empty()) {
1247 auto plist = cmParseXcFrameworkPlist(xcFrameworkPath, *this->Makefile,
1248 item.Backtrace);
1249 if (!plist) {
1250 return;
1252 if (auto const* library =
1253 plist->SelectSuitableLibrary(*this->Makefile, item.Backtrace)) {
1254 if (!library->HeadersPath.empty()) {
1255 this->AddXcFrameworkHeaderPath(cmStrCat(xcFrameworkPath, '/',
1256 library->LibraryIdentifier,
1257 '/', library->HeadersPath));
1259 } else {
1260 return;
1263 } else {
1264 // This is not a CMake target. Use the name given.
1265 if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) ||
1266 (entry.Feature == DEFAULT &&
1267 cmSystemTools::IsPathToFramework(item.Value) &&
1268 this->Target->IsApple())) {
1269 // This is a framework.
1270 this->AddFrameworkItem(entry);
1271 } else if (cmHasSuffix(entry.Feature, "XCFRAMEWORK"_s) ||
1272 (entry.Feature == DEFAULT &&
1273 cmSystemTools::IsPathToXcFramework(item.Value) &&
1274 this->Target->IsApple())) {
1275 // This is a framework.
1276 this->AddXcFrameworkItem(entry);
1277 } else if (cmSystemTools::FileIsFullPath(item.Value)) {
1278 if (cmSystemTools::FileIsDirectory(item.Value)) {
1279 // This is a directory.
1280 this->DropDirectoryItem(item);
1281 } else {
1282 // Use the full path given to the library file.
1283 this->Depends.push_back(item.Value);
1284 this->AddFullItem(entry);
1285 this->AddLibraryRuntimeInfo(item.Value);
1287 } else if (entry.Kind != cmComputeLinkDepends::LinkEntry::Object) {
1288 // This is a library or option specified by the user.
1289 this->AddUserItem(entry, true);
1294 void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry)
1296 BT<std::string> const& item = entry.Item;
1297 const cmGeneratorTarget* tgt = entry.Target;
1299 // Record dependencies on DLLs.
1300 if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
1301 this->Target->IsDLLPlatform() &&
1302 this->SharedDependencyMode != SharedDepModeLink) {
1303 this->AddRuntimeDLL(tgt);
1306 // If dropping shared library dependencies, ignore them.
1307 if (this->SharedDependencyMode == SharedDepModeNone) {
1308 return;
1311 // The user may have incorrectly named an item. Skip items that are
1312 // not full paths to shared libraries.
1313 if (tgt) {
1314 // The target will provide a full path. Make sure it is a shared
1315 // library.
1316 if (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
1317 return;
1319 } else {
1320 // Skip items that are not full paths. We will not be able to
1321 // reliably specify them.
1322 if (!cmSystemTools::FileIsFullPath(item.Value)) {
1323 return;
1326 // Get the name of the library from the file name.
1327 std::string file = cmSystemTools::GetFilenameName(item.Value);
1328 if (!this->ExtractSharedLibraryName.find(file)) {
1329 // This is not the name of a shared library.
1330 return;
1334 // If in linking mode, just link to the shared library.
1335 if (this->SharedDependencyMode == SharedDepModeLink ||
1336 // For an imported shared library without a known runtime artifact,
1337 // such as a CUDA stub, a library file named with the real soname
1338 // may not be available at all, so '-rpath-link' cannot help linkers
1339 // find it to satisfy '--no-allow-shlib-undefined' recursively.
1340 // Pass this dependency to the linker explicitly just in case.
1341 // If the linker also uses '--as-needed' behavior, this will not
1342 // add an unnecessary direct dependency.
1343 (tgt && tgt->IsImported() &&
1344 !tgt->HasKnownRuntimeArtifactLocation(this->Config) &&
1345 this->Target->LinkerEnforcesNoAllowShLibUndefined(this->Config))) {
1346 this->AddItem(entry);
1347 return;
1350 // Get a full path to the dependent shared library.
1351 // Add it to the runtime path computation so that the target being
1352 // linked will be able to find it.
1353 std::string lib;
1354 if (tgt) {
1355 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
1356 ? cmStateEnums::ImportLibraryArtifact
1357 : cmStateEnums::RuntimeBinaryArtifact;
1358 lib = tgt->GetFullPath(this->Config, artifact);
1359 if (tgt->IsApple() && tgt->HasImportLibrary(this->Config)) {
1360 // Use the library rather than the tbd file for runpath computation
1361 this->AddLibraryRuntimeInfo(
1362 tgt->GetFullPath(this->Config, cmStateEnums::RuntimeBinaryArtifact,
1363 true),
1364 tgt);
1365 } else {
1366 this->AddLibraryRuntimeInfo(lib, tgt);
1368 } else {
1369 lib = item.Value;
1370 this->AddLibraryRuntimeInfo(lib);
1373 // Check if we need to include the dependent shared library in other
1374 // path ordering.
1375 cmOrderDirectories* order = nullptr;
1376 if (this->SharedDependencyMode == SharedDepModeLibDir &&
1377 !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
1378 // Add the item to the linker search path.
1379 order = this->OrderLinkerSearchPath.get();
1380 } else if (this->SharedDependencyMode == SharedDepModeDir) {
1381 // Add the item to the separate dependent library search path.
1382 order = this->OrderDependentRPath.get();
1384 if (order) {
1385 if (tgt) {
1386 std::string soName = tgt->GetSOName(this->Config);
1387 const char* soname = soName.empty() ? nullptr : soName.c_str();
1388 order->AddRuntimeLibrary(lib, soname);
1389 } else {
1390 order->AddRuntimeLibrary(lib);
1395 void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
1397 if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
1398 this->RuntimeDLLs.end()) {
1399 this->RuntimeDLLs.emplace_back(tgt);
1403 void cmComputeLinkInformation::ComputeLinkTypeInfo()
1405 // Check whether archives may actually be shared libraries.
1406 this->ArchivesMayBeShared =
1407 this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1408 "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
1410 // First assume we cannot do link type stuff.
1411 this->LinkTypeEnabled = false;
1413 // Lookup link type selection flags.
1414 cmValue static_link_type_flag = nullptr;
1415 cmValue shared_link_type_flag = nullptr;
1416 const char* target_type_str = nullptr;
1417 switch (this->Target->GetType()) {
1418 case cmStateEnums::EXECUTABLE:
1419 target_type_str = "EXE";
1420 break;
1421 case cmStateEnums::SHARED_LIBRARY:
1422 target_type_str = "SHARED_LIBRARY";
1423 break;
1424 case cmStateEnums::MODULE_LIBRARY:
1425 target_type_str = "SHARED_MODULE";
1426 break;
1427 default:
1428 break;
1430 if (target_type_str) {
1431 std::string static_link_type_flag_var =
1432 cmStrCat("CMAKE_", target_type_str, "_LINK_STATIC_", this->LinkLanguage,
1433 "_FLAGS");
1434 static_link_type_flag =
1435 this->Makefile->GetDefinition(static_link_type_flag_var);
1437 std::string shared_link_type_flag_var =
1438 cmStrCat("CMAKE_", target_type_str, "_LINK_DYNAMIC_", this->LinkLanguage,
1439 "_FLAGS");
1440 shared_link_type_flag =
1441 this->Makefile->GetDefinition(shared_link_type_flag_var);
1444 // We can support link type switching only if all needed flags are
1445 // known.
1446 if (cmNonempty(static_link_type_flag) && cmNonempty(shared_link_type_flag)) {
1447 this->LinkTypeEnabled = true;
1448 this->StaticLinkTypeFlag = *static_link_type_flag;
1449 this->SharedLinkTypeFlag = *shared_link_type_flag;
1452 // Lookup the starting link type from the target (linked statically?).
1453 cmValue lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
1454 this->StartLinkType = lss.IsOn() ? LinkStatic : LinkShared;
1455 this->CurrentLinkType = this->StartLinkType;
1458 void cmComputeLinkInformation::ComputeItemParserInfo()
1460 // Get possible library name prefixes.
1461 cmMakefile* mf = this->Makefile;
1462 this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
1463 this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
1465 // Import library names should be matched and treated as shared
1466 // libraries for the purposes of linking.
1467 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
1468 LinkShared);
1469 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
1470 LinkStatic);
1471 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
1472 LinkShared);
1473 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
1474 LinkUnknown);
1475 if (cmValue linkSuffixes =
1476 mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
1477 cmList linkSuffixList{ *linkSuffixes };
1478 for (auto const& i : linkSuffixList) {
1479 this->AddLinkExtension(i, LinkUnknown);
1482 if (cmValue sharedSuffixes =
1483 mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
1484 cmList sharedSuffixList{ *sharedSuffixes };
1485 for (std::string const& i : sharedSuffixList) {
1486 this->AddLinkExtension(i, LinkShared);
1490 // Compute a regex to match link extensions.
1491 std::string libext =
1492 this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
1494 // Create regex to remove any library extension.
1495 std::string reg("(.*)");
1496 reg += libext;
1497 this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
1499 // Create a regex to match a library name. Match index 1 will be
1500 // the prefix if it exists and empty otherwise. Match index 2 will
1501 // be the library name. Match index 3 will be the library
1502 // extension.
1503 reg = "^(";
1504 for (std::string const& p : this->LinkPrefixes) {
1505 reg += p;
1506 reg += '|';
1508 reg += ")([^/:]*)";
1510 // Create a regex to match any library name.
1511 std::string reg_any = cmStrCat(reg, libext);
1512 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1513 fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
1514 #endif
1515 this->ExtractAnyLibraryName.compile(reg_any);
1517 // Create a regex to match static library names.
1518 if (!this->StaticLinkExtensions.empty()) {
1519 std::string reg_static = cmStrCat(
1520 reg, this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic));
1521 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1522 fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
1523 #endif
1524 this->ExtractStaticLibraryName.compile(reg_static);
1527 // Create a regex to match shared library names.
1528 if (!this->SharedLinkExtensions.empty()) {
1529 std::string reg_shared = reg;
1530 this->SharedRegexString =
1531 this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
1532 reg_shared += this->SharedRegexString;
1533 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1534 fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
1535 #endif
1536 this->ExtractSharedLibraryName.compile(reg_shared);
1540 void cmComputeLinkInformation::AddLinkPrefix(std::string const& p)
1542 if (!p.empty()) {
1543 this->LinkPrefixes.insert(p);
1547 void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
1548 LinkType type)
1550 if (!e.empty()) {
1551 if (type == LinkStatic) {
1552 this->StaticLinkExtensions.emplace_back(e);
1554 if (type == LinkShared) {
1555 this->SharedLinkExtensions.emplace_back(e);
1557 this->LinkExtensions.emplace_back(e);
1561 // XXX(clang-tidy): This method's const-ness is platform dependent, so we
1562 // cannot make it `const` as `clang-tidy` wants us to.
1563 // NOLINTNEXTLINE(readability-make-member-function-const)
1564 std::string cmComputeLinkInformation::CreateExtensionRegex(
1565 std::vector<std::string> const& exts, LinkType type)
1567 // Build a list of extension choices.
1568 std::string libext = "(";
1569 const char* sep = "";
1570 for (std::string const& i : exts) {
1571 // Separate this choice from the previous one.
1572 libext += sep;
1573 sep = "|";
1575 // Store this extension choice with the "." escaped.
1576 libext += "\\";
1577 #if defined(_WIN32) && !defined(__CYGWIN__)
1578 libext += this->NoCaseExpression(i);
1579 #else
1580 libext += i;
1581 #endif
1584 // Finish the list.
1585 libext += ')';
1587 // Add an optional OpenBSD-style version or major.minor.version component.
1588 if (this->IsOpenBSD || type == LinkShared) {
1589 libext += "(\\.[0-9]+)*";
1592 libext += '$';
1593 return libext;
1596 std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
1598 std::string ret;
1599 ret.reserve(str.size() * 4);
1600 for (char c : str) {
1601 if (c == '.') {
1602 ret += c;
1603 } else {
1604 ret += '[';
1605 ret += static_cast<char>(tolower(c));
1606 ret += static_cast<char>(toupper(c));
1607 ret += ']';
1610 return ret;
1613 void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
1615 // If we are changing the current link type add the flag to tell the
1616 // linker about it.
1617 if (this->CurrentLinkType != lt) {
1618 this->CurrentLinkType = lt;
1620 if (this->LinkTypeEnabled) {
1621 switch (this->CurrentLinkType) {
1622 case LinkStatic:
1623 this->Items.emplace_back(this->StaticLinkTypeFlag, ItemIsPath::No);
1624 break;
1625 case LinkShared:
1626 this->Items.emplace_back(this->SharedLinkTypeFlag, ItemIsPath::No);
1627 break;
1628 default:
1629 break;
1635 void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
1637 // This is called to handle a link item that is a full path to a target.
1638 // If the target is not a static library make sure the link type is
1639 // shared. This is because dynamic-mode linking can handle both
1640 // shared and static libraries but static-mode can handle only
1641 // static libraries. If a previous user item changed the link type
1642 // to static we need to make sure it is back to shared.
1643 BT<std::string> const& item = entry.Item;
1644 cmGeneratorTarget const* target = entry.Target;
1646 if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
1647 this->SetCurrentLinkType(LinkShared);
1650 // Keep track of shared library targets linked.
1651 if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
1652 this->SharedLibrariesLinked.insert(target);
1655 // Handle case of an imported shared library with no soname.
1656 if (this->NoSONameUsesPath &&
1657 target->IsImportedSharedLibWithoutSOName(this->Config)) {
1658 this->AddSharedLibNoSOName(entry);
1659 return;
1662 // For compatibility with CMake 2.4 include the item's directory in
1663 // the linker search path.
1664 if (this->OldLinkDirMode && !target->IsFrameworkOnApple() &&
1665 !cm::contains(this->OldLinkDirMask,
1666 cmSystemTools::GetFilenamePath(item.Value))) {
1667 this->OldLinkDirItems.push_back(item.Value);
1670 const bool isImportedFrameworkFolderOnApple =
1671 target->IsImportedFrameworkFolderOnApple(this->Config);
1672 if (target->IsFrameworkOnApple() || isImportedFrameworkFolderOnApple) {
1673 // Add the framework directory and the framework item itself
1674 auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
1675 item.Value, cmGlobalGenerator::FrameworkFormat::Extended);
1676 if (!fwDescriptor) {
1677 this->CMakeInstance->IssueMessage(
1678 MessageType::FATAL_ERROR,
1679 cmStrCat("Could not parse framework path \"", item.Value,
1680 "\" linked by target ", this->Target->GetName(), '.'),
1681 item.Backtrace);
1682 return;
1684 if (!fwDescriptor->Directory.empty()) {
1685 // Add the directory portion to the framework search path.
1686 this->AddFrameworkPath(fwDescriptor->Directory);
1689 if (this->GlobalGenerator->IsXcode()) {
1690 if (isImportedFrameworkFolderOnApple) {
1691 if (entry.Feature == DEFAULT) {
1692 this->AddLibraryFeature("FRAMEWORK");
1693 this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr,
1694 this->FindLibraryFeature("FRAMEWORK"));
1695 } else {
1696 this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr,
1697 this->FindLibraryFeature(entry.Feature));
1699 } else {
1700 this->Items.emplace_back(
1701 item, ItemIsPath::Yes, target, nullptr,
1702 this->FindLibraryFeature(entry.Feature == DEFAULT
1703 ? "__CMAKE_LINK_FRAMEWORK"
1704 : entry.Feature));
1706 } else {
1707 if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
1708 this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
1709 target, nullptr,
1710 this->FindLibraryFeature(entry.Feature));
1711 } else if (entry.Feature == DEFAULT &&
1712 isImportedFrameworkFolderOnApple) {
1713 this->AddLibraryFeature("FRAMEWORK");
1714 this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
1715 target, nullptr,
1716 this->FindLibraryFeature("FRAMEWORK"));
1717 } else {
1718 this->Items.emplace_back(
1719 item, ItemIsPath::Yes, target, nullptr,
1720 this->FindLibraryFeature(entry.Feature == DEFAULT
1721 ? "__CMAKE_LINK_LIBRARY"
1722 : entry.Feature));
1725 } else {
1726 // Now add the full path to the library.
1727 this->Items.emplace_back(
1728 item, ItemIsPath::Yes, target, nullptr,
1729 this->FindLibraryFeature(
1730 entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature));
1734 void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry)
1736 BT<std::string> const& item = entry.Item;
1738 // Check for the implicit link directory special case.
1739 if (this->CheckImplicitDirItem(entry)) {
1740 return;
1743 // Check for case of shared library with no builtin soname.
1744 if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(entry)) {
1745 return;
1748 // Full path libraries should specify a valid library file name.
1749 // See documentation of CMP0008.
1750 std::string generator = this->GlobalGenerator->GetName();
1751 if (this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
1752 (generator.find("Visual Studio") != std::string::npos ||
1753 generator.find("Xcode") != std::string::npos)) {
1754 std::string file = cmSystemTools::GetFilenameName(item.Value);
1755 if (!this->ExtractAnyLibraryName.find(file)) {
1756 this->HandleBadFullItem(entry, file);
1757 return;
1761 // This is called to handle a link item that is a full path.
1762 // If the target is not a static library make sure the link type is
1763 // shared. This is because dynamic-mode linking can handle both
1764 // shared and static libraries but static-mode can handle only
1765 // static libraries. If a previous user item changed the link type
1766 // to static we need to make sure it is back to shared.
1767 if (this->LinkTypeEnabled) {
1768 std::string name = cmSystemTools::GetFilenameName(item.Value);
1769 if (this->ExtractSharedLibraryName.find(name)) {
1770 this->SetCurrentLinkType(LinkShared);
1771 } else if (!this->ExtractStaticLibraryName.find(item.Value)) {
1772 // We cannot determine the type. Assume it is the target's
1773 // default type.
1774 this->SetCurrentLinkType(this->StartLinkType);
1778 // For compatibility with CMake 2.4 include the item's directory in
1779 // the linker search path.
1780 if (this->OldLinkDirMode &&
1781 !cm::contains(this->OldLinkDirMask,
1782 cmSystemTools::GetFilenamePath(item.Value))) {
1783 this->OldLinkDirItems.push_back(item.Value);
1786 // Now add the full path to the library.
1787 this->Items.emplace_back(
1788 item, ItemIsPath::Yes, nullptr, entry.ObjectSource,
1789 this->FindLibraryFeature(
1790 entry.Feature == DEFAULT
1791 ? (entry.Kind == cmComputeLinkDepends::LinkEntry::Object
1792 ? "__CMAKE_LINK_OBJECT"
1793 : "__CMAKE_LINK_LIBRARY")
1794 : entry.Feature));
1797 bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry)
1799 BT<std::string> const& item = entry.Item;
1801 // We only switch to a pathless item if the link type may be
1802 // enforced. Fortunately only platforms that support link types
1803 // seem to have magic per-architecture implicit link directories.
1804 if (!this->LinkTypeEnabled) {
1805 return false;
1808 // Check if this item is in an implicit link directory.
1809 std::string dir = cmSystemTools::GetFilenamePath(item.Value);
1810 if (!cm::contains(this->ImplicitLinkDirs, dir)) {
1811 // Only libraries in implicit link directories are converted to
1812 // pathless items.
1813 return false;
1816 // Only apply the policy below if the library file is one that can
1817 // be found by the linker.
1818 std::string file = cmSystemTools::GetFilenameName(item.Value);
1819 if (!this->ExtractAnyLibraryName.find(file)) {
1820 return false;
1823 // Check the policy for whether we should use the approach below.
1824 switch (this->Target->GetPolicyStatusCMP0060()) {
1825 case cmPolicies::WARN:
1826 if (this->CMP0060Warn) {
1827 // Print the warning at most once for this item.
1828 std::string const& wid =
1829 cmStrCat("CMP0060-WARNING-GIVEN-", item.Value);
1830 if (!this->CMakeInstance->GetPropertyAsBool(wid)) {
1831 this->CMakeInstance->SetProperty(wid, "1");
1832 this->CMP0060WarnItems.insert(item.Value);
1835 CM_FALLTHROUGH;
1836 case cmPolicies::OLD:
1837 break;
1838 case cmPolicies::REQUIRED_ALWAYS:
1839 case cmPolicies::REQUIRED_IF_USED:
1840 case cmPolicies::NEW:
1841 return false;
1844 // Many system linkers support multiple architectures by
1845 // automatically selecting the implicit linker search path for the
1846 // current architecture. If the library appears in an implicit link
1847 // directory then just report the file name without the directory
1848 // portion. This will allow the system linker to locate the proper
1849 // library for the architecture at link time.
1850 LinkEntry fileEntry{ entry };
1851 fileEntry.Item = file;
1852 this->AddUserItem(fileEntry, false);
1854 // Make sure the link directory ordering will find the library.
1855 this->OrderLinkerSearchPath->AddLinkLibrary(item.Value);
1857 return true;
1860 void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry,
1861 bool pathNotKnown)
1863 // This is called to handle a link item that does not match a CMake
1864 // target and is not a full path. We check here if it looks like a
1865 // library file name to automatically request the proper link type
1866 // from the linker. For example:
1868 // foo ==> -lfoo
1869 // libfoo.a ==> -Wl,-Bstatic -lfoo
1871 BT<std::string> const& item = entry.Item;
1873 if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') {
1874 // Pass flags through untouched.
1875 // if this is a -l option then we might need to warn about
1876 // CMP0003 so put it in OldUserFlagItems, if it is not a -l
1877 // or -Wl,-l (-framework -pthread), then allow it without a
1878 // CMP0003 as -L will not affect those other linker flags
1879 if (cmHasLiteralPrefix(item.Value, "-l") ||
1880 cmHasLiteralPrefix(item.Value, "-Wl,-l")) {
1881 // This is a linker option provided by the user.
1882 this->OldUserFlagItems.push_back(item.Value);
1885 // Restore the target link type since this item does not specify
1886 // one.
1887 this->SetCurrentLinkType(this->StartLinkType);
1889 // Use the item verbatim.
1890 this->Items.emplace_back(item, ItemIsPath::No);
1891 return;
1894 // Parse out the prefix, base, and suffix components of the
1895 // library name. If the name matches that of a shared or static
1896 // library then set the link type accordingly.
1898 // Search for shared library names first because some platforms
1899 // have shared libraries with names that match the static library
1900 // pattern. For example cygwin and msys use the convention
1901 // libfoo.dll.a for import libraries and libfoo.a for static
1902 // libraries. On AIX a library with the name libfoo.a can be
1903 // shared!
1904 std::string lib;
1905 if (this->ExtractSharedLibraryName.find(item.Value)) {
1906 // This matches a shared library file name.
1907 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1908 fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
1909 this->ExtractSharedLibraryName.match(1).c_str(),
1910 this->ExtractSharedLibraryName.match(2).c_str(),
1911 this->ExtractSharedLibraryName.match(3).c_str());
1912 #endif
1913 // Set the link type to shared.
1914 this->SetCurrentLinkType(LinkShared);
1916 // Use just the library name so the linker will search.
1917 lib = this->ExtractSharedLibraryName.match(2);
1918 } else if (this->ExtractStaticLibraryName.find(item.Value)) {
1919 // This matches a static library file name.
1920 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1921 fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
1922 this->ExtractStaticLibraryName.match(1).c_str(),
1923 this->ExtractStaticLibraryName.match(2).c_str(),
1924 this->ExtractStaticLibraryName.match(3).c_str());
1925 #endif
1926 // Set the link type to static.
1927 this->SetCurrentLinkType(LinkStatic);
1929 // Use just the library name so the linker will search.
1930 lib = this->ExtractStaticLibraryName.match(2);
1931 } else if (this->ExtractAnyLibraryName.find(item.Value)) {
1932 // This matches a library file name.
1933 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1934 fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
1935 this->ExtractAnyLibraryName.match(1).c_str(),
1936 this->ExtractAnyLibraryName.match(2).c_str(),
1937 this->ExtractAnyLibraryName.match(3).c_str());
1938 #endif
1939 // Restore the target link type since this item does not specify
1940 // one.
1941 this->SetCurrentLinkType(this->StartLinkType);
1943 // Use just the library name so the linker will search.
1944 lib = this->ExtractAnyLibraryName.match(2);
1945 } else {
1946 // This is a name specified by the user.
1947 if (pathNotKnown) {
1948 this->OldUserFlagItems.push_back(item.Value);
1951 // We must ask the linker to search for a library with this name.
1952 // Restore the target link type since this item does not specify
1953 // one.
1954 this->SetCurrentLinkType(this->StartLinkType);
1955 lib = item.Value;
1958 // Create an option to ask the linker to search for the library.
1959 auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
1961 if (entry.Feature != DEFAULT) {
1962 auto const& feature = this->GetLibraryFeature(entry.Feature);
1963 this->Items.emplace_back(
1964 BT<std::string>(
1965 feature.GetDecoratedItem(cmStrCat(lib, this->LibLinkSuffix),
1966 item.Value, out, ItemIsPath::No),
1967 item.Backtrace),
1968 ItemIsPath::No);
1969 } else {
1970 this->Items.emplace_back(BT<std::string>(out, item.Backtrace),
1971 ItemIsPath::No);
1974 // Here we could try to find the library the linker will find and
1975 // add a runtime information entry for it. It would probably not be
1976 // reliable and we want to encourage use of full paths for library
1977 // specification.
1980 void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
1982 std::string const& item = entry.Item.Value;
1984 // Try to separate the framework name and path.
1985 auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
1986 item,
1987 entry.Feature == DEFAULT ? cmGlobalGenerator::FrameworkFormat::Relaxed
1988 : cmGlobalGenerator::FrameworkFormat::Extended);
1989 if (!fwDescriptor) {
1990 std::ostringstream e;
1991 e << "Could not parse framework path \"" << item << "\" linked by target "
1992 << this->Target->GetName() << '.';
1993 cmSystemTools::Error(e.str());
1994 return;
1997 const std::string& fw_path = fwDescriptor->Directory;
1998 if (!fw_path.empty()) {
1999 // Add the directory portion to the framework search path.
2000 this->AddFrameworkPath(fw_path);
2003 // add runtime information
2004 this->AddLibraryRuntimeInfo(fwDescriptor->GetFullPath());
2006 if (entry.Feature == DEFAULT) {
2007 // ensure FRAMEWORK feature is loaded
2008 this->AddLibraryFeature("FRAMEWORK");
2011 if (this->GlobalGenerator->IsXcode()) {
2012 // Add framework path - it will be handled by Xcode after it's added to
2013 // "Link Binary With Libraries" build phase
2014 this->Items.emplace_back(item, ItemIsPath::Yes, nullptr, nullptr,
2015 this->FindLibraryFeature(entry.Feature == DEFAULT
2016 ? "FRAMEWORK"
2017 : entry.Feature));
2018 } else {
2019 this->Items.emplace_back(
2020 fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr, nullptr,
2021 this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK"
2022 : entry.Feature));
2026 void cmComputeLinkInformation::AddXcFrameworkItem(LinkEntry const& entry)
2028 auto plist = cmParseXcFrameworkPlist(entry.Item.Value, *this->Makefile,
2029 entry.Item.Backtrace);
2030 if (!plist) {
2031 return;
2034 if (auto const* lib =
2035 plist->SelectSuitableLibrary(*this->Makefile, entry.Item.Backtrace)) {
2036 if (this->GlobalGenerator->IsXcode()) {
2037 this->Items.emplace_back(
2038 entry.Item.Value, ItemIsPath::Yes, nullptr, nullptr,
2039 this->FindLibraryFeature(entry.Feature == DEFAULT
2040 ? "__CMAKE_LINK_XCFRAMEWORK"
2041 : entry.Feature));
2042 } else {
2043 auto libraryPath = cmStrCat(
2044 entry.Item.Value, '/', lib->LibraryIdentifier, '/', lib->LibraryPath);
2045 LinkEntry libraryEntry(
2046 BT<std::string>(libraryPath, entry.Item.Backtrace), entry.Target);
2048 if (cmSystemTools::IsPathToFramework(libraryPath) &&
2049 this->Target->IsApple()) {
2050 // This is a framework.
2051 this->AddFrameworkItem(libraryEntry);
2052 } else {
2053 this->Depends.push_back(libraryPath);
2054 this->AddFullItem(libraryEntry);
2055 this->AddLibraryRuntimeInfo(libraryPath);
2056 if (!lib->HeadersPath.empty()) {
2057 this->AddXcFrameworkHeaderPath(cmStrCat(entry.Item.Value, '/',
2058 lib->LibraryIdentifier, '/',
2059 lib->HeadersPath));
2066 void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item)
2068 // A full path to a directory was found as a link item. Warn the
2069 // user.
2070 this->CMakeInstance->IssueMessage(
2071 MessageType::WARNING,
2072 cmStrCat("Target \"", this->Target->GetName(),
2073 "\" requests linking to directory \"", item.Value,
2074 "\". Targets may link only to libraries. CMake is dropping "
2075 "the item."),
2076 item.Backtrace);
2079 void cmComputeLinkInformation::ComputeFrameworkInfo()
2081 // Avoid adding implicit framework paths.
2082 cmList implicitDirs;
2084 // Get platform-wide implicit directories.
2085 implicitDirs.assign(this->Makefile->GetDefinition(
2086 "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"));
2088 // Get language-specific implicit directories.
2089 std::string implicitDirVar = cmStrCat(
2090 "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES");
2091 implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar));
2093 this->FrameworkPathsEmitted.insert(implicitDirs.begin(), implicitDirs.end());
2096 void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
2098 if (this->FrameworkPathsEmitted.insert(p).second) {
2099 this->FrameworkPaths.push_back(p);
2103 void cmComputeLinkInformation::AddXcFrameworkHeaderPath(std::string const& p)
2105 this->XcFrameworkHeaderPaths.push_back(p);
2108 bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry)
2110 // This platform will use the path to a library as its soname if the
2111 // library is given via path and was not built with an soname. If
2112 // this is a shared library that might be the case.
2113 std::string file = cmSystemTools::GetFilenameName(entry.Item.Value);
2114 if (this->ExtractSharedLibraryName.find(file)) {
2115 // If we can guess the soname fairly reliably then assume the
2116 // library has one. Otherwise assume the library has no builtin
2117 // soname.
2118 std::string soname;
2119 if (!cmSystemTools::GuessLibrarySOName(entry.Item.Value, soname)) {
2120 this->AddSharedLibNoSOName(entry);
2121 return true;
2124 return false;
2127 void cmComputeLinkInformation::AddSharedLibNoSOName(LinkEntry const& entry)
2129 // We have a full path to a shared library with no soname. We need
2130 // to ask the linker to locate the item because otherwise the path
2131 // we give to it will be embedded in the target linked. Then at
2132 // runtime the dynamic linker will search for the library using the
2133 // path instead of just the name.
2134 LinkEntry fileEntry{ entry };
2135 fileEntry.Item = cmSystemTools::GetFilenameName(entry.Item.Value);
2136 this->AddUserItem(fileEntry, false);
2138 // Make sure the link directory ordering will find the library.
2139 this->OrderLinkerSearchPath->AddLinkLibrary(entry.Item.Value);
2142 void cmComputeLinkInformation::HandleBadFullItem(LinkEntry const& entry,
2143 std::string const& file)
2145 std::string const& item = entry.Item.Value;
2146 // Do not depend on things that do not exist.
2147 auto i = std::find(this->Depends.begin(), this->Depends.end(), item);
2148 if (i != this->Depends.end()) {
2149 this->Depends.erase(i);
2152 // Tell the linker to search for the item and provide the proper
2153 // path for it. Do not contribute to any CMP0003 warning (do not
2154 // put in OldLinkDirItems or OldUserFlagItems).
2155 LinkEntry fileEntry{ entry };
2156 fileEntry.Item = file;
2157 this->AddUserItem(fileEntry, false);
2158 this->OrderLinkerSearchPath->AddLinkLibrary(item);
2160 // Produce any needed message.
2161 switch (this->Target->GetPolicyStatusCMP0008()) {
2162 case cmPolicies::WARN: {
2163 // Print the warning at most once for this item.
2164 std::string wid = cmStrCat("CMP0008-WARNING-GIVEN-", item);
2165 if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(wid)) {
2166 this->CMakeInstance->GetState()->SetGlobalProperty(wid, "1");
2167 std::ostringstream w;
2168 /* clang-format off */
2169 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0008) << "\n"
2170 "Target \"" << this->Target->GetName() << "\" links to item\n"
2171 " " << item << "\n"
2172 "which is a full-path but not a valid library file name.";
2173 /* clang-format on */
2174 this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
2175 this->Target->GetBacktrace());
2178 CM_FALLTHROUGH;
2179 case cmPolicies::OLD: // NOLINT(bugprone-branch-clone)
2180 // OLD behavior does not warn.
2181 break;
2182 case cmPolicies::NEW:
2183 // NEW behavior will not get here.
2184 break;
2185 case cmPolicies::REQUIRED_IF_USED:
2186 case cmPolicies::REQUIRED_ALWAYS: {
2187 std::ostringstream e;
2188 /* clang-format off */
2189 e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0008) << "\n"
2190 "Target \"" << this->Target->GetName() << "\" links to item\n"
2191 " " << item << "\n"
2192 "which is a full-path but not a valid library file name.";
2193 /* clang-format on */
2194 this->CMakeInstance->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2195 this->Target->GetBacktrace());
2196 } break;
2200 bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
2202 // Support broken projects if necessary.
2203 if (this->OldLinkDirItems.empty() || this->OldUserFlagItems.empty() ||
2204 !this->OldLinkDirMode) {
2205 return true;
2208 // Enforce policy constraints.
2209 switch (this->Target->GetPolicyStatusCMP0003()) {
2210 case cmPolicies::WARN:
2211 if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
2212 "CMP0003-WARNING-GIVEN")) {
2213 this->CMakeInstance->GetState()->SetGlobalProperty(
2214 "CMP0003-WARNING-GIVEN", "1");
2215 std::ostringstream w;
2216 this->PrintLinkPolicyDiagnosis(w);
2217 this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
2218 this->Target->GetBacktrace());
2220 CM_FALLTHROUGH;
2221 case cmPolicies::OLD:
2222 // OLD behavior is to add the paths containing libraries with
2223 // known full paths as link directories.
2224 break;
2225 case cmPolicies::NEW:
2226 // Should never happen due to assignment of OldLinkDirMode
2227 return true;
2228 case cmPolicies::REQUIRED_IF_USED:
2229 case cmPolicies::REQUIRED_ALWAYS: {
2230 std::ostringstream e;
2231 e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0003) << '\n';
2232 this->PrintLinkPolicyDiagnosis(e);
2233 this->CMakeInstance->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2234 this->Target->GetBacktrace());
2235 return false;
2239 // Add the link directories for full path items.
2240 for (std::string const& i : this->OldLinkDirItems) {
2241 this->OrderLinkerSearchPath->AddLinkLibrary(i);
2243 return true;
2246 void cmComputeLinkInformation::PrintLinkPolicyDiagnosis(std::ostream& os)
2248 // Tell the user what to do.
2249 /* clang-format off */
2250 os << "Policy CMP0003 should be set before this line. "
2251 "Add code such as\n"
2252 " if(COMMAND cmake_policy)\n"
2253 " cmake_policy(SET CMP0003 NEW)\n"
2254 " endif(COMMAND cmake_policy)\n"
2255 "as early as possible but after the most recent call to "
2256 "cmake_minimum_required or cmake_policy(VERSION). ";
2257 /* clang-format on */
2259 // List the items that might need the old-style paths.
2260 os << "This warning appears because target \"" << this->Target->GetName()
2261 << "\" links to some libraries for which the linker must search:\n";
2263 // Format the list of unknown items to be as short as possible while
2264 // still fitting in the allowed width (a true solution would be the
2265 // bin packing problem if we were allowed to change the order).
2266 std::string::size_type max_size = 76;
2267 std::string line;
2268 const char* sep = " ";
2269 for (std::string const& i : this->OldUserFlagItems) {
2270 // If the addition of another item will exceed the limit then
2271 // output the current line and reset it. Note that the separator
2272 // is either " " or ", " which is always 2 characters.
2273 if (!line.empty() && (line.size() + i.size() + 2) > max_size) {
2274 os << line << '\n';
2275 sep = " ";
2276 line.clear();
2278 line += sep;
2279 line += i;
2280 // Convert to the other separator.
2281 sep = ", ";
2283 if (!line.empty()) {
2284 os << line << '\n';
2288 // List the paths old behavior is adding.
2289 os << "and other libraries with known full path:\n";
2290 std::set<std::string> emitted;
2291 for (std::string const& i : this->OldLinkDirItems) {
2292 if (emitted.insert(cmSystemTools::GetFilenamePath(i)).second) {
2293 os << " " << i << '\n';
2297 // Explain.
2298 os << "CMake is adding directories in the second list to the linker "
2299 "search path in case they are needed to find libraries from the "
2300 "first list (for backwards compatibility with CMake 2.4). "
2301 "Set policy CMP0003 to OLD or NEW to enable or disable this "
2302 "behavior explicitly. "
2303 "Run \"cmake --help-policy CMP0003\" for more information.";
2306 void cmComputeLinkInformation::LoadImplicitLinkInfo()
2308 // Get platform-wide implicit directories.
2309 cmList implicitDirs{ this->Makefile->GetDefinition(
2310 "CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES") };
2312 // Append library architecture to all implicit platform directories
2313 // and add them to the set
2314 if (cmValue libraryArch =
2315 this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
2316 for (auto const& i : implicitDirs) {
2317 this->ImplicitLinkDirs.insert(cmStrCat(i, '/', *libraryArch));
2321 // Get language-specific implicit directories.
2322 std::string implicitDirVar =
2323 cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES");
2324 implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar));
2326 // Store implicit link directories.
2327 this->ImplicitLinkDirs.insert(implicitDirs.begin(), implicitDirs.end());
2329 // Get language-specific implicit libraries.
2330 std::string implicitLibVar =
2331 cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES");
2332 cmList implicitLibs{ this->Makefile->GetDefinition(implicitLibVar) };
2334 // Store implicit link libraries.
2335 for (auto const& item : implicitLibs) {
2336 // Items starting in '-' but not '-l' are flags, not libraries,
2337 // and should not be filtered by this implicit list.
2338 if (item[0] != '-' || item[1] == 'l') {
2339 this->ImplicitLinkLibs.insert(item);
2343 // Get platform specific rpath link directories
2344 cmList::append(this->RuntimeLinkDirs,
2345 this->Makefile->GetDefinition("CMAKE_PLATFORM_RUNTIME_PATH"));
2348 std::vector<std::string> const&
2349 cmComputeLinkInformation::GetRuntimeSearchPath() const
2351 return this->OrderRuntimeSearchPath->GetOrderedDirectories();
2354 void cmComputeLinkInformation::AddLibraryRuntimeInfo(
2355 std::string const& fullPath, cmGeneratorTarget const* target)
2357 // Ignore targets on Apple where install_name is not @rpath.
2358 // The dependenty library can be found with other means such as
2359 // @loader_path or full paths.
2360 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2361 if (!target->HasMacOSXRpathInstallNameDir(this->Config)) {
2362 return;
2366 // Libraries with unknown type must be handled using just the file
2367 // on disk.
2368 if (target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
2369 this->AddLibraryRuntimeInfo(fullPath);
2370 return;
2373 // Skip targets that are not shared libraries (modules cannot be linked).
2374 if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
2375 return;
2378 // Skip targets that do not have a known runtime artifact.
2379 if (!target->HasKnownRuntimeArtifactLocation(this->Config)) {
2380 return;
2383 // Try to get the soname of the library. Only files with this name
2384 // could possibly conflict.
2385 std::string soName = target->GetSOName(this->Config);
2386 const char* soname = soName.empty() ? nullptr : soName.c_str();
2388 // Include this library in the runtime path ordering.
2389 this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
2390 if (this->LinkWithRuntimePath) {
2391 this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
2395 void cmComputeLinkInformation::AddLibraryRuntimeInfo(
2396 std::string const& fullPath)
2398 // Get the name of the library from the file name.
2399 bool is_shared_library = false;
2400 std::string file = cmSystemTools::GetFilenameName(fullPath);
2402 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2403 // Check that @rpath is part of the install name.
2404 // If it isn't, return.
2405 std::string soname;
2406 if (!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) {
2407 return;
2410 if (soname.find("@rpath") == std::string::npos) {
2411 return;
2415 is_shared_library = this->ExtractSharedLibraryName.find(file);
2417 if (!is_shared_library) {
2418 // On some platforms (AIX) a shared library may look static.
2419 if (this->ArchivesMayBeShared) {
2420 if (this->ExtractStaticLibraryName.find(file)) {
2421 // This is the name of a shared library or archive.
2422 is_shared_library = true;
2427 // It could be an Apple framework
2428 if (!is_shared_library) {
2429 is_shared_library =
2430 this->GlobalGenerator
2431 ->SplitFrameworkPath(fullPath,
2432 cmGlobalGenerator::FrameworkFormat::Strict)
2433 .has_value();
2436 if (!is_shared_library) {
2437 return;
2440 // Include this library in the runtime path ordering.
2441 this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
2442 if (this->LinkWithRuntimePath) {
2443 this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
2447 static void cmCLI_ExpandListUnique(std::string const& str,
2448 std::vector<std::string>& out,
2449 std::set<std::string>& emitted)
2451 cmList tmp{ str };
2452 for (std::string const& i : tmp) {
2453 if (emitted.insert(i).second) {
2454 out.push_back(i);
2459 void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
2460 bool for_install) const
2462 // Select whether to generate runtime search directories.
2463 bool outputRuntime =
2464 !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->RuntimeFlag.empty();
2466 // Select whether to generate an rpath for the install tree or the
2467 // build tree.
2468 bool linking_for_install =
2469 (for_install ||
2470 this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
2471 bool use_install_rpath =
2472 (outputRuntime && this->Target->HaveInstallTreeRPATH(this->Config) &&
2473 linking_for_install);
2474 bool use_build_rpath =
2475 (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
2476 !linking_for_install);
2477 bool use_link_rpath = outputRuntime && linking_for_install &&
2478 !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
2479 this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
2481 // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree.
2482 std::string const& originToken = this->Makefile->GetSafeDefinition(
2483 "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN");
2484 std::string targetOutputDir = this->Target->GetDirectory(this->Config);
2485 bool use_relative_build_rpath =
2486 this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") &&
2487 !originToken.empty() && !targetOutputDir.empty();
2489 // Construct the RPATH.
2490 std::set<std::string> emitted;
2491 if (use_install_rpath) {
2492 std::string install_rpath;
2493 this->Target->GetInstallRPATH(this->Config, install_rpath);
2494 cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
2496 if (use_build_rpath) {
2497 // Add directories explicitly specified by user
2498 std::string build_rpath;
2499 if (this->Target->GetBuildRPATH(this->Config, build_rpath)) {
2500 // This will not resolve entries to use $ORIGIN, the user is expected
2501 // to do that if necessary.
2502 cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
2505 if (use_build_rpath || use_link_rpath) {
2506 std::string rootPath;
2507 if (cmValue sysrootLink =
2508 this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
2509 rootPath = *sysrootLink;
2510 } else {
2511 rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
2513 cmValue stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
2514 std::string const& installPrefix =
2515 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2516 cmSystemTools::ConvertToUnixSlashes(rootPath);
2517 std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
2518 std::string const& topBinaryDir =
2519 this->CMakeInstance->GetHomeOutputDirectory();
2520 for (std::string const& ri : rdirs) {
2521 // Put this directory in the rpath if using build-tree rpath
2522 // support or if using the link path as an rpath.
2523 if (use_build_rpath) {
2524 std::string d = ri;
2525 if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
2526 d.erase(0, rootPath.size());
2527 } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
2528 d.erase(0, (*stagePath).size());
2529 d = cmStrCat(installPrefix, '/', d);
2530 cmSystemTools::ConvertToUnixSlashes(d);
2531 } else if (use_relative_build_rpath) {
2532 // If expansion of the $ORIGIN token is supported and permitted per
2533 // policy, use relative paths in the RPATH.
2534 if (cmSystemTools::ComparePath(d, topBinaryDir) ||
2535 cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
2536 d = cmSystemTools::RelativePath(targetOutputDir, d);
2537 if (!d.empty()) {
2538 d = cmStrCat(originToken, "/", d);
2539 } else {
2540 d = originToken;
2544 if (emitted.insert(d).second) {
2545 runtimeDirs.push_back(std::move(d));
2547 } else if (use_link_rpath) {
2548 // Do not add any path inside the source or build tree.
2549 std::string const& topSourceDir =
2550 this->CMakeInstance->GetHomeDirectory();
2551 if (!cmSystemTools::ComparePath(ri, topSourceDir) &&
2552 !cmSystemTools::ComparePath(ri, topBinaryDir) &&
2553 !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
2554 !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
2555 std::string d = ri;
2556 if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
2557 d.erase(0, rootPath.size());
2558 } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
2559 d.erase(0, (*stagePath).size());
2560 d = cmStrCat(installPrefix, '/', d);
2561 cmSystemTools::ConvertToUnixSlashes(d);
2563 if (emitted.insert(d).second) {
2564 runtimeDirs.push_back(std::move(d));
2571 // Add runtime paths required by the languages to always be
2572 // present. This is done even when skipping rpath support.
2574 cmGeneratorTarget::LinkClosure const* lc =
2575 this->Target->GetLinkClosure(this->Config);
2576 for (std::string const& li : lc->Languages) {
2577 std::string useVar = cmStrCat(
2578 "CMAKE_", li, "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH");
2579 if (this->Makefile->IsOn(useVar)) {
2580 std::string dirVar =
2581 cmStrCat("CMAKE_", li, "_IMPLICIT_LINK_DIRECTORIES");
2582 if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
2583 cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
2589 // Add runtime paths required by the platform to always be
2590 // present. This is done even when skipping rpath support.
2591 cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted);
2594 std::string cmComputeLinkInformation::GetRPathString(bool for_install) const
2596 // Get the directories to use.
2597 std::vector<std::string> runtimeDirs;
2598 this->GetRPath(runtimeDirs, for_install);
2600 // Concatenate the paths.
2601 std::string rpath = cmJoin(runtimeDirs, this->GetRuntimeSep());
2603 // If the rpath will be replaced at install time, prepare space.
2604 if (!for_install && this->RuntimeUseChrpath) {
2605 if (!rpath.empty()) {
2606 // Add one trailing separator so the linker does not reuse the
2607 // rpath .dynstr entry for a symbol name that happens to match
2608 // the end of the rpath string.
2609 rpath += this->GetRuntimeSep();
2612 // Make sure it is long enough to hold the replacement value.
2613 std::string::size_type minLength = this->GetChrpathString().length();
2614 while (rpath.length() < minLength) {
2615 rpath += this->GetRuntimeSep();
2619 return rpath;
2622 std::string cmComputeLinkInformation::GetChrpathString() const
2624 if (!this->RuntimeUseChrpath) {
2625 return "";
2628 return this->GetRPathString(true);