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"
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 "cmListFileCache.h"
19 #include "cmLocalGenerator.h"
20 #include "cmMakefile.h"
21 #include "cmMessageType.h"
22 #include "cmOrderDirectories.h"
23 #include "cmPlaceholderExpander.h"
24 #include "cmPolicies.h"
26 #include "cmStateTypes.h"
27 #include "cmStringAlgorithms.h"
28 #include "cmSystemTools.h"
33 //#define CM_COMPUTE_LINK_INFO_DEBUG
36 Notes about linking on various platforms:
38 ------------------------------------------------------------------------------
40 Linux, FreeBSD, macOS, Sun, Windows:
42 Linking to libraries using the full path works fine.
44 ------------------------------------------------------------------------------
46 On AIX, more work is needed.
48 The "-bnoipath" option is needed. From "man ld":
50 Note: If you specify a shared object, or an archive file
51 containing a shared object, with an absolute or relative path
52 name, instead of with the -lName flag, the path name is
53 included in the import file ID string in the loader section of
54 the output file. You can override this behavior with the
59 For shared objects listed on the command-line, rather than
60 specified with the -l flag, use a null path component when
61 listing the shared object in the loader section of the
62 output file. A null path component is always used for
63 shared objects specified with the -l flag. This option
64 does not affect the specification of a path component by
65 using a line beginning with #! in an import file. The
66 default is the ipath option.
68 This prevents the full path specified on the compile line from being
69 compiled directly into the binary.
71 By default the linker places -L paths in the embedded runtime path.
72 In order to implement CMake's RPATH interface correctly, we need the
73 -blibpath:Path option. From "man ld":
77 Uses Path as the library path when writing the loader section
78 of the output file. Path is neither checked for validity nor
79 used when searching for libraries specified by the -l flag.
80 Path overrides any library paths generated when the -L flag is
83 If you do not specify any -L flags, or if you specify the
84 nolibpath option, the default library path information is
85 written in the loader section of the output file. The default
86 library path information is the value of the LIBPATH
87 environment variable if it is defined, and /usr/lib:/lib,
90 We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
91 and not break when the user sets LIBPATH. Then if we want to add an
92 rpath we insert it into the option before /usr/lib.
94 ------------------------------------------------------------------------------
96 On HP-UX, more work is needed. There are differences between
99 ld: 92453-07 linker linker ld B.10.33 990520
101 Linking with a full path works okay for static and shared libraries.
102 The linker seems to always put the full path to where the library
103 was found in the binary whether using a full path or -lfoo syntax.
104 Transitive link dependencies work just fine due to the full paths.
106 It has the "-l:libfoo.sl" option. The +nodefaultrpath is accepted
107 but not documented and does not seem to do anything. There is no
110 ld: 92453-07 linker ld HP Itanium(R) B.12.41 IPF/IPF
112 Linking with a full path works okay for static libraries.
114 Linking with a full path works okay for shared libraries. However
115 dependent (transitive) libraries of those linked directly must be
116 either found with an rpath stored in the direct dependencies or
117 found in -L paths as if they were specified with "-l:libfoo.sl"
118 (really "-l:<soname>"). The search matches that of the dynamic
119 loader but only with -L paths. In other words, if we have an
120 executable that links to shared library bar which links to shared
121 library foo, the link line for the exe must contain
123 /dir/with/bar/libbar.sl -L/dir/with/foo
125 It does not matter whether the exe wants to link to foo directly or
126 whether /dir/with/foo/libfoo.sl is listed. The -L path must still
127 be present. It should match the runtime path computed for the
128 executable taking all directly and transitively linked libraries
131 The "+nodefaultrpath" option should be used to avoid getting -L
132 paths in the rpath unless we add our own rpath with +b. This means
133 that skip-build-rpath should use this option.
135 See documentation in "man ld", "man dld.so", and
136 http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm
139 +defaultrpath is the default. Include any paths that are
140 specified with -L in the embedded path, unless you specify the
141 +b option. If you use +b, only the path list specified by +b is
142 in the embedded path.
144 The +nodefaultrpath option removes all library paths that were
145 specified with the -L option from the embedded path. The linker
146 searches the library paths specified by the -L option at link
147 time. At run time, the only library paths searched are those
148 specified by the environment variables LD_LIBRARY_PATH and
149 SHLIB_PATH, library paths specified by the +b linker option, and
150 finally the default library paths.
153 This option will cause the paths specified in RPATH (embedded
154 path) to be used before the paths specified in LD_LIBRARY_PATH
155 or SHLIB_PATH, in searching for shared libraries. This changes
156 the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
157 RPATH (embedded path).
159 ------------------------------------------------------------------------------
160 Notes about dependent (transitive) shared libraries:
162 On non-Windows systems shared libraries may have transitive
163 dependencies. In order to support LINK_INTERFACE_LIBRARIES we must
164 support linking to a shared library without listing all the libraries
165 to which it links. Some linkers want to be able to find the
166 transitive dependencies (dependent libraries) of shared libraries
167 listed on the command line.
169 - On Windows, DLLs are not directly linked, and the import libraries
170 have no transitive dependencies.
172 - On Mac OS X 10.5 and above transitive dependencies are not needed.
174 - On Mac OS X 10.4 and below we need to actually list the dependencies.
175 Otherwise when using -isysroot for universal binaries it cannot
176 find the dependent libraries. Listing them on the command line
177 tells the linker where to find them, but unfortunately also links
180 - On HP-UX, the linker wants to find the transitive dependencies of
181 shared libraries in the -L paths even if the dependent libraries
182 are given on the link line.
184 - On AIX the transitive dependencies are not needed.
186 - On SGI, the linker wants to find the transitive dependencies of
187 shared libraries in the -L paths if they are not given on the link
188 line. Transitive linking can be disabled using the options
190 -no_transitive_link -Wl,-no_transitive_link
192 which disable it. Both options must be given when invoking the
193 linker through the compiler.
195 - On Sun, the linker wants to find the transitive dependencies of
196 shared libraries in the -L paths if they are not given on the link
199 - On Linux, FreeBSD, and QNX:
201 The linker wants to find the transitive dependencies of shared
202 libraries in the "-rpath-link" paths option if they have not been
203 given on the link line. The option is like rpath but just for
206 -Wl,-rpath-link,"/path1:/path2"
208 For -rpath-link, we need a separate runtime path ordering pass
209 including just the dependent libraries that are not linked.
211 For -L paths on non-HP, we can do the same thing as with rpath-link
212 but put the results in -L paths. The paths should be listed at the
213 end to avoid conflicting with user search paths (?).
215 For -L paths on HP, we should do a runtime path ordering pass with
216 all libraries, both linked and non-linked. Even dependent
217 libraries that are also linked need to be listed in -L paths.
219 In our implementation we add all dependent libraries to the runtime
220 path computation. Then the auto-generated RPATH will find everything.
222 ------------------------------------------------------------------------------
223 Notes about shared libraries with not builtin soname:
225 Some UNIX shared libraries may be created with no builtin soname. On
226 some platforms such libraries cannot be linked using the path to their
227 location because the linker will copy the path into the field used to
228 find the library at runtime.
230 Apple: ../libfoo.dylib ==> libfoo.dylib # ok, uses install_name
231 SGI: ../libfoo.so ==> libfoo.so # ok
232 AIX: ../libfoo.so ==> libfoo.so # ok
233 Linux: ../libfoo.so ==> ../libfoo.so # bad
234 HP-UX: ../libfoo.so ==> ../libfoo.so # bad
235 Sun: ../libfoo.so ==> ../libfoo.so # bad
236 FreeBSD: ../libfoo.so ==> ../libfoo.so # bad
238 In order to link these libraries we need to use the old-style split
239 into -L.. and -lfoo options. This should be fairly safe because most
240 problems with -lfoo options were related to selecting shared libraries
241 instead of static but in this case we want the shared lib. Link
242 directory ordering needs to be done to make sure these shared
243 libraries are found first. There should be very few restrictions
244 because this need be done only for shared libraries without soname-s.
248 cmComputeLinkInformation::cmComputeLinkInformation(
249 const cmGeneratorTarget* target, const std::string& config)
250 // Store context information.
252 , Makefile(target->Target->GetMakefile())
253 , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
254 , CMakeInstance(this->GlobalGenerator->GetCMakeInstance())
255 // The configuration being linked.
258 // Check whether to recognize OpenBSD-style library versioned names.
259 this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
260 "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
262 // Allocate internals.
263 this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>(
264 this->GlobalGenerator, target, "linker search path");
265 this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>(
266 this->GlobalGenerator, target, "runtime search path");
268 // Get the language used for linking this target.
269 this->LinkLanguage = this->Target->GetLinkerLanguage(config);
270 if (this->LinkLanguage.empty()) {
271 // The Compute method will do nothing, so skip the rest of the
276 // Check whether we should skip dependencies on shared library files.
277 this->LinkDependsNoShared =
278 this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
280 // On platforms without import libraries there may be a special flag
281 // to use when creating a plugin (module) that obtains symbols from
282 // the program that will load it.
283 if (!this->Target->IsDLLPlatform() &&
284 this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
285 std::string loader_flag_var =
286 cmStrCat("CMAKE_SHARED_MODULE_LOADER_", this->LinkLanguage, "_FLAG");
287 this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
290 // Get options needed to link libraries.
291 if (cmValue flag = this->Makefile->GetDefinition(
292 "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_FLAG")) {
293 this->LibLinkFlag = *flag;
296 this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
298 if (cmValue flag = this->Makefile->GetDefinition(
299 "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_FILE_FLAG")) {
300 this->LibLinkFileFlag = *flag;
302 this->LibLinkFileFlag =
303 this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
305 if (cmValue suffix = this->Makefile->GetDefinition(
306 "CMAKE_" + this->LinkLanguage + "_LINK_LIBRARY_SUFFIX")) {
307 this->LibLinkSuffix = *suffix;
309 this->LibLinkSuffix =
310 this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
312 if (cmValue flag = this->Makefile->GetDefinition(
313 "CMAKE_" + this->LinkLanguage + "_LINK_OBJECT_FILE_FLAG")) {
314 this->ObjLinkFileFlag = *flag;
316 this->ObjLinkFileFlag =
317 this->Makefile->GetSafeDefinition("CMAKE_LINK_OBJECT_FILE_FLAG");
320 // Get options needed to specify RPATHs.
321 this->RuntimeUseChrpath = false;
322 if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
323 const char* tType = ((this->Target->GetType() == cmStateEnums::EXECUTABLE)
327 cmStrCat("CMAKE_", tType, "_RUNTIME_", this->LinkLanguage, "_FLAG");
328 std::string rtSepVar = rtVar + "_SEP";
329 this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
330 this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
331 this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
332 "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
334 this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
336 // Get options needed to help find dependent libraries.
338 cmStrCat("CMAKE_", tType, "_RPATH_LINK_", this->LinkLanguage, "_FLAG");
339 this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
342 // Check if we need to include the runtime search path at link time.
344 std::string var = cmStrCat("CMAKE_SHARED_LIBRARY_LINK_",
345 this->LinkLanguage, "_WITH_RUNTIME_PATH");
346 this->LinkWithRuntimePath = this->Makefile->IsOn(var);
349 // Define some Feature descriptors to handle standard library and object link
350 if (!this->GetLibLinkFileFlag().empty()) {
351 this->LibraryFeatureDescriptors.emplace(
352 "__CMAKE_LINK_LIBRARY",
353 LibraryFeatureDescriptor{
354 "__CMAKE_LINK_LIBRARY",
355 cmStrCat(this->GetLibLinkFileFlag(), "<LIBRARY>") });
357 if (!this->GetObjLinkFileFlag().empty()) {
358 this->LibraryFeatureDescriptors.emplace(
359 "__CMAKE_LINK_OBJECT",
360 LibraryFeatureDescriptor{
361 "__CMAKE_LINK_OBJECT",
362 cmStrCat(this->GetObjLinkFileFlag(), "<LIBRARY>") });
364 if (!this->LoaderFlag->empty()) {
365 // Define a Feature descriptor for the link of an executable with exports
366 this->LibraryFeatureDescriptors.emplace(
367 "__CMAKE_LINK_EXECUTABLE",
368 LibraryFeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE",
369 cmStrCat(this->LoaderFlag, "<LIBRARY>") });
371 // To link framewortk using a full path
372 this->LibraryFeatureDescriptors.emplace(
373 "__CMAKE_LINK_FRAMEWORK",
374 LibraryFeatureDescriptor{ "__CMAKE_LINK_FRAMEWORK", "<LIBRARY>" });
376 // Check the platform policy for missing soname case.
377 this->NoSONameUsesPath =
378 this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
380 // Get link type information.
381 this->ComputeLinkTypeInfo();
383 // Setup the link item parser.
384 this->ComputeItemParserInfo();
386 // Setup framework support.
387 this->ComputeFrameworkInfo();
389 // Choose a mode for dealing with shared library dependencies.
390 this->SharedDependencyMode = SharedDepModeNone;
391 if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
392 this->SharedDependencyMode = SharedDepModeLink;
393 } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
394 this->SharedDependencyMode = SharedDepModeLibDir;
395 } else if (!this->RPathLinkFlag.empty()) {
396 this->SharedDependencyMode = SharedDepModeDir;
397 this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>(
398 this->GlobalGenerator, target, "dependent library path");
401 // Add the search path entries requested by the user to path ordering.
402 std::vector<std::string> directories;
403 this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
404 this->OrderLinkerSearchPath->AddUserDirectories(directories);
405 this->OrderRuntimeSearchPath->AddUserDirectories(directories);
407 // Set up the implicit link directories.
408 this->LoadImplicitLinkInfo();
409 this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
410 this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
411 if (this->OrderDependentRPath) {
412 this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
413 this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
416 // Decide whether to enable compatible library search path mode.
417 // There exists code that effectively does
419 // /path/to/libA.so -lB
421 // where -lB is meant to link to /path/to/libB.so. This is broken
422 // because it specified -lB without specifying a link directory (-L)
423 // in which to search for B. This worked in CMake 2.4 and below
424 // because -L/path/to would be added by the -L/-l split for A. In
425 // order to support such projects we need to add the directories
426 // containing libraries linked with a full path to the -L path.
427 this->OldLinkDirMode =
428 this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
429 if (this->OldLinkDirMode) {
430 // Construct a mask to not bother with this behavior for link
431 // directories already specified by the user.
432 this->OldLinkDirMask.insert(directories.begin(), directories.end());
435 this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
436 "CMAKE_POLICY_WARNING_CMP0060");
439 cmComputeLinkInformation::~cmComputeLinkInformation() = default;
442 const std::string& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT;
445 void cmComputeLinkInformation::AppendValues(
446 std::string& result, std::vector<BT<std::string>>& values)
448 for (BT<std::string>& p : values) {
449 if (result.empty()) {
453 result.append(p.Value);
457 cmComputeLinkInformation::ItemVector const&
458 cmComputeLinkInformation::GetItems() const
463 std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
466 return this->OrderLinkerSearchPath->GetOrderedDirectories();
469 std::vector<BT<std::string>>
470 cmComputeLinkInformation::GetDirectoriesWithBacktraces()
472 std::vector<BT<std::string>> directoriesWithBacktraces;
474 std::vector<BT<std::string>> targetLinkDirectores =
475 this->Target->GetLinkDirectories(this->Config, this->LinkLanguage);
477 const std::vector<std::string>& orderedDirectories = this->GetDirectories();
478 for (const std::string& dir : orderedDirectories) {
480 std::find(targetLinkDirectores.begin(), targetLinkDirectores.end(), dir);
481 if (result != targetLinkDirectores.end()) {
482 directoriesWithBacktraces.emplace_back(std::move(*result));
484 directoriesWithBacktraces.emplace_back(dir);
488 return directoriesWithBacktraces;
491 std::string cmComputeLinkInformation::GetRPathLinkString() const
493 // If there is no separate linker runtime search flag (-rpath-link)
494 // there is no reason to compute a string.
495 if (!this->OrderDependentRPath) {
499 // Construct the linker runtime search path. These MUST NOT contain tokens
500 // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
501 return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
504 std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const
506 return this->Depends;
509 std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
512 return this->FrameworkPaths;
515 std::set<std::string> const&
516 cmComputeLinkInformation::GetFrameworkPathsEmitted() const
518 return this->FrameworkPathsEmitted;
521 const std::set<const cmGeneratorTarget*>&
522 cmComputeLinkInformation::GetSharedLibrariesLinked() const
524 return this->SharedLibrariesLinked;
527 bool cmComputeLinkInformation::Compute()
529 // Skip targets that do not link.
530 if (!(this->Target->GetType() == cmStateEnums::EXECUTABLE ||
531 this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
532 this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
533 this->Target->GetType() == cmStateEnums::STATIC_LIBRARY)) {
537 // We require a link language for the target.
538 if (this->LinkLanguage.empty()) {
539 cmSystemTools::Error(
540 "CMake can not determine linker language for target: " +
541 this->Target->GetName());
545 // Compute the ordered link line items.
546 cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage);
547 cld.SetOldLinkDirMode(this->OldLinkDirMode);
548 cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
549 FeatureDescriptor const* currentFeature = nullptr;
551 // Add the link line items.
552 for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) {
553 if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::Group) {
554 const auto& groupFeature = this->GetGroupFeature(linkEntry.Feature);
555 if (groupFeature.Supported) {
556 if (linkEntry.Item.Value == "</LINK_GROUP>" &&
557 currentFeature != nullptr) {
558 // emit feature suffix, if any
559 if (!currentFeature->Suffix.empty()) {
560 this->Items.emplace_back(
561 BT<std::string>{ currentFeature->Suffix,
562 this->Items.back().Value.Backtrace },
565 currentFeature = nullptr;
567 this->Items.emplace_back(
568 BT<std::string>{ linkEntry.Item.Value == "<LINK_GROUP>"
569 ? groupFeature.Prefix
570 : groupFeature.Suffix,
571 linkEntry.Item.Backtrace },
577 if (currentFeature != nullptr &&
578 linkEntry.Feature != currentFeature->Name) {
579 // emit feature suffix, if any
580 if (!currentFeature->Suffix.empty()) {
581 this->Items.emplace_back(
582 BT<std::string>{ currentFeature->Suffix,
583 this->Items.back().Value.Backtrace },
586 currentFeature = nullptr;
589 if (linkEntry.Feature != DEFAULT &&
590 (currentFeature == nullptr ||
591 linkEntry.Feature != currentFeature->Name)) {
592 if (!this->AddLibraryFeature(linkEntry.Feature)) {
595 currentFeature = this->FindLibraryFeature(linkEntry.Feature);
596 // emit feature prefix, if any
597 if (!currentFeature->Prefix.empty()) {
598 this->Items.emplace_back(
599 BT<std::string>{ currentFeature->Prefix, linkEntry.Item.Backtrace },
604 if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::SharedDep) {
605 this->AddSharedDepItem(linkEntry);
607 this->AddItem(linkEntry);
611 if (currentFeature != nullptr) {
612 // emit feature suffix, if any
613 if (!currentFeature->Suffix.empty()) {
614 this->Items.emplace_back(
615 BT<std::string>{ currentFeature->Suffix,
616 this->Items.back().Value.Backtrace },
621 // Restore the target link type so the correct system runtime
622 // libraries are found.
623 cmValue lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
625 this->SetCurrentLinkType(LinkStatic);
627 this->SetCurrentLinkType(this->StartLinkType);
630 // Finish listing compatibility paths.
631 if (this->OldLinkDirMode) {
632 // For CMake 2.4 bug-compatibility we need to consider the output
633 // directories of targets linked in another configuration as link
635 std::set<cmGeneratorTarget const*> const& wrongItems =
636 cld.GetOldWrongConfigItems();
637 for (cmGeneratorTarget const* tgt : wrongItems) {
638 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
639 ? cmStateEnums::ImportLibraryArtifact
640 : cmStateEnums::RuntimeBinaryArtifact;
641 this->OldLinkDirItems.push_back(
642 tgt->GetFullPath(this->Config, artifact, true));
646 // Finish setting up linker search directories.
647 if (!this->FinishLinkerSearchDirectories()) {
651 // Add implicit language runtime libraries and directories.
652 this->AddImplicitLinkInfo();
654 if (!this->CMP0060WarnItems.empty()) {
655 std::ostringstream w;
656 /* clang-format off */
657 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0060) << "\n"
658 "Some library files are in directories implicitly searched by "
659 "the linker when invoked for " << this->LinkLanguage << ":\n"
660 " " << cmJoin(this->CMP0060WarnItems, "\n ") << "\n"
661 "For compatibility with older versions of CMake, the generated "
662 "link line will ask the linker to search for these by library "
665 /* clang-format on */
666 this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
667 this->Target->GetBacktrace());
674 void FinalizeFeatureFormat(std::string& format, const std::string& activeTag,
675 const std::string& otherTag)
677 auto pos = format.find(otherTag);
678 if (pos != std::string::npos) {
679 format.erase(pos, format.find('}', pos) - pos + 1);
681 pos = format.find(activeTag);
682 if (pos != std::string::npos) {
683 format.erase(pos, activeTag.length());
684 pos = format.find('}', pos);
685 if (pos != std::string::npos) {
686 format.erase(pos, 1);
691 bool IsValidFeatureFormat(const std::string& format)
693 return format.find("<LIBRARY>") != std::string::npos ||
694 format.find("<LIB_ITEM>") != std::string::npos ||
695 format.find("<LINK_ITEM>") != std::string::npos;
698 class FeaturePlaceHolderExpander : public cmPlaceholderExpander
701 FeaturePlaceHolderExpander(const std::string* library,
702 const std::string* libItem = nullptr,
703 const std::string* linkItem = nullptr)
711 std::string ExpandVariable(std::string const& variable) override
713 if (this->Library != nullptr && variable == "LIBRARY") {
714 return *this->Library;
716 if (this->LibItem != nullptr && variable == "LIB_ITEM") {
717 return *this->LibItem;
719 if (this->LinkItem != nullptr && variable == "LINK_ITEM") {
720 return *this->LinkItem;
726 const std::string* Library = nullptr;
727 const std::string* LibItem = nullptr;
728 const std::string* LinkItem = nullptr;
732 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
733 std::string name, std::string itemFormat)
734 : Name(std::move(name))
736 , ItemPathFormat(std::move(itemFormat))
737 , ItemNameFormat(this->ItemPathFormat)
740 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
741 std::string name, std::string itemPathFormat, std::string itemNameFormat)
742 : Name(std::move(name))
744 , ItemPathFormat(std::move(itemPathFormat))
745 , ItemNameFormat(std::move(itemNameFormat))
748 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
749 std::string name, std::string prefix, std::string itemPathFormat,
750 std::string itemNameFormat, std::string suffix)
751 : Name(std::move(name))
753 , Prefix(std::move(prefix))
754 , Suffix(std::move(suffix))
755 , ItemPathFormat(std::move(itemPathFormat))
756 , ItemNameFormat(std::move(itemNameFormat))
759 cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
760 std::string name, std::string prefix, std::string suffix, bool)
761 : Name(std::move(name))
763 , Prefix(std::move(prefix))
764 , Suffix(std::move(suffix))
768 std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
769 std::string const& library, ItemIsPath isPath) const
772 isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
774 // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns with library path
775 FeaturePlaceHolderExpander expander(&library, &library, &library);
776 return expander.ExpandVariables(format);
778 std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
779 std::string const& library, std::string const& libItem,
780 std::string const& linkItem, ItemIsPath isPath) const
783 isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
785 // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns
786 FeaturePlaceHolderExpander expander(&library, &libItem, &linkItem);
787 return expander.ExpandVariables(format);
790 cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
791 std::string name, std::string itemFormat)
792 : FeatureDescriptor(std::move(name), std::move(itemFormat))
795 cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
796 std::string name, std::string itemPathFormat, std::string itemNameFormat)
797 : FeatureDescriptor(std::move(name), std::move(itemPathFormat),
798 std::move(itemNameFormat))
801 cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
802 std::string name, std::string prefix, std::string itemPathFormat,
803 std::string itemNameFormat, std::string suffix)
804 : FeatureDescriptor(std::move(name), std::move(prefix),
805 std::move(itemPathFormat), std::move(itemNameFormat),
810 bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature)
812 auto it = this->LibraryFeatureDescriptors.find(feature);
813 if (it != this->LibraryFeatureDescriptors.end()) {
814 return it->second.Supported;
818 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_USING_", feature);
819 cmValue featureSupported =
820 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
821 if (!featureSupported) {
822 // language specific variable is not defined, fallback to the more generic
824 featureName = cmStrCat("CMAKE_LINK_LIBRARY_USING_", feature);
826 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
828 if (!featureSupported.IsOn()) {
829 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
831 this->CMakeInstance->IssueMessage(
832 MessageType::FATAL_ERROR,
834 "Feature '", feature,
835 "', specified through generator-expression '$<LINK_LIBRARY>' to "
837 this->Target->GetName(), "', is not supported for the '",
838 this->LinkLanguage, "' link language."),
839 this->Target->GetBacktrace());
844 cmValue langFeature = this->Makefile->GetDefinition(featureName);
846 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
848 this->CMakeInstance->IssueMessage(
849 MessageType::FATAL_ERROR,
851 "Feature '", feature,
852 "', specified through generator-expression '$<LINK_LIBRARY>' to "
854 this->Target->GetName(), "', is not defined for the '",
855 this->LinkLanguage, "' link language."),
856 this->Target->GetBacktrace());
862 cmExpandListWithBacktrace(langFeature, this->Target->GetBacktrace(), true);
864 if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) ||
865 (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) {
866 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
867 this->CMakeInstance->IssueMessage(
868 MessageType::FATAL_ERROR,
869 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
870 "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
871 "\"<LINK_ITEM>\" patterns "
872 "are missing) and cannot be used to link target '",
873 this->Target->GetName(), "'."),
874 this->Target->GetBacktrace());
879 // now, handle possible "PATH{}" and "NAME{}" patterns
880 if (items.size() == 1) {
881 items.push_back(items.front());
882 FinalizeFeatureFormat(items[0].Value, "PATH{", "NAME{");
883 FinalizeFeatureFormat(items[1].Value, "NAME{", "PATH{");
884 } else if (items.size() == 3) {
885 items.insert(items.begin() + 1, items[1]);
886 FinalizeFeatureFormat(items[1].Value, "PATH{", "NAME{");
887 FinalizeFeatureFormat(items[2].Value, "NAME{", "PATH{");
889 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
890 this->CMakeInstance->IssueMessage(
891 MessageType::FATAL_ERROR,
892 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
893 "', is malformed (wrong number of elements) and cannot be used "
895 this->Target->GetName(), "'."),
896 this->Target->GetBacktrace());
900 if ((items.size() == 2 && !IsValidFeatureFormat(items[0].Value)) ||
901 (items.size() == 4 && !IsValidFeatureFormat(items[1].Value))) {
902 // PATH{} has wrong format
903 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
904 this->CMakeInstance->IssueMessage(
905 MessageType::FATAL_ERROR,
906 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
907 "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
908 "\"<LINK_ITEM>\" patterns "
909 "are missing for \"PATH{}\" alternative) and cannot be used to "
911 this->Target->GetName(), "'."),
912 this->Target->GetBacktrace());
916 if ((items.size() == 2 && !IsValidFeatureFormat(items[1].Value)) ||
917 (items.size() == 4 && !IsValidFeatureFormat(items[2].Value))) {
918 // NAME{} has wrong format
919 this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
920 this->CMakeInstance->IssueMessage(
921 MessageType::FATAL_ERROR,
922 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
923 "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
924 "\"<LINK_ITEM>\" patterns "
925 "are missing for \"NAME{}\" alternative) and cannot be used to "
927 this->Target->GetName(), "'."),
928 this->Target->GetBacktrace());
933 // replace LINKER: pattern
934 this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
936 if (items.size() == 2) {
937 this->LibraryFeatureDescriptors.emplace(
939 LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value });
941 this->LibraryFeatureDescriptors.emplace(
943 LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value,
944 items[2].Value, items[3].Value });
950 cmComputeLinkInformation::FeatureDescriptor const&
951 cmComputeLinkInformation::GetLibraryFeature(std::string const& feature) const
953 return this->LibraryFeatureDescriptors.find(feature)->second;
955 cmComputeLinkInformation::FeatureDescriptor const*
956 cmComputeLinkInformation::FindLibraryFeature(std::string const& feature) const
958 auto it = this->LibraryFeatureDescriptors.find(feature);
959 if (it == this->LibraryFeatureDescriptors.end()) {
966 cmComputeLinkInformation::GroupFeatureDescriptor::GroupFeatureDescriptor(
967 std::string name, std::string prefix, std::string suffix)
968 : FeatureDescriptor(std::move(name), std::move(prefix), std::move(suffix),
973 cmComputeLinkInformation::FeatureDescriptor const&
974 cmComputeLinkInformation::GetGroupFeature(std::string const& feature)
976 auto it = this->GroupFeatureDescriptors.find(feature);
977 if (it != this->GroupFeatureDescriptors.end()) {
982 cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_GROUP_USING_", feature);
983 cmValue featureSupported =
984 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
985 if (!featureSupported) {
986 // language specific variable is not defined, fallback to the more generic
988 featureName = cmStrCat("CMAKE_LINK_GROUP_USING_", feature);
990 this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
992 if (!featureSupported.IsOn()) {
993 this->CMakeInstance->IssueMessage(
994 MessageType::FATAL_ERROR,
995 cmStrCat("Feature '", feature,
996 "', specified through generator-expression '$<LINK_GROUP>' to "
998 this->Target->GetName(), "', is not supported for the '",
999 this->LinkLanguage, "' link language."),
1000 this->Target->GetBacktrace());
1001 return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1005 cmValue langFeature = this->Makefile->GetDefinition(featureName);
1007 this->CMakeInstance->IssueMessage(
1008 MessageType::FATAL_ERROR,
1009 cmStrCat("Feature '", feature,
1010 "', specified through generator-expression '$<LINK_GROUP>' to "
1012 this->Target->GetName(), "', is not defined for the '",
1013 this->LinkLanguage, "' link language."),
1014 this->Target->GetBacktrace());
1015 return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1020 cmExpandListWithBacktrace(langFeature, this->Target->GetBacktrace(), true);
1022 // replace LINKER: pattern
1023 this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
1025 if (items.size() == 2) {
1026 return this->GroupFeatureDescriptors
1029 GroupFeatureDescriptor{ feature, items[0].Value, items[1].Value })
1033 this->CMakeInstance->IssueMessage(
1034 MessageType::FATAL_ERROR,
1035 cmStrCat("Feature '", feature, "', specified by variable '", featureName,
1036 "', is malformed (wrong number of elements) and cannot be used "
1038 this->Target->GetName(), "'."),
1039 this->Target->GetBacktrace());
1040 return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
1044 void cmComputeLinkInformation::AddImplicitLinkInfo()
1046 // The link closure lists all languages whose implicit info is needed.
1047 cmGeneratorTarget::LinkClosure const* lc =
1048 this->Target->GetLinkClosure(this->Config);
1049 for (std::string const& li : lc->Languages) {
1051 if (li == "CUDA" || li == "HIP") {
1052 // These need to go before the other implicit link information
1053 // as they could require symbols from those other library
1054 // Currently restricted as CUDA and HIP are the only languages
1055 // we have documented runtime behavior controls for
1056 this->AddRuntimeLinkLibrary(li);
1059 // Skip those of the linker language. They are implicit.
1060 if (li != this->LinkLanguage) {
1061 this->AddImplicitLinkInfo(li);
1066 void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
1068 std::string const& runtimeLibrary =
1069 this->Target->GetRuntimeLinkLibrary(lang, this->Config);
1070 if (runtimeLibrary.empty()) {
1073 if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(
1074 "CMAKE_" + lang + "_RUNTIME_LIBRARY_LINK_OPTIONS_" + runtimeLibrary)) {
1075 std::vector<std::string> libsVec = cmExpandedList(*runtimeLinkOptions);
1076 for (std::string const& i : libsVec) {
1077 if (!cm::contains(this->ImplicitLinkLibs, i)) {
1078 this->AddItem({ i });
1084 void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
1086 // Add libraries for this language that are not implied by the
1088 std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
1089 if (cmValue libs = this->Makefile->GetDefinition(libVar)) {
1090 std::vector<std::string> libsVec = cmExpandedList(*libs);
1091 for (std::string const& i : libsVec) {
1092 if (!cm::contains(this->ImplicitLinkLibs, i)) {
1093 this->AddItem({ i });
1098 // Add linker search paths for this language that are not
1099 // implied by the linker language.
1100 std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
1101 if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
1102 std::vector<std::string> dirsVec = cmExpandedList(*dirs);
1103 this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec);
1107 void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
1109 cmGeneratorTarget const* tgt = entry.Target;
1110 BT<std::string> const& item = entry.Item;
1112 // Compute the proper name to use to link this library.
1113 const std::string& config = this->Config;
1114 bool impexe = (tgt && tgt->IsExecutableWithExports());
1115 if (impexe && !tgt->HasImportLibrary(config) && !this->LoaderFlag) {
1116 // Skip linking to executables on platforms with no import
1117 // libraries or loader flags.
1121 if (tgt && tgt->IsLinkable()) {
1122 // This is a CMake target. Ask the target for its real name.
1123 if (impexe && this->LoaderFlag) {
1124 // This link item is an executable that may provide symbols
1125 // used by this target. A special flag is needed on this
1126 // platform. Add it now using a special feature.
1127 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
1128 ? cmStateEnums::ImportLibraryArtifact
1129 : cmStateEnums::RuntimeBinaryArtifact;
1130 std::string exe = tgt->GetFullPath(config, artifact, true);
1131 this->Items.emplace_back(
1132 BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt,
1133 this->FindLibraryFeature(entry.Feature == DEFAULT
1134 ? "__CMAKE_LINK_EXECUTABLE"
1136 this->Depends.push_back(std::move(exe));
1137 } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
1138 // Add the interface library as an item so it can be considered as part
1139 // of COMPATIBLE_INTERFACE_ enforcement. The generators will ignore
1140 // this for the actual link line.
1141 this->Items.emplace_back(std::string(), ItemIsPath::No, tgt);
1143 // Also add the item the interface specifies to be used in its place.
1144 std::string const& libName = tgt->GetImportedLibName(config);
1145 if (!libName.empty()) {
1146 this->AddItem(BT<std::string>(libName, item.Backtrace));
1148 } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
1149 // Ignore object library!
1150 // Its object-files should already have been extracted for linking.
1152 // Decide whether to use an import library.
1153 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
1154 ? cmStateEnums::ImportLibraryArtifact
1155 : cmStateEnums::RuntimeBinaryArtifact;
1157 // Pass the full path to the target file.
1158 BT<std::string> lib = BT<std::string>(
1159 tgt->GetFullPath(config, artifact, true), item.Backtrace);
1160 if (tgt->Target->IsAIX() && cmHasLiteralSuffix(lib.Value, "-NOTFOUND") &&
1161 artifact == cmStateEnums::ImportLibraryArtifact) {
1162 // This is an imported executable on AIX that has ENABLE_EXPORTS
1163 // but not IMPORTED_IMPLIB. CMake used to produce and accept such
1164 // imported executables on AIX before we taught it to use linker
1165 // import files. For compatibility, simply skip linking to this
1166 // executable as we did before. It works with runtime linking.
1169 if (!this->LinkDependsNoShared ||
1170 tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
1171 this->Depends.push_back(lib.Value);
1174 LinkEntry libEntry{ entry };
1175 libEntry.Item = lib;
1176 this->AddTargetItem(libEntry);
1177 this->AddLibraryRuntimeInfo(lib.Value, tgt);
1178 if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
1179 this->Target->IsDLLPlatform()) {
1180 this->AddRuntimeDLL(tgt);
1184 // This is not a CMake target. Use the name given.
1185 if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) ||
1186 (entry.Feature == DEFAULT &&
1187 cmSystemTools::IsPathToFramework(item.Value) &&
1188 this->Makefile->IsOn("APPLE"))) {
1189 // This is a framework.
1190 this->AddFrameworkItem(entry);
1191 } else if (cmSystemTools::FileIsFullPath(item.Value)) {
1192 if (cmSystemTools::FileIsDirectory(item.Value)) {
1193 // This is a directory.
1194 this->DropDirectoryItem(item);
1196 // Use the full path given to the library file.
1197 this->Depends.push_back(item.Value);
1198 this->AddFullItem(entry);
1199 this->AddLibraryRuntimeInfo(item.Value);
1202 // This is a library or option specified by the user.
1203 this->AddUserItem(entry, true);
1208 void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry)
1210 BT<std::string> const& item = entry.Item;
1211 const cmGeneratorTarget* tgt = entry.Target;
1213 // Record dependencies on DLLs.
1214 if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
1215 this->Target->IsDLLPlatform() &&
1216 this->SharedDependencyMode != SharedDepModeLink) {
1217 this->AddRuntimeDLL(tgt);
1220 // If dropping shared library dependencies, ignore them.
1221 if (this->SharedDependencyMode == SharedDepModeNone) {
1225 // The user may have incorrectly named an item. Skip items that are
1226 // not full paths to shared libraries.
1228 // The target will provide a full path. Make sure it is a shared
1230 if (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
1234 // Skip items that are not full paths. We will not be able to
1235 // reliably specify them.
1236 if (!cmSystemTools::FileIsFullPath(item.Value)) {
1240 // Get the name of the library from the file name.
1241 std::string file = cmSystemTools::GetFilenameName(item.Value);
1242 if (!this->ExtractSharedLibraryName.find(file)) {
1243 // This is not the name of a shared library.
1248 // If in linking mode, just link to the shared library.
1249 if (this->SharedDependencyMode == SharedDepModeLink) {
1250 this->AddItem(entry);
1254 // Get a full path to the dependent shared library.
1255 // Add it to the runtime path computation so that the target being
1256 // linked will be able to find it.
1259 cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
1260 ? cmStateEnums::ImportLibraryArtifact
1261 : cmStateEnums::RuntimeBinaryArtifact;
1262 lib = tgt->GetFullPath(this->Config, artifact);
1263 this->AddLibraryRuntimeInfo(lib, tgt);
1266 this->AddLibraryRuntimeInfo(lib);
1269 // Check if we need to include the dependent shared library in other
1271 cmOrderDirectories* order = nullptr;
1272 if (this->SharedDependencyMode == SharedDepModeLibDir &&
1273 !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
1274 // Add the item to the linker search path.
1275 order = this->OrderLinkerSearchPath.get();
1276 } else if (this->SharedDependencyMode == SharedDepModeDir) {
1277 // Add the item to the separate dependent library search path.
1278 order = this->OrderDependentRPath.get();
1282 std::string soName = tgt->GetSOName(this->Config);
1283 const char* soname = soName.empty() ? nullptr : soName.c_str();
1284 order->AddRuntimeLibrary(lib, soname);
1286 order->AddRuntimeLibrary(lib);
1291 void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
1293 if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
1294 this->RuntimeDLLs.end()) {
1295 this->RuntimeDLLs.emplace_back(tgt);
1299 void cmComputeLinkInformation::ComputeLinkTypeInfo()
1301 // Check whether archives may actually be shared libraries.
1302 this->ArchivesMayBeShared =
1303 this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
1304 "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
1306 // First assume we cannot do link type stuff.
1307 this->LinkTypeEnabled = false;
1309 // Lookup link type selection flags.
1310 cmValue static_link_type_flag = nullptr;
1311 cmValue shared_link_type_flag = nullptr;
1312 const char* target_type_str = nullptr;
1313 switch (this->Target->GetType()) {
1314 case cmStateEnums::EXECUTABLE:
1315 target_type_str = "EXE";
1317 case cmStateEnums::SHARED_LIBRARY:
1318 target_type_str = "SHARED_LIBRARY";
1320 case cmStateEnums::MODULE_LIBRARY:
1321 target_type_str = "SHARED_MODULE";
1326 if (target_type_str) {
1327 std::string static_link_type_flag_var =
1328 cmStrCat("CMAKE_", target_type_str, "_LINK_STATIC_", this->LinkLanguage,
1330 static_link_type_flag =
1331 this->Makefile->GetDefinition(static_link_type_flag_var);
1333 std::string shared_link_type_flag_var =
1334 cmStrCat("CMAKE_", target_type_str, "_LINK_DYNAMIC_", this->LinkLanguage,
1336 shared_link_type_flag =
1337 this->Makefile->GetDefinition(shared_link_type_flag_var);
1340 // We can support link type switching only if all needed flags are
1342 if (cmNonempty(static_link_type_flag) && cmNonempty(shared_link_type_flag)) {
1343 this->LinkTypeEnabled = true;
1344 this->StaticLinkTypeFlag = *static_link_type_flag;
1345 this->SharedLinkTypeFlag = *shared_link_type_flag;
1348 // Lookup the starting link type from the target (linked statically?).
1349 cmValue lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
1350 this->StartLinkType = cmIsOn(lss) ? LinkStatic : LinkShared;
1351 this->CurrentLinkType = this->StartLinkType;
1354 void cmComputeLinkInformation::ComputeItemParserInfo()
1356 // Get possible library name prefixes.
1357 cmMakefile* mf = this->Makefile;
1358 this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
1359 this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
1361 // Import library names should be matched and treated as shared
1362 // libraries for the purposes of linking.
1363 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
1365 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
1367 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
1369 this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
1371 if (cmValue linkSuffixes =
1372 mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
1373 std::vector<std::string> linkSuffixVec = cmExpandedList(*linkSuffixes);
1374 for (std::string const& i : linkSuffixVec) {
1375 this->AddLinkExtension(i, LinkUnknown);
1378 if (cmValue sharedSuffixes =
1379 mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
1380 std::vector<std::string> sharedSuffixVec = cmExpandedList(*sharedSuffixes);
1381 for (std::string const& i : sharedSuffixVec) {
1382 this->AddLinkExtension(i, LinkShared);
1386 // Compute a regex to match link extensions.
1387 std::string libext =
1388 this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
1390 // Create regex to remove any library extension.
1391 std::string reg("(.*)");
1393 this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
1395 // Create a regex to match a library name. Match index 1 will be
1396 // the prefix if it exists and empty otherwise. Match index 2 will
1397 // be the library name. Match index 3 will be the library
1400 for (std::string const& p : this->LinkPrefixes) {
1407 // Create a regex to match any library name.
1408 std::string reg_any = cmStrCat(reg, libext);
1409 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1410 fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
1412 this->ExtractAnyLibraryName.compile(reg_any);
1414 // Create a regex to match static library names.
1415 if (!this->StaticLinkExtensions.empty()) {
1416 std::string reg_static = cmStrCat(
1417 reg, this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic));
1418 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1419 fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
1421 this->ExtractStaticLibraryName.compile(reg_static);
1424 // Create a regex to match shared library names.
1425 if (!this->SharedLinkExtensions.empty()) {
1426 std::string reg_shared = reg;
1427 this->SharedRegexString =
1428 this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
1429 reg_shared += this->SharedRegexString;
1430 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1431 fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
1433 this->ExtractSharedLibraryName.compile(reg_shared);
1437 void cmComputeLinkInformation::AddLinkPrefix(std::string const& p)
1440 this->LinkPrefixes.insert(p);
1444 void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
1448 if (type == LinkStatic) {
1449 this->StaticLinkExtensions.emplace_back(e);
1451 if (type == LinkShared) {
1452 this->SharedLinkExtensions.emplace_back(e);
1454 this->LinkExtensions.emplace_back(e);
1458 // XXX(clang-tidy): This method's const-ness is platform dependent, so we
1459 // cannot make it `const` as `clang-tidy` wants us to.
1460 // NOLINTNEXTLINE(readability-make-member-function-const)
1461 std::string cmComputeLinkInformation::CreateExtensionRegex(
1462 std::vector<std::string> const& exts, LinkType type)
1464 // Build a list of extension choices.
1465 std::string libext = "(";
1466 const char* sep = "";
1467 for (std::string const& i : exts) {
1468 // Separate this choice from the previous one.
1472 // Store this extension choice with the "." escaped.
1474 #if defined(_WIN32) && !defined(__CYGWIN__)
1475 libext += this->NoCaseExpression(i);
1484 // Add an optional OpenBSD-style version or major.minor.version component.
1485 if (this->OpenBSD || type == LinkShared) {
1486 libext += "(\\.[0-9]+)*";
1493 std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
1496 ret.reserve(str.size() * 4);
1497 for (char c : str) {
1502 ret += static_cast<char>(tolower(c));
1503 ret += static_cast<char>(toupper(c));
1510 void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
1512 // If we are changing the current link type add the flag to tell the
1514 if (this->CurrentLinkType != lt) {
1515 this->CurrentLinkType = lt;
1517 if (this->LinkTypeEnabled) {
1518 switch (this->CurrentLinkType) {
1520 this->Items.emplace_back(this->StaticLinkTypeFlag, ItemIsPath::No);
1523 this->Items.emplace_back(this->SharedLinkTypeFlag, ItemIsPath::No);
1532 void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
1534 // This is called to handle a link item that is a full path to a target.
1535 // If the target is not a static library make sure the link type is
1536 // shared. This is because dynamic-mode linking can handle both
1537 // shared and static libraries but static-mode can handle only
1538 // static libraries. If a previous user item changed the link type
1539 // to static we need to make sure it is back to shared.
1540 BT<std::string> const& item = entry.Item;
1541 cmGeneratorTarget const* target = entry.Target;
1543 if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
1544 this->SetCurrentLinkType(LinkShared);
1547 // Keep track of shared library targets linked.
1548 if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
1549 this->SharedLibrariesLinked.insert(target);
1552 // Handle case of an imported shared library with no soname.
1553 if (this->NoSONameUsesPath &&
1554 target->IsImportedSharedLibWithoutSOName(this->Config)) {
1555 this->AddSharedLibNoSOName(entry);
1559 // For compatibility with CMake 2.4 include the item's directory in
1560 // the linker search path.
1561 if (this->OldLinkDirMode && !target->IsFrameworkOnApple() &&
1562 !cm::contains(this->OldLinkDirMask,
1563 cmSystemTools::GetFilenamePath(item.Value))) {
1564 this->OldLinkDirItems.push_back(item.Value);
1567 if (target->IsFrameworkOnApple() && !this->GlobalGenerator->IsXcode()) {
1568 // Add the framework directory and the framework item itself
1569 auto fwItems = this->GlobalGenerator->SplitFrameworkPath(item.Value, true);
1571 this->CMakeInstance->IssueMessage(
1572 MessageType::FATAL_ERROR,
1573 cmStrCat("Could not parse framework path \"", item.Value,
1574 "\" linked by target ", this->Target->GetName(), '.'),
1578 if (!fwItems->first.empty()) {
1579 // Add the directory portion to the framework search path.
1580 this->AddFrameworkPath(fwItems->first);
1582 if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
1583 this->Items.emplace_back(fwItems->second, ItemIsPath::Yes, target,
1584 this->FindLibraryFeature(entry.Feature));
1586 this->Items.emplace_back(
1587 item, ItemIsPath::Yes, target,
1588 this->FindLibraryFeature(
1589 entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature));
1592 // Now add the full path to the library.
1593 this->Items.emplace_back(
1594 item, ItemIsPath::Yes, target,
1595 this->FindLibraryFeature(
1596 entry.Feature == DEFAULT
1597 ? (target->IsFrameworkOnApple() && this->GlobalGenerator->IsXcode()
1598 ? "__CMAKE_LINK_FRAMEWORK"
1599 : "__CMAKE_LINK_LIBRARY")
1604 void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry)
1606 BT<std::string> const& item = entry.Item;
1608 // Check for the implicit link directory special case.
1609 if (this->CheckImplicitDirItem(entry)) {
1613 // Check for case of shared library with no builtin soname.
1614 if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(entry)) {
1618 // Full path libraries should specify a valid library file name.
1619 // See documentation of CMP0008.
1620 std::string generator = this->GlobalGenerator->GetName();
1621 if (this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
1622 (generator.find("Visual Studio") != std::string::npos ||
1623 generator.find("Xcode") != std::string::npos)) {
1624 std::string file = cmSystemTools::GetFilenameName(item.Value);
1625 if (!this->ExtractAnyLibraryName.find(file)) {
1626 this->HandleBadFullItem(entry, file);
1631 // This is called to handle a link item that is a full path.
1632 // If the target is not a static library make sure the link type is
1633 // shared. This is because dynamic-mode linking can handle both
1634 // shared and static libraries but static-mode can handle only
1635 // static libraries. If a previous user item changed the link type
1636 // to static we need to make sure it is back to shared.
1637 if (this->LinkTypeEnabled) {
1638 std::string name = cmSystemTools::GetFilenameName(item.Value);
1639 if (this->ExtractSharedLibraryName.find(name)) {
1640 this->SetCurrentLinkType(LinkShared);
1641 } else if (!this->ExtractStaticLibraryName.find(item.Value)) {
1642 // We cannot determine the type. Assume it is the target's
1644 this->SetCurrentLinkType(this->StartLinkType);
1648 // For compatibility with CMake 2.4 include the item's directory in
1649 // the linker search path.
1650 if (this->OldLinkDirMode &&
1651 !cm::contains(this->OldLinkDirMask,
1652 cmSystemTools::GetFilenamePath(item.Value))) {
1653 this->OldLinkDirItems.push_back(item.Value);
1656 // Now add the full path to the library.
1657 this->Items.emplace_back(
1658 item, ItemIsPath::Yes, nullptr,
1659 this->FindLibraryFeature(
1660 entry.Feature == DEFAULT
1661 ? (entry.Kind == cmComputeLinkDepends::LinkEntry::Object
1662 ? "__CMAKE_LINK_OBJECT"
1663 : "__CMAKE_LINK_LIBRARY")
1667 bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry)
1669 BT<std::string> const& item = entry.Item;
1671 // We only switch to a pathless item if the link type may be
1672 // enforced. Fortunately only platforms that support link types
1673 // seem to have magic per-architecture implicit link directories.
1674 if (!this->LinkTypeEnabled) {
1678 // Check if this item is in an implicit link directory.
1679 std::string dir = cmSystemTools::GetFilenamePath(item.Value);
1680 if (!cm::contains(this->ImplicitLinkDirs, dir)) {
1681 // Only libraries in implicit link directories are converted to
1686 // Only apply the policy below if the library file is one that can
1687 // be found by the linker.
1688 std::string file = cmSystemTools::GetFilenameName(item.Value);
1689 if (!this->ExtractAnyLibraryName.find(file)) {
1693 // Check the policy for whether we should use the approach below.
1694 switch (this->Target->GetPolicyStatusCMP0060()) {
1695 case cmPolicies::WARN:
1696 if (this->CMP0060Warn) {
1697 // Print the warning at most once for this item.
1698 std::string const& wid = "CMP0060-WARNING-GIVEN-" + item.Value;
1699 if (!this->CMakeInstance->GetPropertyAsBool(wid)) {
1700 this->CMakeInstance->SetProperty(wid, "1");
1701 this->CMP0060WarnItems.insert(item.Value);
1705 case cmPolicies::OLD:
1707 case cmPolicies::REQUIRED_ALWAYS:
1708 case cmPolicies::REQUIRED_IF_USED:
1709 case cmPolicies::NEW:
1713 // Many system linkers support multiple architectures by
1714 // automatically selecting the implicit linker search path for the
1715 // current architecture. If the library appears in an implicit link
1716 // directory then just report the file name without the directory
1717 // portion. This will allow the system linker to locate the proper
1718 // library for the architecture at link time.
1719 LinkEntry fileEntry{ entry };
1720 fileEntry.Item = file;
1721 this->AddUserItem(fileEntry, false);
1723 // Make sure the link directory ordering will find the library.
1724 this->OrderLinkerSearchPath->AddLinkLibrary(item.Value);
1729 void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry,
1732 // This is called to handle a link item that does not match a CMake
1733 // target and is not a full path. We check here if it looks like a
1734 // library file name to automatically request the proper link type
1735 // from the linker. For example:
1738 // libfoo.a ==> -Wl,-Bstatic -lfoo
1740 BT<std::string> const& item = entry.Item;
1742 if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') {
1743 // Pass flags through untouched.
1744 // if this is a -l option then we might need to warn about
1745 // CMP0003 so put it in OldUserFlagItems, if it is not a -l
1746 // or -Wl,-l (-framework -pthread), then allow it without a
1747 // CMP0003 as -L will not affect those other linker flags
1748 if (cmHasLiteralPrefix(item.Value, "-l") ||
1749 cmHasLiteralPrefix(item.Value, "-Wl,-l")) {
1750 // This is a linker option provided by the user.
1751 this->OldUserFlagItems.push_back(item.Value);
1754 // Restore the target link type since this item does not specify
1756 this->SetCurrentLinkType(this->StartLinkType);
1758 // Use the item verbatim.
1759 this->Items.emplace_back(item, ItemIsPath::No);
1763 // Parse out the prefix, base, and suffix components of the
1764 // library name. If the name matches that of a shared or static
1765 // library then set the link type accordingly.
1767 // Search for shared library names first because some platforms
1768 // have shared libraries with names that match the static library
1769 // pattern. For example cygwin and msys use the convention
1770 // libfoo.dll.a for import libraries and libfoo.a for static
1771 // libraries. On AIX a library with the name libfoo.a can be
1774 if (this->ExtractSharedLibraryName.find(item.Value)) {
1775 // This matches a shared library file name.
1776 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1777 fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
1778 this->ExtractSharedLibraryName.match(1).c_str(),
1779 this->ExtractSharedLibraryName.match(2).c_str(),
1780 this->ExtractSharedLibraryName.match(3).c_str());
1782 // Set the link type to shared.
1783 this->SetCurrentLinkType(LinkShared);
1785 // Use just the library name so the linker will search.
1786 lib = this->ExtractSharedLibraryName.match(2);
1787 } else if (this->ExtractStaticLibraryName.find(item.Value)) {
1788 // This matches a static library file name.
1789 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1790 fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
1791 this->ExtractStaticLibraryName.match(1).c_str(),
1792 this->ExtractStaticLibraryName.match(2).c_str(),
1793 this->ExtractStaticLibraryName.match(3).c_str());
1795 // Set the link type to static.
1796 this->SetCurrentLinkType(LinkStatic);
1798 // Use just the library name so the linker will search.
1799 lib = this->ExtractStaticLibraryName.match(2);
1800 } else if (this->ExtractAnyLibraryName.find(item.Value)) {
1801 // This matches a library file name.
1802 #ifdef CM_COMPUTE_LINK_INFO_DEBUG
1803 fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
1804 this->ExtractAnyLibraryName.match(1).c_str(),
1805 this->ExtractAnyLibraryName.match(2).c_str(),
1806 this->ExtractAnyLibraryName.match(3).c_str());
1808 // Restore the target link type since this item does not specify
1810 this->SetCurrentLinkType(this->StartLinkType);
1812 // Use just the library name so the linker will search.
1813 lib = this->ExtractAnyLibraryName.match(2);
1815 // This is a name specified by the user.
1817 this->OldUserFlagItems.push_back(item.Value);
1820 // We must ask the linker to search for a library with this name.
1821 // Restore the target link type since this item does not specify
1823 this->SetCurrentLinkType(this->StartLinkType);
1827 // Create an option to ask the linker to search for the library.
1828 auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
1830 if (entry.Feature != DEFAULT) {
1831 auto const& feature = this->GetLibraryFeature(entry.Feature);
1832 this->Items.emplace_back(
1834 feature.GetDecoratedItem(cmStrCat(lib, this->LibLinkSuffix),
1835 item.Value, out, ItemIsPath::No),
1839 this->Items.emplace_back(BT<std::string>(out, item.Backtrace),
1843 // Here we could try to find the library the linker will find and
1844 // add a runtime information entry for it. It would probably not be
1845 // reliable and we want to encourage use of full paths for library
1849 void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
1851 std::string const& item = entry.Item.Value;
1853 // Try to separate the framework name and path.
1855 this->GlobalGenerator->SplitFrameworkPath(item, entry.Feature != DEFAULT);
1857 std::ostringstream e;
1858 e << "Could not parse framework path \"" << item << "\" "
1859 << "linked by target " << this->Target->GetName() << ".";
1860 cmSystemTools::Error(e.str());
1864 std::string fw_path = std::move(fwItems->first);
1865 std::string fw = std::move(fwItems->second);
1866 std::string full_fw = cmStrCat(fw, ".framework/", fw);
1868 if (!fw_path.empty()) {
1869 full_fw = cmStrCat(fw_path, '/', full_fw);
1870 // Add the directory portion to the framework search path.
1871 this->AddFrameworkPath(fw_path);
1874 // add runtime information
1875 this->AddLibraryRuntimeInfo(full_fw);
1877 if (entry.Feature == DEFAULT) {
1878 // ensure FRAMEWORK feature is loaded
1879 this->AddLibraryFeature("FRAMEWORK");
1882 if (this->GlobalGenerator->IsXcode()) {
1883 // Add framework path - it will be handled by Xcode after it's added to
1884 // "Link Binary With Libraries" build phase
1885 this->Items.emplace_back(item, ItemIsPath::Yes, nullptr,
1886 this->FindLibraryFeature(entry.Feature == DEFAULT
1890 this->Items.emplace_back(fw, ItemIsPath::Yes, nullptr,
1891 this->FindLibraryFeature(entry.Feature == DEFAULT
1897 void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item)
1899 // A full path to a directory was found as a link item. Warn the
1901 this->CMakeInstance->IssueMessage(
1902 MessageType::WARNING,
1903 cmStrCat("Target \"", this->Target->GetName(),
1904 "\" requests linking to directory \"", item.Value,
1905 "\". Targets may link only to libraries. CMake is dropping "
1910 void cmComputeLinkInformation::ComputeFrameworkInfo()
1912 // Avoid adding implicit framework paths.
1913 std::vector<std::string> implicitDirVec;
1915 // Get platform-wide implicit directories.
1916 this->Makefile->GetDefExpandList(
1917 "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES", implicitDirVec);
1919 // Get language-specific implicit directories.
1920 std::string implicitDirVar = cmStrCat(
1921 "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES");
1922 this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec);
1924 this->FrameworkPathsEmitted.insert(implicitDirVec.begin(),
1925 implicitDirVec.end());
1928 void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
1930 if (this->FrameworkPathsEmitted.insert(p).second) {
1931 this->FrameworkPaths.push_back(p);
1935 bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry)
1937 // This platform will use the path to a library as its soname if the
1938 // library is given via path and was not built with an soname. If
1939 // this is a shared library that might be the case.
1940 std::string file = cmSystemTools::GetFilenameName(entry.Item.Value);
1941 if (this->ExtractSharedLibraryName.find(file)) {
1942 // If we can guess the soname fairly reliably then assume the
1943 // library has one. Otherwise assume the library has no builtin
1946 if (!cmSystemTools::GuessLibrarySOName(entry.Item.Value, soname)) {
1947 this->AddSharedLibNoSOName(entry);
1954 void cmComputeLinkInformation::AddSharedLibNoSOName(LinkEntry const& entry)
1956 // We have a full path to a shared library with no soname. We need
1957 // to ask the linker to locate the item because otherwise the path
1958 // we give to it will be embedded in the target linked. Then at
1959 // runtime the dynamic linker will search for the library using the
1960 // path instead of just the name.
1961 LinkEntry fileEntry{ entry };
1962 fileEntry.Item = cmSystemTools::GetFilenameName(entry.Item.Value);
1963 this->AddUserItem(fileEntry, false);
1965 // Make sure the link directory ordering will find the library.
1966 this->OrderLinkerSearchPath->AddLinkLibrary(entry.Item.Value);
1969 void cmComputeLinkInformation::HandleBadFullItem(LinkEntry const& entry,
1970 std::string const& file)
1972 std::string const& item = entry.Item.Value;
1973 // Do not depend on things that do not exist.
1974 auto i = std::find(this->Depends.begin(), this->Depends.end(), item);
1975 if (i != this->Depends.end()) {
1976 this->Depends.erase(i);
1979 // Tell the linker to search for the item and provide the proper
1980 // path for it. Do not contribute to any CMP0003 warning (do not
1981 // put in OldLinkDirItems or OldUserFlagItems).
1982 LinkEntry fileEntry{ entry };
1983 fileEntry.Item = file;
1984 this->AddUserItem(fileEntry, false);
1985 this->OrderLinkerSearchPath->AddLinkLibrary(item);
1987 // Produce any needed message.
1988 switch (this->Target->GetPolicyStatusCMP0008()) {
1989 case cmPolicies::WARN: {
1990 // Print the warning at most once for this item.
1991 std::string wid = cmStrCat("CMP0008-WARNING-GIVEN-", item);
1992 if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(wid)) {
1993 this->CMakeInstance->GetState()->SetGlobalProperty(wid, "1");
1994 std::ostringstream w;
1995 /* clang-format off */
1996 w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0008) << "\n"
1997 << "Target \"" << this->Target->GetName() << "\" links to item\n"
1998 << " " << item << "\n"
1999 << "which is a full-path but not a valid library file name.";
2000 /* clang-format on */
2001 this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
2002 this->Target->GetBacktrace());
2006 case cmPolicies::OLD: // NOLINT(bugprone-branch-clone)
2007 // OLD behavior does not warn.
2009 case cmPolicies::NEW:
2010 // NEW behavior will not get here.
2012 case cmPolicies::REQUIRED_IF_USED:
2013 case cmPolicies::REQUIRED_ALWAYS: {
2014 std::ostringstream e;
2015 /* clang-format off */
2016 e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0008) << "\n"
2017 << "Target \"" << this->Target->GetName() << "\" links to item\n"
2018 << " " << item << "\n"
2019 << "which is a full-path but not a valid library file name.";
2020 /* clang-format on */
2021 this->CMakeInstance->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2022 this->Target->GetBacktrace());
2027 bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
2029 // Support broken projects if necessary.
2030 if (this->OldLinkDirItems.empty() || this->OldUserFlagItems.empty() ||
2031 !this->OldLinkDirMode) {
2035 // Enforce policy constraints.
2036 switch (this->Target->GetPolicyStatusCMP0003()) {
2037 case cmPolicies::WARN:
2038 if (!this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
2039 "CMP0003-WARNING-GIVEN")) {
2040 this->CMakeInstance->GetState()->SetGlobalProperty(
2041 "CMP0003-WARNING-GIVEN", "1");
2042 std::ostringstream w;
2043 this->PrintLinkPolicyDiagnosis(w);
2044 this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
2045 this->Target->GetBacktrace());
2048 case cmPolicies::OLD:
2049 // OLD behavior is to add the paths containing libraries with
2050 // known full paths as link directories.
2052 case cmPolicies::NEW:
2053 // Should never happen due to assignment of OldLinkDirMode
2055 case cmPolicies::REQUIRED_IF_USED:
2056 case cmPolicies::REQUIRED_ALWAYS: {
2057 std::ostringstream e;
2058 e << cmPolicies::GetRequiredPolicyError(cmPolicies::CMP0003) << "\n";
2059 this->PrintLinkPolicyDiagnosis(e);
2060 this->CMakeInstance->IssueMessage(MessageType::FATAL_ERROR, e.str(),
2061 this->Target->GetBacktrace());
2066 // Add the link directories for full path items.
2067 for (std::string const& i : this->OldLinkDirItems) {
2068 this->OrderLinkerSearchPath->AddLinkLibrary(i);
2073 void cmComputeLinkInformation::PrintLinkPolicyDiagnosis(std::ostream& os)
2075 // Tell the user what to do.
2076 /* clang-format off */
2077 os << "Policy CMP0003 should be set before this line. "
2078 << "Add code such as\n"
2079 << " if(COMMAND cmake_policy)\n"
2080 << " cmake_policy(SET CMP0003 NEW)\n"
2081 << " endif(COMMAND cmake_policy)\n"
2082 << "as early as possible but after the most recent call to "
2083 << "cmake_minimum_required or cmake_policy(VERSION). ";
2084 /* clang-format on */
2086 // List the items that might need the old-style paths.
2087 os << "This warning appears because target \"" << this->Target->GetName()
2089 << "links to some libraries for which the linker must search:\n";
2091 // Format the list of unknown items to be as short as possible while
2092 // still fitting in the allowed width (a true solution would be the
2093 // bin packing problem if we were allowed to change the order).
2094 std::string::size_type max_size = 76;
2096 const char* sep = " ";
2097 for (std::string const& i : this->OldUserFlagItems) {
2098 // If the addition of another item will exceed the limit then
2099 // output the current line and reset it. Note that the separator
2100 // is either " " or ", " which is always 2 characters.
2101 if (!line.empty() && (line.size() + i.size() + 2) > max_size) {
2108 // Convert to the other separator.
2111 if (!line.empty()) {
2116 // List the paths old behavior is adding.
2117 os << "and other libraries with known full path:\n";
2118 std::set<std::string> emitted;
2119 for (std::string const& i : this->OldLinkDirItems) {
2120 if (emitted.insert(cmSystemTools::GetFilenamePath(i)).second) {
2121 os << " " << i << "\n";
2126 os << "CMake is adding directories in the second list to the linker "
2127 << "search path in case they are needed to find libraries from the "
2128 << "first list (for backwards compatibility with CMake 2.4). "
2129 << "Set policy CMP0003 to OLD or NEW to enable or disable this "
2130 << "behavior explicitly. "
2131 << "Run \"cmake --help-policy CMP0003\" for more information.";
2134 void cmComputeLinkInformation::LoadImplicitLinkInfo()
2136 std::vector<std::string> implicitDirVec;
2138 // Get platform-wide implicit directories.
2139 this->Makefile->GetDefExpandList("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES",
2142 // Append library architecture to all implicit platform directories
2143 // and add them to the set
2144 if (cmValue libraryArch =
2145 this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
2146 for (std::string const& i : implicitDirVec) {
2147 this->ImplicitLinkDirs.insert(i + "/" + *libraryArch);
2151 // Get language-specific implicit directories.
2152 std::string implicitDirVar =
2153 cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES");
2154 this->Makefile->GetDefExpandList(implicitDirVar, implicitDirVec);
2156 // Store implicit link directories.
2157 this->ImplicitLinkDirs.insert(implicitDirVec.begin(), implicitDirVec.end());
2159 // Get language-specific implicit libraries.
2160 std::vector<std::string> implicitLibVec;
2161 std::string implicitLibVar =
2162 cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES");
2163 this->Makefile->GetDefExpandList(implicitLibVar, implicitLibVec);
2165 // Store implicit link libraries.
2166 for (std::string const& item : implicitLibVec) {
2167 // Items starting in '-' but not '-l' are flags, not libraries,
2168 // and should not be filtered by this implicit list.
2169 if (item[0] != '-' || item[1] == 'l') {
2170 this->ImplicitLinkLibs.insert(item);
2174 // Get platform specific rpath link directories
2175 this->Makefile->GetDefExpandList("CMAKE_PLATFORM_RUNTIME_PATH",
2176 this->RuntimeLinkDirs);
2179 std::vector<std::string> const&
2180 cmComputeLinkInformation::GetRuntimeSearchPath() const
2182 return this->OrderRuntimeSearchPath->GetOrderedDirectories();
2185 void cmComputeLinkInformation::AddLibraryRuntimeInfo(
2186 std::string const& fullPath, cmGeneratorTarget const* target)
2188 // Ignore targets on Apple where install_name is not @rpath.
2189 // The dependenty library can be found with other means such as
2190 // @loader_path or full paths.
2191 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2192 if (!target->HasMacOSXRpathInstallNameDir(this->Config)) {
2197 // Libraries with unknown type must be handled using just the file
2199 if (target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
2200 this->AddLibraryRuntimeInfo(fullPath);
2204 // Skip targets that are not shared libraries (modules cannot be linked).
2205 if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
2209 // Try to get the soname of the library. Only files with this name
2210 // could possibly conflict.
2211 std::string soName = target->GetSOName(this->Config);
2212 const char* soname = soName.empty() ? nullptr : soName.c_str();
2214 // Include this library in the runtime path ordering.
2215 this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
2216 if (this->LinkWithRuntimePath) {
2217 this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
2221 void cmComputeLinkInformation::AddLibraryRuntimeInfo(
2222 std::string const& fullPath)
2224 // Get the name of the library from the file name.
2225 bool is_shared_library = false;
2226 std::string file = cmSystemTools::GetFilenameName(fullPath);
2228 if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
2229 // Check that @rpath is part of the install name.
2230 // If it isn't, return.
2232 if (!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) {
2236 if (soname.find("@rpath") == std::string::npos) {
2241 is_shared_library = this->ExtractSharedLibraryName.find(file);
2243 if (!is_shared_library) {
2244 // On some platforms (AIX) a shared library may look static.
2245 if (this->ArchivesMayBeShared) {
2246 if (this->ExtractStaticLibraryName.find(file)) {
2247 // This is the name of a shared library or archive.
2248 is_shared_library = true;
2253 // It could be an Apple framework
2254 if (!is_shared_library) {
2255 if (fullPath.find(".framework") != std::string::npos) {
2256 static cmsys::RegularExpression splitFramework(
2257 "^(.*)/(.*).framework/(.*)$");
2258 if (splitFramework.find(fullPath) &&
2259 (std::string::npos !=
2260 splitFramework.match(3).find(splitFramework.match(2)))) {
2261 is_shared_library = true;
2266 if (!is_shared_library) {
2270 // Include this library in the runtime path ordering.
2271 this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
2272 if (this->LinkWithRuntimePath) {
2273 this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
2277 static void cmCLI_ExpandListUnique(std::string const& str,
2278 std::vector<std::string>& out,
2279 std::set<std::string>& emitted)
2281 std::vector<std::string> tmp = cmExpandedList(str);
2282 for (std::string const& i : tmp) {
2283 if (emitted.insert(i).second) {
2289 void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
2290 bool for_install) const
2292 // Select whether to generate runtime search directories.
2293 bool outputRuntime =
2294 !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->RuntimeFlag.empty();
2296 // Select whether to generate an rpath for the install tree or the
2298 bool linking_for_install =
2300 this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
2301 bool use_install_rpath =
2302 (outputRuntime && this->Target->HaveInstallTreeRPATH(this->Config) &&
2303 linking_for_install);
2304 bool use_build_rpath =
2305 (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
2306 !linking_for_install);
2307 bool use_link_rpath = outputRuntime && linking_for_install &&
2308 !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
2309 this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
2311 // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree.
2312 std::string const& originToken = this->Makefile->GetSafeDefinition(
2313 "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN");
2314 std::string targetOutputDir = this->Target->GetDirectory(this->Config);
2315 bool use_relative_build_rpath =
2316 this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") &&
2317 !originToken.empty() && !targetOutputDir.empty();
2319 // Construct the RPATH.
2320 std::set<std::string> emitted;
2321 if (use_install_rpath) {
2322 std::string install_rpath;
2323 this->Target->GetInstallRPATH(this->Config, install_rpath);
2324 cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
2326 if (use_build_rpath) {
2327 // Add directories explicitly specified by user
2328 std::string build_rpath;
2329 if (this->Target->GetBuildRPATH(this->Config, build_rpath)) {
2330 // This will not resolve entries to use $ORIGIN, the user is expected
2331 // to do that if necessary.
2332 cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
2335 if (use_build_rpath || use_link_rpath) {
2336 std::string rootPath;
2337 if (cmValue sysrootLink =
2338 this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
2339 rootPath = *sysrootLink;
2341 rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
2343 cmValue stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
2344 std::string const& installPrefix =
2345 this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
2346 cmSystemTools::ConvertToUnixSlashes(rootPath);
2347 std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
2348 std::string const& topBinaryDir =
2349 this->CMakeInstance->GetHomeOutputDirectory();
2350 for (std::string const& ri : rdirs) {
2351 // Put this directory in the rpath if using build-tree rpath
2352 // support or if using the link path as an rpath.
2353 if (use_build_rpath) {
2355 if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
2356 d.erase(0, rootPath.size());
2357 } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
2358 d.erase(0, (*stagePath).size());
2359 d = cmStrCat(installPrefix, '/', d);
2360 cmSystemTools::ConvertToUnixSlashes(d);
2361 } else if (use_relative_build_rpath) {
2362 // If expansion of the $ORIGIN token is supported and permitted per
2363 // policy, use relative paths in the RPATH.
2364 if (cmSystemTools::ComparePath(d, topBinaryDir) ||
2365 cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
2366 d = cmSystemTools::RelativePath(targetOutputDir, d);
2368 d = cmStrCat(originToken, "/", d);
2374 if (emitted.insert(d).second) {
2375 runtimeDirs.push_back(std::move(d));
2377 } else if (use_link_rpath) {
2378 // Do not add any path inside the source or build tree.
2379 std::string const& topSourceDir =
2380 this->CMakeInstance->GetHomeDirectory();
2381 if (!cmSystemTools::ComparePath(ri, topSourceDir) &&
2382 !cmSystemTools::ComparePath(ri, topBinaryDir) &&
2383 !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
2384 !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
2386 if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
2387 d.erase(0, rootPath.size());
2388 } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
2389 d.erase(0, (*stagePath).size());
2390 d = cmStrCat(installPrefix, '/', d);
2391 cmSystemTools::ConvertToUnixSlashes(d);
2393 if (emitted.insert(d).second) {
2394 runtimeDirs.push_back(std::move(d));
2401 // Add runtime paths required by the languages to always be
2402 // present. This is done even when skipping rpath support.
2404 cmGeneratorTarget::LinkClosure const* lc =
2405 this->Target->GetLinkClosure(this->Config);
2406 for (std::string const& li : lc->Languages) {
2407 std::string useVar =
2408 "CMAKE_" + li + "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH";
2409 if (this->Makefile->IsOn(useVar)) {
2410 std::string dirVar = "CMAKE_" + li + "_IMPLICIT_LINK_DIRECTORIES";
2411 if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
2412 cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
2418 // Add runtime paths required by the platform to always be
2419 // present. This is done even when skipping rpath support.
2420 cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted);
2423 std::string cmComputeLinkInformation::GetRPathString(bool for_install) const
2425 // Get the directories to use.
2426 std::vector<std::string> runtimeDirs;
2427 this->GetRPath(runtimeDirs, for_install);
2429 // Concatenate the paths.
2430 std::string rpath = cmJoin(runtimeDirs, this->GetRuntimeSep());
2432 // If the rpath will be replaced at install time, prepare space.
2433 if (!for_install && this->RuntimeUseChrpath) {
2434 if (!rpath.empty()) {
2435 // Add one trailing separator so the linker does not re-use the
2436 // rpath .dynstr entry for a symbol name that happens to match
2437 // the end of the rpath string.
2438 rpath += this->GetRuntimeSep();
2441 // Make sure it is long enough to hold the replacement value.
2442 std::string::size_type minLength = this->GetChrpathString().length();
2443 while (rpath.length() < minLength) {
2444 rpath += this->GetRuntimeSep();
2451 std::string cmComputeLinkInformation::GetChrpathString() const
2453 if (!this->RuntimeUseChrpath) {
2457 return this->GetRPathString(true);