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