cmComputeLinkInformation.cxx 66.2 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
3
4
#include "cmComputeLinkInformation.h"

5
#include "cmComputeLinkDepends.h"
6
#include "cmGeneratorTarget.h"
7
#include "cmGlobalGenerator.h"
8
#include "cmLocalGenerator.h"
9
#include "cmMakefile.h"
10
#include "cmMessageType.h"
11
#include "cmOrderDirectories.h"
12
#include "cmOutputConverter.h"
13
#include "cmPolicies.h"
14
#include "cmState.h"
15
#include "cmStateTypes.h"
16
#include "cmStringAlgorithms.h"
17
18
#include "cmSystemTools.h"
#include "cmTarget.h"
19
#include "cmake.h"
20

21
#include <algorithm>
22
#include <ctype.h>
23
24
25
#include <sstream>
#include <string.h>
#include <utility>
26

27
28
//#define CM_COMPUTE_LINK_INFO_DEBUG

29
30
31
32
33
/*
Notes about linking on various platforms:

------------------------------------------------------------------------------

34
Linux, FreeBSD, macOS, Sun, Windows:
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151

Linking to libraries using the full path works fine.

------------------------------------------------------------------------------

On AIX, more work is needed.

  The "-bnoipath" option is needed.  From "man ld":

    Note: If you specify a shared object, or an archive file
    containing a shared object, with an absolute or relative path
    name, instead of with the -lName flag, the path name is
    included in the import file ID string in the loader section of
    the output file. You can override this behavior with the
    -bnoipath option.

      noipath

        For shared objects listed on the command-line, rather than
        specified with the -l flag, use a null path component when
        listing the shared object in the loader section of the
        output file. A null path component is always used for
        shared objects specified with the -l flag. This option
        does not affect the specification of a path component by
        using a line beginning with #! in an import file. The
        default is the ipath option.

  This prevents the full path specified on the compile line from being
  compiled directly into the binary.

  By default the linker places -L paths in the embedded runtime path.
  In order to implement CMake's RPATH interface correctly, we need the
  -blibpath:Path option.  From "man ld":

      libpath:Path

        Uses Path as the library path when writing the loader section
        of the output file. Path is neither checked for validity nor
        used when searching for libraries specified by the -l flag.
        Path overrides any library paths generated when the -L flag is
        used.

        If you do not specify any -L flags, or if you specify the
        nolibpath option, the default library path information is
        written in the loader section of the output file. The default
        library path information is the value of the LIBPATH
        environment variable if it is defined, and /usr/lib:/lib,
        otherwise.

  We can pass -Wl,-blibpath:/usr/lib:/lib always to avoid the -L stuff
  and not break when the user sets LIBPATH.  Then if we want to add an
  rpath we insert it into the option before /usr/lib.

------------------------------------------------------------------------------

On HP-UX, more work is needed.  There are differences between
versions.

ld: 92453-07 linker linker ld B.10.33 990520

  Linking with a full path works okay for static and shared libraries.
  The linker seems to always put the full path to where the library
  was found in the binary whether using a full path or -lfoo syntax.
  Transitive link dependencies work just fine due to the full paths.

  It has the "-l:libfoo.sl" option.  The +nodefaultrpath is accepted
  but not documented and does not seem to do anything.  There is no
  +forceload option.

ld: 92453-07 linker ld HP Itanium(R) B.12.41  IPF/IPF

  Linking with a full path works okay for static libraries.

  Linking with a full path works okay for shared libraries.  However
  dependent (transitive) libraries of those linked directly must be
  either found with an rpath stored in the direct dependencies or
  found in -L paths as if they were specified with "-l:libfoo.sl"
  (really "-l:<soname>").  The search matches that of the dynamic
  loader but only with -L paths.  In other words, if we have an
  executable that links to shared library bar which links to shared
  library foo, the link line for the exe must contain

    /dir/with/bar/libbar.sl -L/dir/with/foo

  It does not matter whether the exe wants to link to foo directly or
  whether /dir/with/foo/libfoo.sl is listed.  The -L path must still
  be present.  It should match the runtime path computed for the
  executable taking all directly and transitively linked libraries
  into account.

  The "+nodefaultrpath" option should be used to avoid getting -L
  paths in the rpath unless we add our own rpath with +b.  This means
  that skip-build-rpath should use this option.

  See documentation in "man ld", "man dld.so", and
  http://docs.hp.com/en/B2355-90968/creatingandusinglibraries.htm

    +[no]defaultrpath
      +defaultrpath is the default.  Include any paths that are
      specified with -L in the embedded path, unless you specify the
      +b option.  If you use +b, only the path list specified by +b is
      in the embedded path.

      The +nodefaultrpath option removes all library paths that were
      specified with the -L option from the embedded path.  The linker
      searches the library paths specified by the -L option at link
      time.  At run time, the only library paths searched are those
      specified by the environment variables LD_LIBRARY_PATH and
      SHLIB_PATH, library paths specified by the +b linker option, and
      finally the default library paths.

    +rpathfirst
      This option will cause the paths specified in RPATH (embedded
      path) to be used before the paths specified in LD_LIBRARY_PATH
      or SHLIB_PATH, in searching for shared libraries.  This changes
      the default search order of LD_LIBRARY_PATH, SHLIB_PATH, and
      RPATH (embedded path).
152
153
154
155
156
157
158
159
160
161
162
163
164
165

------------------------------------------------------------------------------
Notes about dependent (transitive) shared libraries:

On non-Windows systems shared libraries may have transitive
dependencies.  In order to support LINK_INTERFACE_LIBRARIES we must
support linking to a shared library without listing all the libraries
to which it links.  Some linkers want to be able to find the
transitive dependencies (dependent libraries) of shared libraries
listed on the command line.

  - On Windows, DLLs are not directly linked, and the import libraries
    have no transitive dependencies.

166
167
168
  - On Mac OS X 10.5 and above transitive dependencies are not needed.

  - On Mac OS X 10.4 and below we need to actually list the dependencies.
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
    Otherwise when using -isysroot for universal binaries it cannot
    find the dependent libraries.  Listing them on the command line
    tells the linker where to find them, but unfortunately also links
    the library.

  - On HP-UX, the linker wants to find the transitive dependencies of
    shared libraries in the -L paths even if the dependent libraries
    are given on the link line.

  - On AIX the transitive dependencies are not needed.

  - On SGI, the linker wants to find the transitive dependencies of
    shared libraries in the -L paths if they are not given on the link
    line.  Transitive linking can be disabled using the options

      -no_transitive_link -Wl,-no_transitive_link

    which disable it.  Both options must be given when invoking the
    linker through the compiler.

  - On Sun, the linker wants to find the transitive dependencies of
    shared libraries in the -L paths if they are not given on the link
    line.

  - On Linux, FreeBSD, and QNX:

    The linker wants to find the transitive dependencies of shared
    libraries in the "-rpath-link" paths option if they have not been
    given on the link line.  The option is like rpath but just for
    link time:

      -Wl,-rpath-link,"/path1:/path2"

For -rpath-link, we need a separate runtime path ordering pass
including just the dependent libraries that are not linked.

For -L paths on non-HP, we can do the same thing as with rpath-link
but put the results in -L paths.  The paths should be listed at the
end to avoid conflicting with user search paths (?).

For -L paths on HP, we should do a runtime path ordering pass with
all libraries, both linked and non-linked.  Even dependent
libraries that are also linked need to be listed in -L paths.

In our implementation we add all dependent libraries to the runtime
path computation.  Then the auto-generated RPATH will find everything.

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
------------------------------------------------------------------------------
Notes about shared libraries with not builtin soname:

Some UNIX shared libraries may be created with no builtin soname.  On
some platforms such libraries cannot be linked using the path to their
location because the linker will copy the path into the field used to
find the library at runtime.

  Apple:    ../libfoo.dylib  ==>  libfoo.dylib  # ok, uses install_name
  SGI:      ../libfoo.so     ==>  libfoo.so     # ok
  AIX:      ../libfoo.so     ==>  libfoo.so     # ok
  Linux:    ../libfoo.so     ==>  ../libfoo.so  # bad
  HP-UX:    ../libfoo.so     ==>  ../libfoo.so  # bad
  Sun:      ../libfoo.so     ==>  ../libfoo.so  # bad
  FreeBSD:  ../libfoo.so     ==>  ../libfoo.so  # bad

In order to link these libraries we need to use the old-style split
into -L.. and -lfoo options.  This should be fairly safe because most
problems with -lfoo options were related to selecting shared libraries
instead of static but in this case we want the shared lib.  Link
directory ordering needs to be done to make sure these shared
libraries are found first.  There should be very few restrictions
because this need be done only for shared libraries without soname-s.

240
241
*/

242
243
cmComputeLinkInformation::cmComputeLinkInformation(
  const cmGeneratorTarget* target, const std::string& config)
244
  // Store context information.
245
246
247
248
249
250
  : Target(target)
  , Makefile(target->Target->GetMakefile())
  , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
  , CMakeInstance(this->GlobalGenerator->GetCMakeInstance())
  // The configuration being linked.
  , Config(config)
251
{
252
  // Check whether to recognize OpenBSD-style library versioned names.
253
254
  this->OpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
    "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
255

256
  // Allocate internals.
257
258
259
260
  this->OrderLinkerSearchPath = new cmOrderDirectories(
    this->GlobalGenerator, target, "linker search path");
  this->OrderRuntimeSearchPath = new cmOrderDirectories(
    this->GlobalGenerator, target, "runtime search path");
Daniel Pfeifer's avatar
Daniel Pfeifer committed
261
  this->OrderDependentRPath = nullptr;
262

263
  // Get the language used for linking this target.
264
  this->LinkLanguage = this->Target->GetLinkerLanguage(config);
265
  if (this->LinkLanguage.empty()) {
266
267
268
    // The Compute method will do nothing, so skip the rest of the
    // initialization.
    return;
269
  }
270

271
272
  // Check whether we should skip dependencies on shared library files.
  this->LinkDependsNoShared =
273
    this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
274

275
276
277
  // On platforms without import libraries there may be a special flag
  // to use when creating a plugin (module) that obtains symbols from
  // the program that will load it.
Daniel Pfeifer's avatar
Daniel Pfeifer committed
278
  this->LoaderFlag = nullptr;
279
  if (!this->Target->IsDLLPlatform() &&
280
      this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
281
282
283
    std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_";
    loader_flag_var += this->LinkLanguage;
    loader_flag_var += "_FLAG";
Stephen Kelly's avatar
Stephen Kelly committed
284
    this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
285
  }
286
287
288
289

  // Get options needed to link libraries.
  this->LibLinkFlag =
    this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
290
291
  this->LibLinkFileFlag =
    this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
292
293
294
  this->LibLinkSuffix =
    this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");

295
296
  // Get options needed to specify RPATHs.
  this->RuntimeUseChrpath = false;
297
298
299
300
  if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
    const char* tType = ((this->Target->GetType() == cmStateEnums::EXECUTABLE)
                           ? "EXECUTABLE"
                           : "SHARED_LIBRARY");
301
    std::string rtVar = "CMAKE_";
302
    rtVar += tType;
303
304
305
306
    rtVar += "_RUNTIME_";
    rtVar += this->LinkLanguage;
    rtVar += "_FLAG";
    std::string rtSepVar = rtVar + "_SEP";
Stephen Kelly's avatar
Stephen Kelly committed
307
308
    this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
    this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
309
310
    this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
      "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
311

312
    this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
313
314
315
316
317
318
319

    // Get options needed to help find dependent libraries.
    std::string rlVar = "CMAKE_";
    rlVar += tType;
    rlVar += "_RPATH_LINK_";
    rlVar += this->LinkLanguage;
    rlVar += "_FLAG";
Stephen Kelly's avatar
Stephen Kelly committed
320
    this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
321
  }
322

323
324
  // Check if we need to include the runtime search path at link time.
  {
325
326
327
328
    std::string var = "CMAKE_SHARED_LIBRARY_LINK_";
    var += this->LinkLanguage;
    var += "_WITH_RUNTIME_PATH";
    this->LinkWithRuntimePath = this->Makefile->IsOn(var);
329
330
331
332
333
334
  }

  // Check the platform policy for missing soname case.
  this->NoSONameUsesPath =
    this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");

335
336
337
338
339
340
341
342
343
  // Get link type information.
  this->ComputeLinkTypeInfo();

  // Setup the link item parser.
  this->ComputeItemParserInfo();

  // Setup framework support.
  this->ComputeFrameworkInfo();

344
345
  // Choose a mode for dealing with shared library dependencies.
  this->SharedDependencyMode = SharedDepModeNone;
346
  if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
347
    this->SharedDependencyMode = SharedDepModeLink;
348
  } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
349
    this->SharedDependencyMode = SharedDepModeLibDir;
350
  } else if (!this->RPathLinkFlag.empty()) {
351
    this->SharedDependencyMode = SharedDepModeDir;
352
353
354
    this->OrderDependentRPath = new cmOrderDirectories(
      this->GlobalGenerator, target, "dependent library path");
  }
355

356
  // Add the search path entries requested by the user to path ordering.
357
358
359
360
  std::vector<std::string> directories;
  this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
  this->OrderLinkerSearchPath->AddUserDirectories(directories);
  this->OrderRuntimeSearchPath->AddUserDirectories(directories);
361
362
363

  // Set up the implicit link directories.
  this->LoadImplicitLinkInfo();
364
365
366
367
368
369
  this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
  this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
  if (this->OrderDependentRPath) {
    this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
    this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
  }
370

371
372
373
374
375
376
377
378
379
380
381
  // Decide whether to enable compatible library search path mode.
  // There exists code that effectively does
  //
  //    /path/to/libA.so -lB
  //
  // where -lB is meant to link to /path/to/libB.so.  This is broken
  // because it specified -lB without specifying a link directory (-L)
  // in which to search for B.  This worked in CMake 2.4 and below
  // because -L/path/to would be added by the -L/-l split for A.  In
  // order to support such projects we need to add the directories
  // containing libraries linked with a full path to the -L path.
382
  this->OldLinkDirMode =
383
    this->Target->GetPolicyStatusCMP0003() != cmPolicies::NEW;
384
  if (this->OldLinkDirMode) {
385
386
    // Construct a mask to not bother with this behavior for link
    // directories already specified by the user.
387
    this->OldLinkDirMask.insert(directories.begin(), directories.end());
388
  }
389

390
391
  this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
    "CMAKE_POLICY_WARNING_CMP0060");
392
393
}

394
395
cmComputeLinkInformation::~cmComputeLinkInformation()
{
396
  delete this->OrderLinkerSearchPath;
397
398
399
400
  delete this->OrderRuntimeSearchPath;
  delete this->OrderDependentRPath;
}

401
cmComputeLinkInformation::ItemVector const&
402
cmComputeLinkInformation::GetItems() const
403
404
405
406
407
{
  return this->Items;
}

std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
408
  const
409
{
410
  return this->OrderLinkerSearchPath->GetOrderedDirectories();
411
412
}

413
std::string cmComputeLinkInformation::GetRPathLinkString() const
414
415
416
{
  // If there is no separate linker runtime search flag (-rpath-link)
  // there is no reason to compute a string.
417
  if (!this->OrderDependentRPath) {
418
    return "";
419
  }
420

421
422
  // Construct the linker runtime search path. These MUST NOT contain tokens
  // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
423
  return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
424
425
}

426
std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const
427
428
429
430
431
{
  return this->Depends;
}

std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
432
  const
433
434
435
436
{
  return this->FrameworkPaths;
}

437
const std::set<const cmGeneratorTarget*>&
438
cmComputeLinkInformation::GetSharedLibrariesLinked() const
439
440
441
442
{
  return this->SharedLibrariesLinked;
}

443
444
445
bool cmComputeLinkInformation::Compute()
{
  // Skip targets that do not link.
446
447
448
449
  if (!(this->Target->GetType() == cmStateEnums::EXECUTABLE ||
        this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
        this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
        this->Target->GetType() == cmStateEnums::STATIC_LIBRARY)) {
450
    return false;
451
  }
452
453

  // We require a link language for the target.
454
455
  if (this->LinkLanguage.empty()) {
    cmSystemTools::Error(
456
457
      "CMake can not determine linker language for target: " +
      this->Target->GetName());
458
    return false;
459
  }
460

461
  // Compute the ordered link line items.
462
  cmComputeLinkDepends cld(this->Target, this->Config);
Brad King's avatar
Brad King committed
463
  cld.SetOldLinkDirMode(this->OldLinkDirMode);
464
  cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
465

466
  // Add the link line items.
467
468
469
  for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) {
    if (linkEntry.IsSharedDep) {
      this->AddSharedDepItem(linkEntry.Item, linkEntry.Target);
470
    } else {
471
      this->AddItem(linkEntry.Item, linkEntry.Target);
472
    }
473
  }
474
475
476

  // Restore the target link type so the correct system runtime
  // libraries are found.
477
478
  const char* lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
  if (cmSystemTools::IsOn(lss)) {
479
    this->SetCurrentLinkType(LinkStatic);
480
  } else {
481
    this->SetCurrentLinkType(this->StartLinkType);
482
  }
483

Brad King's avatar
Brad King committed
484
  // Finish listing compatibility paths.
485
  if (this->OldLinkDirMode) {
Brad King's avatar
Brad King committed
486
487
488
    // For CMake 2.4 bug-compatibility we need to consider the output
    // directories of targets linked in another configuration as link
    // directories.
489
    std::set<cmGeneratorTarget const*> const& wrongItems =
490
      cld.GetOldWrongConfigItems();
491
    for (cmGeneratorTarget const* tgt : wrongItems) {
492
      cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
493
494
        ? cmStateEnums::ImportLibraryArtifact
        : cmStateEnums::RuntimeBinaryArtifact;
495
496
      this->OldLinkDirItems.push_back(
        tgt->GetFullPath(this->Config, artifact, true));
Brad King's avatar
Brad King committed
497
    }
498
  }
Brad King's avatar
Brad King committed
499

500
  // Finish setting up linker search directories.
501
  if (!this->FinishLinkerSearchDirectories()) {
502
    return false;
503
  }
504

505
  // Add implicit language runtime libraries and directories.
506
507
  this->AddImplicitLinkInfo();

508
  if (!this->CMP0060WarnItems.empty()) {
509
    std::ostringstream w;
510
    /* clang-format off */
Stephen Kelly's avatar
Stephen Kelly committed
511
    w << cmPolicies::GetPolicyWarning(cmPolicies::CMP0060) << "\n"
512
513
514
515
516
517
518
      "Some library files are in directories implicitly searched by "
      "the linker when invoked for " << this->LinkLanguage << ":\n"
      " " << cmJoin(this->CMP0060WarnItems, "\n ") << "\n"
      "For compatibility with older versions of CMake, the generated "
      "link line will ask the linker to search for these by library "
      "name."
      ;
519
    /* clang-format on */
520
    this->CMakeInstance->IssueMessage(MessageType::AUTHOR_WARNING, w.str(),
521
                                      this->Target->GetBacktrace());
522
  }
523

524
525
526
527
528
529
  return true;
}

void cmComputeLinkInformation::AddImplicitLinkInfo()
{
  // The link closure lists all languages whose implicit info is needed.
530
  cmGeneratorTarget::LinkClosure const* lc =
531
    this->Target->GetLinkClosure(this->Config);
532
  for (std::string const& li : lc->Languages) {
533
    // Skip those of the linker language.  They are implicit.
534
535
    if (li != this->LinkLanguage) {
      this->AddImplicitLinkInfo(li);
536
    }
537
  }
538
}
539

540
541
542
543
544
545
546
void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
{
  // Add libraries for this language that are not implied by the
  // linker language.
  std::string libVar = "CMAKE_";
  libVar += lang;
  libVar += "_IMPLICIT_LINK_LIBRARIES";
547
  if (const char* libs = this->Makefile->GetDefinition(libVar)) {
548
549
    std::vector<std::string> libsVec;
    cmSystemTools::ExpandListArgument(libs, libsVec);
550
551
552
    for (std::string const& i : libsVec) {
      if (this->ImplicitLinkLibs.find(i) == this->ImplicitLinkLibs.end()) {
        this->AddItem(i, nullptr);
553
554
      }
    }
555
  }
556

557
558
559
560
561
  // Add linker search paths for this language that are not
  // implied by the linker language.
  std::string dirVar = "CMAKE_";
  dirVar += lang;
  dirVar += "_IMPLICIT_LINK_DIRECTORIES";
562
  if (const char* dirs = this->Makefile->GetDefinition(dirVar)) {
563
564
565
    std::vector<std::string> dirsVec;
    cmSystemTools::ExpandListArgument(dirs, dirsVec);
    this->OrderLinkerSearchPath->AddLanguageDirectories(dirsVec);
566
  }
567
568
}

569
void cmComputeLinkInformation::AddItem(std::string const& item,
570
                                       cmGeneratorTarget const* tgt)
571
572
{
  // Compute the proper name to use to link this library.
573
  const std::string& config = this->Config;
574
  bool impexe = (tgt && tgt->IsExecutableWithExports());
575
  if (impexe && !tgt->HasImportLibrary(config) && !this->LoaderFlag) {
576
577
578
    // Skip linking to executables on platforms with no import
    // libraries or loader flags.
    return;
579
  }
580

581
  if (tgt && tgt->IsLinkable()) {
582
    // This is a CMake target.  Ask the target for its real name.
583
    if (impexe && this->LoaderFlag) {
584
585
586
587
588
      // This link item is an executable that may provide symbols
      // used by this target.  A special flag is needed on this
      // platform.  Add it now.
      std::string linkItem;
      linkItem = this->LoaderFlag;
589
      cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
590
591
        ? cmStateEnums::ImportLibraryArtifact
        : cmStateEnums::RuntimeBinaryArtifact;
592

593
      std::string exe = tgt->GetFullPath(config, artifact, true);
594
      linkItem += exe;
595
596
      this->Items.emplace_back(linkItem, true, tgt);
      this->Depends.push_back(std::move(exe));
597
    } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
598
599
600
      // Add the interface library as an item so it can be considered as part
      // of COMPATIBLE_INTERFACE_ enforcement.  The generators will ignore
      // this for the actual link line.
601
      this->Items.emplace_back(std::string(), false, tgt);
602
603
604
605

      // Also add the item the interface specifies to be used in its place.
      std::string const& libName = tgt->GetImportedLibName(config);
      if (!libName.empty()) {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
606
        this->AddItem(libName, nullptr);
607
      }
608
609
610
    } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
      // Ignore object library!
      // Its object-files should already have been extracted for linking.
611
    } else {
612
      // Decide whether to use an import library.
613
      cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
614
615
        ? cmStateEnums::ImportLibraryArtifact
        : cmStateEnums::RuntimeBinaryArtifact;
616

617
      // Pass the full path to the target file.
618
      std::string lib = tgt->GetFullPath(config, artifact, true);
619
620
621
622
623
624
625
626
627
      if (tgt->Target->IsAIX() && cmHasLiteralSuffix(lib, "-NOTFOUND") &&
          artifact == cmStateEnums::ImportLibraryArtifact) {
        // This is an imported executable on AIX that has ENABLE_EXPORTS
        // but not IMPORTED_IMPLIB.  CMake used to produce and accept such
        // imported executables on AIX before we taught it to use linker
        // import files.  For compatibility, simply skip linking to this
        // executable as we did before.  It works with runtime linking.
        return;
      }
628
      if (!this->LinkDependsNoShared ||
629
          tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
630
        this->Depends.push_back(lib);
631
      }
632

633
634
      this->AddTargetItem(lib, tgt);
      this->AddLibraryRuntimeInfo(lib, tgt);
635
    }
636
  } else {
637
    // This is not a CMake target.  Use the name given.
638
    if (cmSystemTools::FileIsFullPath(item)) {
639
      if (cmSystemTools::FileIsDirectory(item)) {
640
641
        // This is a directory.
        this->AddDirectoryItem(item);
642
      } else {
643
644
        // Use the full path given to the library file.
        this->Depends.push_back(item);
645
        this->AddFullItem(item);
646
647
        this->AddLibraryRuntimeInfo(item);
      }
648
    } else {
649
      // This is a library or option specified by the user.
650
      this->AddUserItem(item, true);
651
    }
652
  }
653
654
}

655
void cmComputeLinkInformation::AddSharedDepItem(std::string const& item,
656
                                                const cmGeneratorTarget* tgt)
657
658
{
  // If dropping shared library dependencies, ignore them.
659
  if (this->SharedDependencyMode == SharedDepModeNone) {
660
    return;
661
  }
662
663
664

  // The user may have incorrectly named an item.  Skip items that are
  // not full paths to shared libraries.
665
  if (tgt) {
666
667
    // The target will provide a full path.  Make sure it is a shared
    // library.
668
    if (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
669
670
      return;
    }
671
  } else {
672
673
    // Skip items that are not full paths.  We will not be able to
    // reliably specify them.
674
    if (!cmSystemTools::FileIsFullPath(item)) {
675
      return;
676
    }
677
678
679

    // Get the name of the library from the file name.
    std::string file = cmSystemTools::GetFilenameName(item);
680
    if (!this->ExtractSharedLibraryName.find(file)) {
681
682
683
      // This is not the name of a shared library.
      return;
    }
684
  }
685
686

  // If in linking mode, just link to the shared library.
687
  if (this->SharedDependencyMode == SharedDepModeLink) {
688
689
    this->AddItem(item, tgt);
    return;
690
  }
691
692
693
694
695

  // Get a full path to the dependent shared library.
  // Add it to the runtime path computation so that the target being
  // linked will be able to find it.
  std::string lib;
696
  if (tgt) {
697
    cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
698
699
700
      ? cmStateEnums::ImportLibraryArtifact
      : cmStateEnums::RuntimeBinaryArtifact;
    lib = tgt->GetFullPath(this->Config, artifact);
701
    this->AddLibraryRuntimeInfo(lib, tgt);
702
  } else {
703
704
    lib = item;
    this->AddLibraryRuntimeInfo(lib);
705
  }
706

707
708
  // Check if we need to include the dependent shared library in other
  // path ordering.
Daniel Pfeifer's avatar
Daniel Pfeifer committed
709
  cmOrderDirectories* order = nullptr;
710
711
  if (this->SharedDependencyMode == SharedDepModeLibDir &&
      !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
712
713
    // Add the item to the linker search path.
    order = this->OrderLinkerSearchPath;
714
  } else if (this->SharedDependencyMode == SharedDepModeDir) {
715
716
    // Add the item to the separate dependent library search path.
    order = this->OrderDependentRPath;
717
718
719
  }
  if (order) {
    if (tgt) {
720
      std::string soName = tgt->GetSOName(this->Config);
Daniel Pfeifer's avatar
Daniel Pfeifer committed
721
      const char* soname = soName.empty() ? nullptr : soName.c_str();
722
      order->AddRuntimeLibrary(lib, soname);
723
    } else {
724
      order->AddRuntimeLibrary(lib);
725
    }
726
  }
727
728
}

729
730
void cmComputeLinkInformation::ComputeLinkTypeInfo()
{
731
  // Check whether archives may actually be shared libraries.
732
733
734
  this->ArchivesMayBeShared =
    this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
      "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
735

736
737
738
739
  // First assume we cannot do link type stuff.
  this->LinkTypeEnabled = false;

  // Lookup link type selection flags.
Daniel Pfeifer's avatar
Daniel Pfeifer committed
740
741
742
  const char* static_link_type_flag = nullptr;
  const char* shared_link_type_flag = nullptr;
  const char* target_type_str = nullptr;
743
  switch (this->Target->GetType()) {
744
    case cmStateEnums::EXECUTABLE:
745
746
      target_type_str = "EXE";
      break;
747
    case cmStateEnums::SHARED_LIBRARY:
748
749
      target_type_str = "SHARED_LIBRARY";
      break;
750
    case cmStateEnums::MODULE_LIBRARY:
751
752
753
754
755
756
      target_type_str = "SHARED_MODULE";
      break;
    default:
      break;
  }
  if (target_type_str) {
757
758
759
760
761
762
    std::string static_link_type_flag_var = "CMAKE_";
    static_link_type_flag_var += target_type_str;
    static_link_type_flag_var += "_LINK_STATIC_";
    static_link_type_flag_var += this->LinkLanguage;
    static_link_type_flag_var += "_FLAGS";
    static_link_type_flag =
Stephen Kelly's avatar
Stephen Kelly committed
763
      this->Makefile->GetDefinition(static_link_type_flag_var);
764
765
766
767
768
769
770

    std::string shared_link_type_flag_var = "CMAKE_";
    shared_link_type_flag_var += target_type_str;
    shared_link_type_flag_var += "_LINK_DYNAMIC_";
    shared_link_type_flag_var += this->LinkLanguage;
    shared_link_type_flag_var += "_FLAGS";
    shared_link_type_flag =
Stephen Kelly's avatar
Stephen Kelly committed
771
      this->Makefile->GetDefinition(shared_link_type_flag_var);
772
  }
773
774
775

  // We can support link type switching only if all needed flags are
  // known.
776
777
  if (static_link_type_flag && *static_link_type_flag &&
      shared_link_type_flag && *shared_link_type_flag) {
778
779
780
    this->LinkTypeEnabled = true;
    this->StaticLinkTypeFlag = static_link_type_flag;
    this->SharedLinkTypeFlag = shared_link_type_flag;
781
  }
782

783
  // Lookup the starting link type from the target (linked statically?).
784
785
  const char* lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
  this->StartLinkType = cmSystemTools::IsOn(lss) ? LinkStatic : LinkShared;
786
  this->CurrentLinkType = this->StartLinkType;
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
}

void cmComputeLinkInformation::ComputeItemParserInfo()
{
  // Get possible library name prefixes.
  cmMakefile* mf = this->Makefile;
  this->AddLinkPrefix(mf->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
  this->AddLinkPrefix(mf->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));

  // Import library names should be matched and treated as shared
  // libraries for the purposes of linking.
  this->AddLinkExtension(mf->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
                         LinkShared);
  this->AddLinkExtension(mf->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
                         LinkStatic);
  this->AddLinkExtension(mf->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
                         LinkShared);
  this->AddLinkExtension(mf->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
                         LinkUnknown);
806
807
  if (const char* linkSuffixes =
        mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
808
809
    std::vector<std::string> linkSuffixVec;
    cmSystemTools::ExpandListArgument(linkSuffixes, linkSuffixVec);
810
811
    for (std::string const& i : linkSuffixVec) {
      this->AddLinkExtension(i.c_str(), LinkUnknown);
812
    }
813
814
815
  }
  if (const char* sharedSuffixes =
        mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
816
817
    std::vector<std::string> sharedSuffixVec;
    cmSystemTools::ExpandListArgument(sharedSuffixes, sharedSuffixVec);
818
819
    for (std::string const& i : sharedSuffixVec) {
      this->AddLinkExtension(i.c_str(), LinkShared);
820
    }
821
  }
822
823

  // Compute a regex to match link extensions.
824
825
  std::string libext =
    this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
826
827
828
829

  // Create regex to remove any library extension.
  std::string reg("(.*)");
  reg += libext;
830
  this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
831
832
833
834
835
836

  // Create a regex to match a library name.  Match index 1 will be
  // the prefix if it exists and empty otherwise.  Match index 2 will
  // be the library name.  Match index 3 will be the library
  // extension.
  reg = "^(";
837
838
  for (std::string const& p : this->LinkPrefixes) {
    reg += p;
839
    reg += "|";
840
  }
841
  reg += ")";
842
  reg += "([^/:]*)";
843
844
845
846
847
848
849
850
851
852

  // Create a regex to match any library name.
  std::string reg_any = reg;
  reg_any += libext;
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
  fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
#endif
  this->ExtractAnyLibraryName.compile(reg_any.c_str());

  // Create a regex to match static library names.
853
  if (!this->StaticLinkExtensions.empty()) {
854
    std::string reg_static = reg;
855
856
    reg_static +=
      this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic);
857
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
858
    fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
859
860
#endif
    this->ExtractStaticLibraryName.compile(reg_static.c_str());
861
  }
862
863

  // Create a regex to match shared library names.
864
  if (!this->SharedLinkExtensions.empty()) {
865
    std::string reg_shared = reg;
866
    this->SharedRegexString =
867
      this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
868
    reg_shared += this->SharedRegexString;
869
#ifdef CM_COMPUTE_LINK_INFO_DEBUG
870
    fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
871
872
#endif
    this->ExtractSharedLibraryName.compile(reg_shared.c_str());
873
  }
874
875
876
877
}

void cmComputeLinkInformation::AddLinkPrefix(const char* p)
{
878
  if (p && *p) {
879
    this->LinkPrefixes.insert(p);
880
  }
881
882
883
884
}

void cmComputeLinkInformation::AddLinkExtension(const char* e, LinkType type)
{
885
886
  if (e && *e) {
    if (type == LinkStatic) {
wahikihiki's avatar
wahikihiki committed
887
      this->StaticLinkExtensions.emplace_back(e);
888
889
    }
    if (type == LinkShared) {
wahikihiki's avatar
wahikihiki committed
890
      this->SharedLinkExtensions.emplace_back(e);
891
    }
wahikihiki's avatar
wahikihiki committed
892
    this->LinkExtensions.emplace_back(e);
893
  }
894
895
}

896
897
std::string cmComputeLinkInformation::CreateExtensionRegex(
  std::vector<std::string> const& exts, LinkType type)
898
899
900
901
{
  // Build a list of extension choices.
  std::string libext = "(";
  const char* sep = "";
902
  for (std::string const& i : exts) {
903
904
905
906
907
908
909
    // Separate this choice from the previous one.
    libext += sep;
    sep = "|";

    // Store this extension choice with the "." escaped.
    libext += "\\";
#if defined(_WIN32) && !defined(__CYGWIN__)
910
    libext += this->NoCaseExpression(i.c_str());
911
#else
912
    libext += i;
913
#endif
914
  }
915
916

  // Finish the list.
917
918
  libext += ")";

919
920
921
  // Add an optional OpenBSD-style version or major.minor.version component.
  if (this->OpenBSD || type == LinkShared) {
    libext += "(\\.[0-9]+)*";
922
  }
923
924

  libext += "$";
925
926
927
928
929
930
931
  return libext;
}

std::string cmComputeLinkInformation::NoCaseExpression(const char* str)
{
  std::string ret;
  const char* s = str;
932
933
  while (*s) {
    if (*s == '.') {
934
      ret += *s;
935
    } else {
936
      ret += "[";
937
938
      ret += static_cast<char>(tolower(*s));
      ret += static_cast<char>(toupper(*s));
939
940
      ret += "]";
    }
941
942
    s++;
  }
943
944
945
946
947
948
949
  return ret;
}

void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
{
  // If we are changing the current link type add the flag to tell the
  // linker about it.
950
  if (this->CurrentLinkType != lt) {
951
952
    this->CurrentLinkType = lt;

953
954
    if (this->LinkTypeEnabled) {
      switch (this->CurrentLinkType) {
955
        case LinkStatic:
956
          this->Items.emplace_back(this->StaticLinkTypeFlag, false);
957
958
          break;
        case LinkShared:
959
          this->Items.emplace_back(this->SharedLinkTypeFlag, false);
960
961
962
963
964
          break;
        default:
          break;
      }
    }
965
  }
966
967
}

968
void cmComputeLinkInformation::AddTargetItem(std::string const& item,
969
                                             cmGeneratorTarget const* target)
970
971
972
973
974
975
976
{
  // This is called to handle a link item that is a full path to a target.
  // If the target is not a static library make sure the link type is
  // shared.  This is because dynamic-mode linking can handle both
  // shared and static libraries but static-mode can handle only
  // static libraries.  If a previous user item changed the link type
  // to static we need to make sure it is back to shared.
977
  if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
978
    this->SetCurrentLinkType(LinkShared);
979
  }
980

981
  // Keep track of shared library targets linked.
982
  if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
983
    this->SharedLibrariesLinked.insert(target);
984
  }
985

986
  // Handle case of an imported shared library with no soname.
987
988
  if (this->NoSONameUsesPath &&
      target->IsImportedSharedLibWithoutSOName(this->Config)) {
989
990
    this->AddSharedLibNoSOName(item);
    return;
991
  }
992

993
994
  // For compatibility with CMake 2.4 include the item's directory in
  // the linker search path.
995
996
997
  if (this->OldLinkDirMode && !target->IsFrameworkOnApple() &&
      this->OldLinkDirMask.find(cmSystemTools::GetFilenamePath(item)) ==
        this->OldLinkDirMask.end()) {
998
    this->OldLinkDirItems.push_back(item);
999
  }
1000

1001
  // Now add the full path to the library.
1002
  this->Items.emplace_back(item, true, target