| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmComputeLinkInformation.h"
- #include <algorithm>
- #include <cctype>
- #include <sstream>
- #include <utility>
- #include <cm/memory>
- #include <cm/optional>
- #include <cm/string_view>
- #include <cmext/algorithm>
- #include <cmext/string_view>
- #include "cmComputeLinkDepends.h"
- #include "cmGeneratorTarget.h"
- #include "cmGlobalGenerator.h"
- #include "cmLinkItem.h"
- #include "cmList.h"
- #include "cmListFileCache.h"
- #include "cmLocalGenerator.h"
- #include "cmMakefile.h"
- #include "cmMessageType.h"
- #include "cmOrderDirectories.h"
- #include "cmPlaceholderExpander.h"
- #include "cmSourceFile.h"
- #include "cmState.h"
- #include "cmStateTypes.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- #include "cmTarget.h"
- #include "cmValue.h"
- #include "cmXcFramework.h"
- #include "cmake.h"
- // #define CM_COMPUTE_LINK_INFO_DEBUG
- /*
- Notes about linking on various platforms:
- ------------------------------------------------------------------------------
- Linux, FreeBSD, macOS, Sun, Windows:
- 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).
- ------------------------------------------------------------------------------
- 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.
- - 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.
- 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.
- ------------------------------------------------------------------------------
- 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.
- */
- cmComputeLinkInformation::cmComputeLinkInformation(
- const cmGeneratorTarget* target, const std::string& config)
- // Store context information.
- : Target(target)
- , Makefile(target->Target->GetMakefile())
- , GlobalGenerator(target->GetLocalGenerator()->GetGlobalGenerator())
- , CMakeInstance(this->GlobalGenerator->GetCMakeInstance())
- // The configuration being linked.
- , Config(config)
- {
- // Check whether to recognize OpenBSD-style library versioned names.
- this->IsOpenBSD = this->Makefile->GetState()->GetGlobalPropertyAsBool(
- "FIND_LIBRARY_USE_OPENBSD_VERSIONING");
- // Allocate internals.
- this->OrderLinkerSearchPath = cm::make_unique<cmOrderDirectories>(
- this->GlobalGenerator, target, "linker search path");
- this->OrderRuntimeSearchPath = cm::make_unique<cmOrderDirectories>(
- this->GlobalGenerator, target, "runtime search path");
- // Get the language used for linking this target.
- this->LinkLanguage = this->Target->GetLinkerLanguage(config);
- if (this->LinkLanguage.empty()) {
- // The Compute method will do nothing, so skip the rest of the
- // initialization.
- return;
- }
- // Check whether we should skip dependencies on shared library files.
- this->LinkDependsNoShared =
- this->Target->GetPropertyAsBool("LINK_DEPENDS_NO_SHARED");
- // 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.
- if (!this->Target->IsDLLPlatform() &&
- this->Target->GetType() == cmStateEnums::MODULE_LIBRARY) {
- std::string loader_flag_var =
- cmStrCat("CMAKE_SHARED_MODULE_LOADER_", this->LinkLanguage, "_FLAG");
- this->LoaderFlag = this->Makefile->GetDefinition(loader_flag_var);
- }
- // Get options needed to link libraries.
- if (cmValue flag = this->Makefile->GetDefinition(
- cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_FLAG"))) {
- this->LibLinkFlag = *flag;
- } else {
- this->LibLinkFlag =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG");
- }
- if (cmValue flag = this->Makefile->GetDefinition(
- cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_FILE_FLAG"))) {
- this->LibLinkFileFlag = *flag;
- } else {
- this->LibLinkFileFlag =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FILE_FLAG");
- }
- if (cmValue suffix = this->Makefile->GetDefinition(
- cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_SUFFIX"))) {
- this->LibLinkSuffix = *suffix;
- } else {
- this->LibLinkSuffix =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX");
- }
- if (cmValue flag = this->Makefile->GetDefinition(
- cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_OBJECT_FILE_FLAG"))) {
- this->ObjLinkFileFlag = *flag;
- } else {
- this->ObjLinkFileFlag =
- this->Makefile->GetSafeDefinition("CMAKE_LINK_OBJECT_FILE_FLAG");
- }
- // Get options needed to specify RPATHs.
- this->RuntimeUseChrpath = false;
- if (this->Target->GetType() != cmStateEnums::STATIC_LIBRARY) {
- const char* tType = ((this->Target->GetType() == cmStateEnums::EXECUTABLE)
- ? "EXECUTABLE"
- : "SHARED_LIBRARY");
- std::string rtVar =
- cmStrCat("CMAKE_", tType, "_RUNTIME_", this->LinkLanguage, "_FLAG");
- std::string rtSepVar = cmStrCat(rtVar, "_SEP");
- this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar);
- this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar);
- this->RuntimeAlways = (this->Makefile->GetSafeDefinition(
- "CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"));
- this->RuntimeUseChrpath = this->Target->IsChrpathUsed(config);
- // Get options needed to help find dependent libraries.
- std::string rlVar =
- cmStrCat("CMAKE_", tType, "_RPATH_LINK_", this->LinkLanguage, "_FLAG");
- this->RPathLinkFlag = this->Makefile->GetSafeDefinition(rlVar);
- }
- // Check if we need to include the runtime search path at link time.
- {
- std::string var = cmStrCat("CMAKE_SHARED_LIBRARY_LINK_",
- this->LinkLanguage, "_WITH_RUNTIME_PATH");
- this->LinkWithRuntimePath = this->Makefile->IsOn(var);
- }
- // Define some Feature descriptors to handle standard library and object link
- if (!this->GetLibLinkFileFlag().empty()) {
- this->LibraryFeatureDescriptors.emplace(
- "__CMAKE_LINK_LIBRARY",
- LibraryFeatureDescriptor{
- "__CMAKE_LINK_LIBRARY",
- cmStrCat(this->GetLibLinkFileFlag(), "<LIBRARY>") });
- }
- if (!this->GetObjLinkFileFlag().empty()) {
- this->LibraryFeatureDescriptors.emplace(
- "__CMAKE_LINK_OBJECT",
- LibraryFeatureDescriptor{
- "__CMAKE_LINK_OBJECT",
- cmStrCat(this->GetObjLinkFileFlag(), "<LIBRARY>") });
- }
- if (!this->LoaderFlag->empty()) {
- // Define a Feature descriptor for the link of an executable with exports
- this->LibraryFeatureDescriptors.emplace(
- "__CMAKE_LINK_EXECUTABLE",
- LibraryFeatureDescriptor{ "__CMAKE_LINK_EXECUTABLE",
- cmStrCat(*this->LoaderFlag, "<LIBRARY>") });
- }
- // To link framework using a full path
- this->LibraryFeatureDescriptors.emplace(
- "__CMAKE_LINK_FRAMEWORK",
- LibraryFeatureDescriptor{ "__CMAKE_LINK_FRAMEWORK", "<LIBRARY>" });
- // To link xcframework using a full path
- this->LibraryFeatureDescriptors.emplace(
- "__CMAKE_LINK_XCFRAMEWORK",
- LibraryFeatureDescriptor{ "__CMAKE_LINK_XCFRAMEWORK", "<LIBRARY>" });
- // Check the platform policy for missing soname case.
- this->NoSONameUsesPath =
- this->Makefile->IsOn("CMAKE_PLATFORM_USES_PATH_WHEN_NO_SONAME");
- // Get link type information.
- this->ComputeLinkTypeInfo();
- // Setup the link item parser.
- this->ComputeItemParserInfo();
- // Setup framework support.
- this->ComputeFrameworkInfo();
- // Choose a mode for dealing with shared library dependencies.
- this->SharedDependencyMode = SharedDepModeNone;
- if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_FILES")) {
- this->SharedDependencyMode = SharedDepModeLink;
- } else if (this->Makefile->IsOn("CMAKE_LINK_DEPENDENT_LIBRARY_DIRS")) {
- this->SharedDependencyMode = SharedDepModeLibDir;
- } else if (!this->RPathLinkFlag.empty()) {
- this->SharedDependencyMode = SharedDepModeDir;
- this->OrderDependentRPath = cm::make_unique<cmOrderDirectories>(
- this->GlobalGenerator, target, "dependent library path");
- }
- // Add the search path entries requested by the user to path ordering.
- std::vector<std::string> directories;
- this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
- this->OrderLinkerSearchPath->AddUserDirectories(directories);
- this->OrderRuntimeSearchPath->AddUserDirectories(directories);
- // Set up the implicit link directories.
- this->LoadImplicitLinkInfo();
- this->OrderLinkerSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
- this->OrderRuntimeSearchPath->SetImplicitDirectories(this->ImplicitLinkDirs);
- if (this->OrderDependentRPath) {
- this->OrderDependentRPath->SetImplicitDirectories(this->ImplicitLinkDirs);
- this->OrderDependentRPath->AddLanguageDirectories(this->RuntimeLinkDirs);
- }
- }
- cmComputeLinkInformation::~cmComputeLinkInformation() = default;
- namespace {
- const std::string& DEFAULT = cmComputeLinkDepends::LinkEntry::DEFAULT;
- }
- void cmComputeLinkInformation::AppendValues(
- std::string& result, std::vector<BT<std::string>>& values)
- {
- for (BT<std::string>& p : values) {
- if (result.empty()) {
- result.append(" ");
- }
- result.append(p.Value);
- }
- }
- cmComputeLinkInformation::ItemVector const&
- cmComputeLinkInformation::GetItems() const
- {
- return this->Items;
- }
- std::vector<std::string> const& cmComputeLinkInformation::GetDirectories()
- const
- {
- return this->OrderLinkerSearchPath->GetOrderedDirectories();
- }
- std::vector<BT<std::string>>
- cmComputeLinkInformation::GetDirectoriesWithBacktraces()
- {
- std::vector<BT<std::string>> directoriesWithBacktraces;
- std::vector<BT<std::string>> targetLinkDirectories =
- this->Target->GetLinkDirectories(this->Config, this->LinkLanguage);
- const std::vector<std::string>& orderedDirectories = this->GetDirectories();
- for (const std::string& dir : orderedDirectories) {
- auto result = std::find(targetLinkDirectories.begin(),
- targetLinkDirectories.end(), dir);
- if (result != targetLinkDirectories.end()) {
- directoriesWithBacktraces.emplace_back(std::move(*result));
- } else {
- directoriesWithBacktraces.emplace_back(dir);
- }
- }
- return directoriesWithBacktraces;
- }
- std::string cmComputeLinkInformation::GetRPathLinkString() const
- {
- // If there is no separate linker runtime search flag (-rpath-link)
- // there is no reason to compute a string.
- if (!this->OrderDependentRPath) {
- return "";
- }
- // Construct the linker runtime search path. These MUST NOT contain tokens
- // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
- return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
- }
- std::vector<std::string> const& cmComputeLinkInformation::GetDepends() const
- {
- return this->Depends;
- }
- std::vector<std::string> const& cmComputeLinkInformation::GetFrameworkPaths()
- const
- {
- return this->FrameworkPaths;
- }
- std::set<std::string> const&
- cmComputeLinkInformation::GetFrameworkPathsEmitted() const
- {
- return this->FrameworkPathsEmitted;
- }
- std::vector<std::string> const&
- cmComputeLinkInformation::GetXcFrameworkHeaderPaths() const
- {
- return this->XcFrameworkHeaderPaths;
- }
- const std::set<const cmGeneratorTarget*>&
- cmComputeLinkInformation::GetSharedLibrariesLinked() const
- {
- return this->SharedLibrariesLinked;
- }
- const std::vector<const cmGeneratorTarget*>&
- cmComputeLinkInformation::GetExternalObjectTargets() const
- {
- return this->ExternalObjectTargets;
- }
- bool cmComputeLinkInformation::Compute()
- {
- // Skip targets that do not link or have link-like information consumers may
- // need (namely modules).
- if (!(this->Target->GetType() == cmStateEnums::EXECUTABLE ||
- this->Target->GetType() == cmStateEnums::SHARED_LIBRARY ||
- this->Target->GetType() == cmStateEnums::MODULE_LIBRARY ||
- this->Target->GetType() == cmStateEnums::STATIC_LIBRARY ||
- (this->Target->CanCompileSources() &&
- (this->Target->HaveCxxModuleSupport(this->Config) ==
- cmGeneratorTarget::Cxx20SupportLevel::Supported ||
- this->Target->HaveFortranSources())))) {
- return false;
- }
- // We require a link language for the target.
- if (this->LinkLanguage.empty()) {
- cmSystemTools::Error(
- "CMake can not determine linker language for target: " +
- this->Target->GetName());
- return false;
- }
- LinkLibrariesStrategy strategy = LinkLibrariesStrategy::REORDER_MINIMALLY;
- if (cmValue s = this->Target->GetProperty("LINK_LIBRARIES_STRATEGY")) {
- if (*s == "REORDER_MINIMALLY"_s) {
- strategy = LinkLibrariesStrategy::REORDER_MINIMALLY;
- } else if (*s == "REORDER_FREELY"_s) {
- strategy = LinkLibrariesStrategy::REORDER_FREELY;
- } else {
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("LINK_LIBRARIES_STRATEGY value '", *s,
- "' is not recognized."),
- this->Target->GetBacktrace());
- return false;
- }
- }
- // Compute the ordered link line items.
- cmComputeLinkDepends cld(this->Target, this->Config, this->LinkLanguage,
- strategy);
- cmComputeLinkDepends::EntryVector const& linkEntries = cld.Compute();
- FeatureDescriptor const* currentFeature = nullptr;
- // Add the link line items.
- for (cmComputeLinkDepends::LinkEntry const& linkEntry : linkEntries) {
- if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::Group) {
- const auto& groupFeature = this->GetGroupFeature(linkEntry.Feature);
- if (groupFeature.Supported) {
- if (linkEntry.Item.Value == "</LINK_GROUP>" && currentFeature) {
- // emit feature suffix, if any
- if (!currentFeature->Suffix.empty()) {
- this->Items.emplace_back(
- BT<std::string>{ currentFeature->Suffix,
- this->Items.back().Value.Backtrace },
- ItemIsPath::No);
- }
- currentFeature = nullptr;
- }
- this->Items.emplace_back(
- BT<std::string>{ linkEntry.Item.Value == "<LINK_GROUP>"
- ? groupFeature.Prefix
- : groupFeature.Suffix,
- linkEntry.Item.Backtrace },
- ItemIsPath::No);
- }
- continue;
- }
- if (currentFeature && linkEntry.Feature != currentFeature->Name) {
- // emit feature suffix, if any
- if (!currentFeature->Suffix.empty()) {
- this->Items.emplace_back(
- BT<std::string>{ currentFeature->Suffix,
- this->Items.back().Value.Backtrace },
- ItemIsPath::No);
- }
- currentFeature = nullptr;
- }
- if (linkEntry.Feature != DEFAULT &&
- (!currentFeature || linkEntry.Feature != currentFeature->Name)) {
- if (!this->AddLibraryFeature(linkEntry.Feature)) {
- continue;
- }
- currentFeature = this->FindLibraryFeature(linkEntry.Feature);
- // emit feature prefix, if any
- if (!currentFeature->Prefix.empty()) {
- this->Items.emplace_back(
- BT<std::string>{ currentFeature->Prefix, linkEntry.Item.Backtrace },
- ItemIsPath::No);
- }
- }
- if (linkEntry.Kind == cmComputeLinkDepends::LinkEntry::SharedDep) {
- this->AddSharedDepItem(linkEntry);
- } else {
- this->AddItem(linkEntry);
- }
- }
- if (currentFeature) {
- // emit feature suffix, if any
- if (!currentFeature->Suffix.empty()) {
- this->Items.emplace_back(
- BT<std::string>{ currentFeature->Suffix,
- this->Items.back().Value.Backtrace },
- ItemIsPath::No);
- }
- }
- // Restore the target link type so the correct system runtime
- // libraries are found.
- cmValue lss = this->Target->GetProperty("LINK_SEARCH_END_STATIC");
- if (lss.IsOn()) {
- this->SetCurrentLinkType(LinkStatic);
- } else {
- this->SetCurrentLinkType(this->StartLinkType);
- }
- // Add implicit language runtime libraries and directories.
- this->AddImplicitLinkInfo();
- // Record targets referenced by $<TARGET_OBJECTS:...> sources.
- this->AddExternalObjectTargets();
- return true;
- }
- namespace {
- void FinalizeFeatureFormat(std::string& format, const std::string& activeTag,
- const std::string& otherTag)
- {
- auto pos = format.find(otherTag);
- if (pos != std::string::npos) {
- format.erase(pos, format.find('}', pos) - pos + 1);
- }
- pos = format.find(activeTag);
- if (pos != std::string::npos) {
- format.erase(pos, activeTag.length());
- pos = format.find('}', pos);
- if (pos != std::string::npos) {
- format.erase(pos, 1);
- }
- }
- }
- bool IsValidFeatureFormat(const std::string& format)
- {
- return format.find("<LIBRARY>") != std::string::npos ||
- format.find("<LIB_ITEM>") != std::string::npos ||
- format.find("<LINK_ITEM>") != std::string::npos;
- }
- class FeaturePlaceHolderExpander : public cmPlaceholderExpander
- {
- public:
- FeaturePlaceHolderExpander(const std::string* library,
- const std::string* libItem = nullptr,
- const std::string* linkItem = nullptr)
- : Library(library)
- , LibItem(libItem)
- , LinkItem(linkItem)
- {
- }
- private:
- std::string ExpandVariable(std::string const& variable) override
- {
- if (this->Library && variable == "LIBRARY") {
- return *this->Library;
- }
- if (this->LibItem && variable == "LIB_ITEM") {
- return *this->LibItem;
- }
- if (this->LinkItem && variable == "LINK_ITEM") {
- return *this->LinkItem;
- }
- return variable;
- }
- const std::string* Library = nullptr;
- const std::string* LibItem = nullptr;
- const std::string* LinkItem = nullptr;
- };
- }
- cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
- std::string name, std::string itemFormat)
- : Name(std::move(name))
- , Supported(true)
- , ItemPathFormat(std::move(itemFormat))
- , ItemNameFormat(this->ItemPathFormat)
- {
- }
- cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
- std::string name, std::string itemPathFormat, std::string itemNameFormat)
- : Name(std::move(name))
- , Supported(true)
- , ItemPathFormat(std::move(itemPathFormat))
- , ItemNameFormat(std::move(itemNameFormat))
- {
- }
- cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
- std::string name, std::string prefix, std::string itemPathFormat,
- std::string itemNameFormat, std::string suffix)
- : Name(std::move(name))
- , Supported(true)
- , Prefix(std::move(prefix))
- , Suffix(std::move(suffix))
- , ItemPathFormat(std::move(itemPathFormat))
- , ItemNameFormat(std::move(itemNameFormat))
- {
- }
- cmComputeLinkInformation::FeatureDescriptor::FeatureDescriptor(
- std::string name, std::string prefix, std::string suffix, bool)
- : Name(std::move(name))
- , Supported(true)
- , Prefix(std::move(prefix))
- , Suffix(std::move(suffix))
- {
- }
- std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
- std::string const& library, ItemIsPath isPath) const
- {
- auto format =
- isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
- // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns with library path
- FeaturePlaceHolderExpander expander(&library, &library, &library);
- return expander.ExpandVariables(format);
- }
- std::string cmComputeLinkInformation::FeatureDescriptor::GetDecoratedItem(
- std::string const& library, std::string const& libItem,
- std::string const& linkItem, ItemIsPath isPath) const
- {
- auto format =
- isPath == ItemIsPath::Yes ? this->ItemPathFormat : this->ItemNameFormat;
- // replace <LIBRARY>, <LIB_ITEM> and <LINK_ITEM> patterns
- FeaturePlaceHolderExpander expander(&library, &libItem, &linkItem);
- return expander.ExpandVariables(format);
- }
- cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
- std::string name, std::string itemFormat)
- : FeatureDescriptor(std::move(name), std::move(itemFormat))
- {
- }
- cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
- std::string name, std::string itemPathFormat, std::string itemNameFormat)
- : FeatureDescriptor(std::move(name), std::move(itemPathFormat),
- std::move(itemNameFormat))
- {
- }
- cmComputeLinkInformation::LibraryFeatureDescriptor::LibraryFeatureDescriptor(
- std::string name, std::string prefix, std::string itemPathFormat,
- std::string itemNameFormat, std::string suffix)
- : FeatureDescriptor(std::move(name), std::move(prefix),
- std::move(itemPathFormat), std::move(itemNameFormat),
- std::move(suffix))
- {
- }
- bool cmComputeLinkInformation::AddLibraryFeature(std::string const& feature)
- {
- auto it = this->LibraryFeatureDescriptors.find(feature);
- if (it != this->LibraryFeatureDescriptors.end()) {
- return it->second.Supported;
- }
- auto featureName =
- cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_LIBRARY_USING_", feature);
- cmValue featureSupported =
- this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
- if (!featureSupported) {
- // language specific variable is not defined, fallback to the more generic
- // one
- featureName = cmStrCat("CMAKE_LINK_LIBRARY_USING_", feature);
- featureSupported =
- this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
- }
- if (!featureSupported.IsOn()) {
- this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(
- "Feature '", feature,
- "', specified through generator-expression '$<LINK_LIBRARY>' to "
- "link target '",
- this->Target->GetName(), "', is not supported for the '",
- this->LinkLanguage, "' link language."),
- this->Target->GetBacktrace());
- return false;
- }
- cmValue langFeature = this->Makefile->GetDefinition(featureName);
- if (!langFeature) {
- this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat(
- "Feature '", feature,
- "', specified through generator-expression '$<LINK_LIBRARY>' to "
- "link target '",
- this->Target->GetName(), "', is not defined for the '",
- this->LinkLanguage, "' link language."),
- this->Target->GetBacktrace());
- return false;
- }
- auto items = cmExpandListWithBacktrace(
- *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
- if ((items.size() == 1 && !IsValidFeatureFormat(items.front().Value)) ||
- (items.size() == 3 && !IsValidFeatureFormat(items[1].Value))) {
- this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature, "', specified by variable '", featureName,
- "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
- "\"<LINK_ITEM>\" patterns "
- "are missing) and cannot be used to link target '",
- this->Target->GetName(), "'."),
- this->Target->GetBacktrace());
- return false;
- }
- // now, handle possible "PATH{}" and "NAME{}" patterns
- if (items.size() == 1) {
- items.push_back(items.front());
- FinalizeFeatureFormat(items[0].Value, "PATH{", "NAME{");
- FinalizeFeatureFormat(items[1].Value, "NAME{", "PATH{");
- } else if (items.size() == 3) {
- items.insert(items.begin() + 1, items[1]);
- FinalizeFeatureFormat(items[1].Value, "PATH{", "NAME{");
- FinalizeFeatureFormat(items[2].Value, "NAME{", "PATH{");
- } else {
- this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature, "', specified by variable '", featureName,
- "', is malformed (wrong number of elements) and cannot be used "
- "to link target '",
- this->Target->GetName(), "'."),
- this->Target->GetBacktrace());
- return false;
- }
- if ((items.size() == 2 && !IsValidFeatureFormat(items[0].Value)) ||
- (items.size() == 4 && !IsValidFeatureFormat(items[1].Value))) {
- // PATH{} has wrong format
- this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature, "', specified by variable '", featureName,
- "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
- "\"<LINK_ITEM>\" patterns "
- "are missing for \"PATH{}\" alternative) and cannot be used to "
- "link target '",
- this->Target->GetName(), "'."),
- this->Target->GetBacktrace());
- return false;
- }
- if ((items.size() == 2 && !IsValidFeatureFormat(items[1].Value)) ||
- (items.size() == 4 && !IsValidFeatureFormat(items[2].Value))) {
- // NAME{} has wrong format
- this->LibraryFeatureDescriptors.emplace(feature, FeatureDescriptor{});
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature, "', specified by variable '", featureName,
- "', is malformed (\"<LIBRARY>\", \"<LIB_ITEM>\", or "
- "\"<LINK_ITEM>\" patterns "
- "are missing for \"NAME{}\" alternative) and cannot be used to "
- "link target '",
- this->Target->GetName(), "'."),
- this->Target->GetBacktrace());
- return false;
- }
- // replace LINKER: pattern
- this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
- if (items.size() == 2) {
- this->LibraryFeatureDescriptors.emplace(
- feature,
- LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value });
- } else {
- this->LibraryFeatureDescriptors.emplace(
- feature,
- LibraryFeatureDescriptor{ feature, items[0].Value, items[1].Value,
- items[2].Value, items[3].Value });
- }
- return true;
- }
- cmComputeLinkInformation::FeatureDescriptor const&
- cmComputeLinkInformation::GetLibraryFeature(std::string const& feature) const
- {
- return this->LibraryFeatureDescriptors.find(feature)->second;
- }
- cmComputeLinkInformation::FeatureDescriptor const*
- cmComputeLinkInformation::FindLibraryFeature(std::string const& feature) const
- {
- auto it = this->LibraryFeatureDescriptors.find(feature);
- if (it == this->LibraryFeatureDescriptors.end()) {
- return nullptr;
- }
- return &it->second;
- }
- cmComputeLinkInformation::GroupFeatureDescriptor::GroupFeatureDescriptor(
- std::string name, std::string prefix, std::string suffix)
- : FeatureDescriptor(std::move(name), std::move(prefix), std::move(suffix),
- true)
- {
- }
- cmComputeLinkInformation::FeatureDescriptor const&
- cmComputeLinkInformation::GetGroupFeature(std::string const& feature)
- {
- auto it = this->GroupFeatureDescriptors.find(feature);
- if (it != this->GroupFeatureDescriptors.end()) {
- return it->second;
- }
- auto featureName =
- cmStrCat("CMAKE_", this->LinkLanguage, "_LINK_GROUP_USING_", feature);
- cmValue featureSupported =
- this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
- if (!featureSupported) {
- // language specific variable is not defined, fallback to the more generic
- // one
- featureName = cmStrCat("CMAKE_LINK_GROUP_USING_", feature);
- featureSupported =
- this->Makefile->GetDefinition(cmStrCat(featureName, "_SUPPORTED"));
- }
- if (!featureSupported.IsOn()) {
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature,
- "', specified through generator-expression '$<LINK_GROUP>' to "
- "link target '",
- this->Target->GetName(), "', is not supported for the '",
- this->LinkLanguage, "' link language."),
- this->Target->GetBacktrace());
- return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
- .first->second;
- }
- cmValue langFeature = this->Makefile->GetDefinition(featureName);
- if (!langFeature) {
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature,
- "', specified through generator-expression '$<LINK_GROUP>' to "
- "link target '",
- this->Target->GetName(), "', is not defined for the '",
- this->LinkLanguage, "' link language."),
- this->Target->GetBacktrace());
- return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
- .first->second;
- }
- auto items = cmExpandListWithBacktrace(
- *langFeature, this->Target->GetBacktrace(), cmList::EmptyElements::Yes);
- // replace LINKER: pattern
- this->Target->ResolveLinkerWrapper(items, this->LinkLanguage, true);
- if (items.size() == 2) {
- return this->GroupFeatureDescriptors
- .emplace(
- feature,
- GroupFeatureDescriptor{ feature, items[0].Value, items[1].Value })
- .first->second;
- }
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Feature '", feature, "', specified by variable '", featureName,
- "', is malformed (wrong number of elements) and cannot be used "
- "to link target '",
- this->Target->GetName(), "'."),
- this->Target->GetBacktrace());
- return this->GroupFeatureDescriptors.emplace(feature, FeatureDescriptor{})
- .first->second;
- }
- void cmComputeLinkInformation::AddExternalObjectTargets()
- {
- std::vector<cmSourceFile const*> externalObjects;
- this->Target->GetExternalObjects(externalObjects, this->Config);
- std::set<std::string> emitted;
- for (auto const* externalObject : externalObjects) {
- std::string const& objLib = externalObject->GetObjectLibrary();
- if (objLib.empty()) {
- continue;
- }
- if (emitted.insert(objLib).second) {
- cmLinkItem const& objItem =
- this->Target->ResolveLinkItem(BT<std::string>(objLib));
- if (objItem.Target) {
- this->ExternalObjectTargets.emplace_back(objItem.Target);
- }
- }
- }
- }
- void cmComputeLinkInformation::AddImplicitLinkInfo()
- {
- // The link closure lists all languages whose implicit info is needed.
- cmGeneratorTarget::LinkClosure const* lc =
- this->Target->GetLinkClosure(this->Config);
- for (std::string const& li : lc->Languages) {
- if (li == "CUDA" || li == "HIP") {
- // These need to go before the other implicit link information
- // as they could require symbols from those other library
- // Currently restricted as CUDA and HIP are the only languages
- // we have documented runtime behavior controls for
- this->AddRuntimeLinkLibrary(li);
- }
- // Skip those of the linker language. They are implicit.
- if (li != this->LinkLanguage) {
- this->AddImplicitLinkInfo(li);
- }
- }
- }
- void cmComputeLinkInformation::AddRuntimeLinkLibrary(std::string const& lang)
- {
- std::string const& runtimeLibrary =
- this->Target->GetRuntimeLinkLibrary(lang, this->Config);
- if (runtimeLibrary.empty()) {
- return;
- }
- if (cmValue runtimeLinkOptions = this->Makefile->GetDefinition(cmStrCat(
- "CMAKE_", lang, "_RUNTIME_LIBRARY_LINK_OPTIONS_", runtimeLibrary))) {
- cmList libs{ *runtimeLinkOptions };
- for (auto const& i : libs) {
- if (!cm::contains(this->ImplicitLinkLibs, i)) {
- this->AddItem({ i });
- }
- }
- }
- }
- void cmComputeLinkInformation::AddImplicitLinkInfo(std::string const& lang)
- {
- // Add libraries for this language that are not implied by the
- // linker language.
- std::string libVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_LIBRARIES");
- if (cmValue libs = this->Makefile->GetDefinition(libVar)) {
- cmList libsList{ *libs };
- for (auto const& i : libsList) {
- if (!cm::contains(this->ImplicitLinkLibs, i)) {
- this->AddItem({ i });
- }
- }
- }
- // Add linker search paths for this language that are not
- // implied by the linker language.
- std::string dirVar = cmStrCat("CMAKE_", lang, "_IMPLICIT_LINK_DIRECTORIES");
- if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
- cmList dirsList{ *dirs };
- this->OrderLinkerSearchPath->AddLanguageDirectories(dirsList);
- }
- }
- void cmComputeLinkInformation::AddItem(LinkEntry const& entry)
- {
- cmGeneratorTarget const* tgt = entry.Target;
- BT<std::string> const& item = entry.Item;
- // Compute the proper name to use to link this library.
- const std::string& config = this->Config;
- bool impexe = (tgt && tgt->IsExecutableWithExports());
- if (impexe && !tgt->HasImportLibrary(config) && !this->LoaderFlag) {
- // Skip linking to executables on platforms with no import
- // libraries or loader flags.
- return;
- }
- if (tgt && tgt->IsLinkable()) {
- // This is a CMake target. Ask the target for its real name.
- if (impexe && this->LoaderFlag) {
- // 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 using a special feature.
- cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
- ? cmStateEnums::ImportLibraryArtifact
- : cmStateEnums::RuntimeBinaryArtifact;
- std::string exe = tgt->GetFullPath(config, artifact, true);
- this->Items.emplace_back(
- BT<std::string>(exe, item.Backtrace), ItemIsPath::Yes, tgt, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "__CMAKE_LINK_EXECUTABLE"
- : entry.Feature));
- this->Depends.push_back(std::move(exe));
- } else if (tgt->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
- // 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.
- this->Items.emplace_back(std::string(), ItemIsPath::No, tgt);
- // Also add the item the interface specifies to be used in its place.
- std::string const& libName = tgt->GetImportedLibName(config);
- if (!libName.empty()) {
- this->AddItem(BT<std::string>(libName, item.Backtrace));
- }
- } else if (tgt->GetType() == cmStateEnums::OBJECT_LIBRARY) {
- this->Items.emplace_back(item, ItemIsPath::No, tgt);
- } else if (this->GlobalGenerator->IsXcode() &&
- !tgt->GetImportedXcFrameworkPath(config).empty()) {
- this->Items.emplace_back(
- tgt->GetImportedXcFrameworkPath(config), ItemIsPath::Yes, tgt, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "__CMAKE_LINK_XCFRAMEWORK"
- : entry.Feature));
- } else {
- // Decide whether to use an import library.
- cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(config)
- ? cmStateEnums::ImportLibraryArtifact
- : cmStateEnums::RuntimeBinaryArtifact;
- // Pass the full path to the target file.
- BT<std::string> lib = BT<std::string>(
- tgt->GetFullPath(config, artifact, true), item.Backtrace);
- if (tgt->IsAIX() && cmHasLiteralSuffix(lib.Value, "-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;
- }
- if (!this->LinkDependsNoShared ||
- tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
- this->Depends.push_back(lib.Value);
- }
- LinkEntry libEntry{ entry };
- libEntry.Item = lib;
- this->AddTargetItem(libEntry);
- if (tgt->IsApple() && tgt->HasImportLibrary(config)) {
- // Use the library rather than the tbd file for runpath computation
- this->AddLibraryRuntimeInfo(
- tgt->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact, true),
- tgt);
- } else {
- this->AddLibraryRuntimeInfo(lib.Value, tgt);
- }
- if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
- this->Target->IsDLLPlatform()) {
- this->AddRuntimeDLL(tgt);
- }
- }
- auto xcFrameworkPath = tgt->GetImportedXcFrameworkPath(config);
- if (!xcFrameworkPath.empty()) {
- auto plist = cmParseXcFrameworkPlist(xcFrameworkPath, *this->Makefile,
- item.Backtrace);
- if (!plist) {
- return;
- }
- if (auto const* library =
- plist->SelectSuitableLibrary(*this->Makefile, item.Backtrace)) {
- if (!library->HeadersPath.empty()) {
- this->AddXcFrameworkHeaderPath(cmStrCat(xcFrameworkPath, '/',
- library->LibraryIdentifier,
- '/', library->HeadersPath));
- }
- } else {
- return;
- }
- }
- } else {
- // This is not a CMake target. Use the name given.
- if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s) ||
- (entry.Feature == DEFAULT &&
- cmSystemTools::IsPathToFramework(item.Value) &&
- this->Target->IsApple())) {
- // This is a framework.
- this->AddFrameworkItem(entry);
- } else if (cmHasSuffix(entry.Feature, "XCFRAMEWORK"_s) ||
- (entry.Feature == DEFAULT &&
- cmSystemTools::IsPathToXcFramework(item.Value) &&
- this->Target->IsApple())) {
- // This is a framework.
- this->AddXcFrameworkItem(entry);
- } else if (cmSystemTools::FileIsFullPath(item.Value)) {
- if (cmSystemTools::FileIsDirectory(item.Value)) {
- // This is a directory.
- this->DropDirectoryItem(item);
- } else {
- // Use the full path given to the library file.
- this->Depends.push_back(item.Value);
- this->AddFullItem(entry);
- this->AddLibraryRuntimeInfo(item.Value);
- }
- } else if (entry.Kind != cmComputeLinkDepends::LinkEntry::Object) {
- // This is a library or option specified by the user.
- this->AddUserItem(entry);
- }
- }
- }
- void cmComputeLinkInformation::AddSharedDepItem(LinkEntry const& entry)
- {
- BT<std::string> const& item = entry.Item;
- const cmGeneratorTarget* tgt = entry.Target;
- // Record dependencies on DLLs.
- if (tgt && tgt->GetType() == cmStateEnums::SHARED_LIBRARY &&
- this->Target->IsDLLPlatform() &&
- this->SharedDependencyMode != SharedDepModeLink) {
- this->AddRuntimeDLL(tgt);
- }
- // If dropping shared library dependencies, ignore them.
- if (this->SharedDependencyMode == SharedDepModeNone) {
- return;
- }
- // The user may have incorrectly named an item. Skip items that are
- // not full paths to shared libraries.
- if (tgt) {
- // The target will provide a full path. Make sure it is a shared
- // library.
- if (tgt->GetType() != cmStateEnums::SHARED_LIBRARY) {
- return;
- }
- } else {
- // Skip items that are not full paths. We will not be able to
- // reliably specify them.
- if (!cmSystemTools::FileIsFullPath(item.Value)) {
- return;
- }
- // Get the name of the library from the file name.
- std::string file = cmSystemTools::GetFilenameName(item.Value);
- if (!this->ExtractSharedLibraryName.find(file)) {
- // This is not the name of a shared library.
- return;
- }
- }
- // If in linking mode, just link to the shared library.
- if (this->SharedDependencyMode == SharedDepModeLink ||
- // For an imported shared library without a known runtime artifact,
- // such as a CUDA stub, a library file named with the real soname
- // may not be available at all, so '-rpath-link' cannot help linkers
- // find it to satisfy '--no-allow-shlib-undefined' recursively.
- // Pass this dependency to the linker explicitly just in case.
- // If the linker also uses '--as-needed' behavior, this will not
- // add an unnecessary direct dependency.
- (tgt && tgt->IsImported() &&
- !tgt->HasKnownRuntimeArtifactLocation(this->Config) &&
- this->Target->LinkerEnforcesNoAllowShLibUndefined(this->Config))) {
- this->AddItem(entry);
- return;
- }
- // 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;
- if (tgt) {
- cmStateEnums::ArtifactType artifact = tgt->HasImportLibrary(this->Config)
- ? cmStateEnums::ImportLibraryArtifact
- : cmStateEnums::RuntimeBinaryArtifact;
- lib = tgt->GetFullPath(this->Config, artifact);
- if (tgt->IsApple() && tgt->HasImportLibrary(this->Config)) {
- // Use the library rather than the tbd file for runpath computation
- this->AddLibraryRuntimeInfo(
- tgt->GetFullPath(this->Config, cmStateEnums::RuntimeBinaryArtifact,
- true),
- tgt);
- } else {
- this->AddLibraryRuntimeInfo(lib, tgt);
- }
- } else {
- lib = item.Value;
- this->AddLibraryRuntimeInfo(lib);
- }
- // Check if we need to include the dependent shared library in other
- // path ordering.
- cmOrderDirectories* order = nullptr;
- if (this->SharedDependencyMode == SharedDepModeLibDir &&
- !this->LinkWithRuntimePath /* AddLibraryRuntimeInfo adds it */) {
- // Add the item to the linker search path.
- order = this->OrderLinkerSearchPath.get();
- } else if (this->SharedDependencyMode == SharedDepModeDir) {
- // Add the item to the separate dependent library search path.
- order = this->OrderDependentRPath.get();
- }
- if (order) {
- if (tgt) {
- std::string soName = tgt->GetSOName(this->Config);
- const char* soname = soName.empty() ? nullptr : soName.c_str();
- order->AddRuntimeLibrary(lib, soname);
- } else {
- order->AddRuntimeLibrary(lib);
- }
- }
- }
- void cmComputeLinkInformation::AddRuntimeDLL(cmGeneratorTarget const* tgt)
- {
- if (std::find(this->RuntimeDLLs.begin(), this->RuntimeDLLs.end(), tgt) ==
- this->RuntimeDLLs.end()) {
- this->RuntimeDLLs.emplace_back(tgt);
- }
- }
- void cmComputeLinkInformation::ComputeLinkTypeInfo()
- {
- // Check whether archives may actually be shared libraries.
- this->ArchivesMayBeShared =
- this->CMakeInstance->GetState()->GetGlobalPropertyAsBool(
- "TARGET_ARCHIVES_MAY_BE_SHARED_LIBS");
- // First assume we cannot do link type stuff.
- this->LinkTypeEnabled = false;
- // Lookup link type selection flags.
- cmValue static_link_type_flag = nullptr;
- cmValue shared_link_type_flag = nullptr;
- const char* target_type_str = nullptr;
- switch (this->Target->GetType()) {
- case cmStateEnums::EXECUTABLE:
- target_type_str = "EXE";
- break;
- case cmStateEnums::SHARED_LIBRARY:
- target_type_str = "SHARED_LIBRARY";
- break;
- case cmStateEnums::MODULE_LIBRARY:
- target_type_str = "SHARED_MODULE";
- break;
- default:
- break;
- }
- if (target_type_str) {
- std::string static_link_type_flag_var =
- cmStrCat("CMAKE_", target_type_str, "_LINK_STATIC_", this->LinkLanguage,
- "_FLAGS");
- static_link_type_flag =
- this->Makefile->GetDefinition(static_link_type_flag_var);
- std::string shared_link_type_flag_var =
- cmStrCat("CMAKE_", target_type_str, "_LINK_DYNAMIC_", this->LinkLanguage,
- "_FLAGS");
- shared_link_type_flag =
- this->Makefile->GetDefinition(shared_link_type_flag_var);
- }
- // We can support link type switching only if all needed flags are
- // known.
- if (cmNonempty(static_link_type_flag) && cmNonempty(shared_link_type_flag)) {
- this->LinkTypeEnabled = true;
- this->StaticLinkTypeFlag = *static_link_type_flag;
- this->SharedLinkTypeFlag = *shared_link_type_flag;
- }
- // Lookup the starting link type from the target (linked statically?).
- cmValue lss = this->Target->GetProperty("LINK_SEARCH_START_STATIC");
- this->StartLinkType = lss.IsOn() ? LinkStatic : LinkShared;
- this->CurrentLinkType = this->StartLinkType;
- }
- void cmComputeLinkInformation::ComputeItemParserInfo()
- {
- // Get possible library name prefixes.
- cmMakefile* mf = this->Makefile;
- this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_PREFIX"));
- this->AddLinkPrefix(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_PREFIX"));
- // Import library names should be matched and treated as shared
- // libraries for the purposes of linking.
- this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"),
- LinkShared);
- this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"),
- LinkStatic);
- this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"),
- LinkShared);
- this->AddLinkExtension(mf->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"),
- LinkUnknown);
- if (cmValue linkSuffixes =
- mf->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) {
- cmList linkSuffixList{ *linkSuffixes };
- for (auto const& i : linkSuffixList) {
- this->AddLinkExtension(i, LinkUnknown);
- }
- }
- if (cmValue sharedSuffixes =
- mf->GetDefinition("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")) {
- cmList sharedSuffixList{ *sharedSuffixes };
- for (std::string const& i : sharedSuffixList) {
- this->AddLinkExtension(i, LinkShared);
- }
- }
- // Compute a regex to match link extensions.
- std::string libext =
- this->CreateExtensionRegex(this->LinkExtensions, LinkUnknown);
- // Create regex to remove any library extension.
- std::string reg("(.*)");
- reg += libext;
- this->OrderLinkerSearchPath->SetLinkExtensionInfo(this->LinkExtensions, reg);
- // 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 = "^(";
- for (std::string const& p : this->LinkPrefixes) {
- reg += p;
- reg += '|';
- }
- reg += ")([^/:]*)";
- // Create a regex to match any library name.
- std::string reg_any = cmStrCat(reg, libext);
- #ifdef CM_COMPUTE_LINK_INFO_DEBUG
- fprintf(stderr, "any regex [%s]\n", reg_any.c_str());
- #endif
- this->ExtractAnyLibraryName.compile(reg_any);
- // Create a regex to match static library names.
- if (!this->StaticLinkExtensions.empty()) {
- std::string reg_static = cmStrCat(
- reg, this->CreateExtensionRegex(this->StaticLinkExtensions, LinkStatic));
- #ifdef CM_COMPUTE_LINK_INFO_DEBUG
- fprintf(stderr, "static regex [%s]\n", reg_static.c_str());
- #endif
- this->ExtractStaticLibraryName.compile(reg_static);
- }
- // Create a regex to match shared library names.
- if (!this->SharedLinkExtensions.empty()) {
- std::string reg_shared = reg;
- this->SharedRegexString =
- this->CreateExtensionRegex(this->SharedLinkExtensions, LinkShared);
- reg_shared += this->SharedRegexString;
- #ifdef CM_COMPUTE_LINK_INFO_DEBUG
- fprintf(stderr, "shared regex [%s]\n", reg_shared.c_str());
- #endif
- this->ExtractSharedLibraryName.compile(reg_shared);
- }
- }
- void cmComputeLinkInformation::AddLinkPrefix(std::string const& p)
- {
- if (!p.empty()) {
- this->LinkPrefixes.insert(p);
- }
- }
- void cmComputeLinkInformation::AddLinkExtension(std::string const& e,
- LinkType type)
- {
- if (!e.empty()) {
- if (type == LinkStatic) {
- this->StaticLinkExtensions.emplace_back(e);
- }
- if (type == LinkShared) {
- this->SharedLinkExtensions.emplace_back(e);
- }
- this->LinkExtensions.emplace_back(e);
- }
- }
- // XXX(clang-tidy): This method's const-ness is platform dependent, so we
- // cannot make it `const` as `clang-tidy` wants us to.
- // NOLINTNEXTLINE(readability-make-member-function-const)
- std::string cmComputeLinkInformation::CreateExtensionRegex(
- std::vector<std::string> const& exts, LinkType type)
- {
- // Build a list of extension choices.
- std::string libext = "(";
- const char* sep = "";
- for (std::string const& i : exts) {
- // Separate this choice from the previous one.
- libext += sep;
- sep = "|";
- // Store this extension choice with the "." escaped.
- libext += "\\";
- #if defined(_WIN32) && !defined(__CYGWIN__)
- libext += this->NoCaseExpression(i);
- #else
- libext += i;
- #endif
- }
- // Finish the list.
- libext += ')';
- // Add an optional OpenBSD-style version or major.minor.version component.
- if (this->IsOpenBSD || type == LinkShared) {
- libext += "(\\.[0-9]+)*";
- }
- libext += '$';
- return libext;
- }
- std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
- {
- std::string ret;
- ret.reserve(str.size() * 4);
- for (char c : str) {
- if (c == '.') {
- ret += c;
- } else {
- ret += '[';
- ret += static_cast<char>(tolower(c));
- ret += static_cast<char>(toupper(c));
- ret += ']';
- }
- }
- return ret;
- }
- void cmComputeLinkInformation::SetCurrentLinkType(LinkType lt)
- {
- // If we are changing the current link type add the flag to tell the
- // linker about it.
- if (this->CurrentLinkType != lt) {
- this->CurrentLinkType = lt;
- if (this->LinkTypeEnabled) {
- switch (this->CurrentLinkType) {
- case LinkStatic:
- this->Items.emplace_back(this->StaticLinkTypeFlag, ItemIsPath::No);
- break;
- case LinkShared:
- this->Items.emplace_back(this->SharedLinkTypeFlag, ItemIsPath::No);
- break;
- default:
- break;
- }
- }
- }
- }
- void cmComputeLinkInformation::AddTargetItem(LinkEntry const& entry)
- {
- // 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.
- BT<std::string> const& item = entry.Item;
- cmGeneratorTarget const* target = entry.Target;
- if (target->GetType() != cmStateEnums::STATIC_LIBRARY) {
- this->SetCurrentLinkType(LinkShared);
- }
- // Keep track of shared library targets linked.
- if (target->GetType() == cmStateEnums::SHARED_LIBRARY) {
- this->SharedLibrariesLinked.insert(target);
- }
- // Handle case of an imported shared library with no soname.
- if (this->NoSONameUsesPath &&
- target->IsImportedSharedLibWithoutSOName(this->Config)) {
- this->AddSharedLibNoSOName(entry);
- return;
- }
- const bool isImportedFrameworkFolderOnApple =
- target->IsImportedFrameworkFolderOnApple(this->Config);
- if (target->IsFrameworkOnApple() || isImportedFrameworkFolderOnApple) {
- // Add the framework directory and the framework item itself
- auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
- item.Value, cmGlobalGenerator::FrameworkFormat::Extended);
- if (!fwDescriptor) {
- this->CMakeInstance->IssueMessage(
- MessageType::FATAL_ERROR,
- cmStrCat("Could not parse framework path \"", item.Value,
- "\" linked by target ", this->Target->GetName(), '.'),
- item.Backtrace);
- return;
- }
- if (!fwDescriptor->Directory.empty()) {
- // Add the directory portion to the framework search path.
- this->AddFrameworkPath(fwDescriptor->Directory);
- }
- if (this->GlobalGenerator->IsXcode()) {
- if (isImportedFrameworkFolderOnApple) {
- if (entry.Feature == DEFAULT) {
- this->AddLibraryFeature("FRAMEWORK");
- this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr,
- this->FindLibraryFeature("FRAMEWORK"));
- } else {
- this->Items.emplace_back(item, ItemIsPath::Yes, target, nullptr,
- this->FindLibraryFeature(entry.Feature));
- }
- } else {
- this->Items.emplace_back(
- item, ItemIsPath::Yes, target, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "__CMAKE_LINK_FRAMEWORK"
- : entry.Feature));
- }
- } else {
- if (cmHasSuffix(entry.Feature, "FRAMEWORK"_s)) {
- this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
- target, nullptr,
- this->FindLibraryFeature(entry.Feature));
- } else if (entry.Feature == DEFAULT &&
- isImportedFrameworkFolderOnApple) {
- this->AddLibraryFeature("FRAMEWORK");
- this->Items.emplace_back(fwDescriptor->GetLinkName(), ItemIsPath::Yes,
- target, nullptr,
- this->FindLibraryFeature("FRAMEWORK"));
- } else {
- this->Items.emplace_back(
- item, ItemIsPath::Yes, target, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "__CMAKE_LINK_LIBRARY"
- : entry.Feature));
- }
- }
- } else {
- // Now add the full path to the library.
- this->Items.emplace_back(
- item, ItemIsPath::Yes, target, nullptr,
- this->FindLibraryFeature(
- entry.Feature == DEFAULT ? "__CMAKE_LINK_LIBRARY" : entry.Feature));
- }
- }
- void cmComputeLinkInformation::AddFullItem(LinkEntry const& entry)
- {
- BT<std::string> const& item = entry.Item;
- // Check for the implicit link directory special case.
- if (this->CheckImplicitDirItem(entry)) {
- return;
- }
- // Check for case of shared library with no builtin soname.
- if (this->NoSONameUsesPath && this->CheckSharedLibNoSOName(entry)) {
- return;
- }
- // This is called to handle a link item that is a full path.
- // 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.
- if (this->LinkTypeEnabled) {
- std::string name = cmSystemTools::GetFilenameName(item.Value);
- if (this->ExtractSharedLibraryName.find(name)) {
- this->SetCurrentLinkType(LinkShared);
- } else if (!this->ExtractStaticLibraryName.find(item.Value)) {
- // We cannot determine the type. Assume it is the target's
- // default type.
- this->SetCurrentLinkType(this->StartLinkType);
- }
- }
- // Now add the full path to the library.
- this->Items.emplace_back(
- item, ItemIsPath::Yes, nullptr, entry.ObjectSource,
- this->FindLibraryFeature(
- entry.Feature == DEFAULT
- ? (entry.Kind == cmComputeLinkDepends::LinkEntry::Object
- ? "__CMAKE_LINK_OBJECT"
- : "__CMAKE_LINK_LIBRARY")
- : entry.Feature));
- }
- bool cmComputeLinkInformation::CheckImplicitDirItem(LinkEntry const& entry)
- {
- BT<std::string> const& item = entry.Item;
- // We only switch to a pathless item if the link type may be
- // enforced. Fortunately only platforms that support link types
- // seem to have magic per-architecture implicit link directories.
- if (!this->LinkTypeEnabled) {
- return false;
- }
- // Check if this item is in an implicit link directory.
- std::string dir = cmSystemTools::GetFilenamePath(item.Value);
- if (!cm::contains(this->ImplicitLinkDirs, dir)) {
- // Only libraries in implicit link directories are converted to
- // pathless items.
- return false;
- }
- // Only apply the policy below if the library file is one that can
- // be found by the linker.
- std::string file = cmSystemTools::GetFilenameName(item.Value);
- if (!this->ExtractAnyLibraryName.find(file)) {
- return false;
- }
- return false;
- }
- void cmComputeLinkInformation::AddUserItem(LinkEntry const& entry)
- {
- // This is called to handle a link item that does not match a CMake
- // target and is not a full path. We check here if it looks like a
- // library file name to automatically request the proper link type
- // from the linker. For example:
- //
- // foo ==> -lfoo
- // libfoo.a ==> -Wl,-Bstatic -lfoo
- const cm::string_view LINKER{ "LINKER:" };
- BT<std::string> const& item = entry.Item;
- if (item.Value[0] == '-' || item.Value[0] == '$' || item.Value[0] == '`') {
- // Pass flags through untouched.
- // Restore the target link type since this item does not specify
- // one.
- this->SetCurrentLinkType(this->StartLinkType);
- // Use the item verbatim.
- this->Items.emplace_back(item, ItemIsPath::No);
- return;
- }
- if (cmHasPrefix(item.Value, LINKER)) {
- std::vector<BT<std::string>> linkerFlag{ 1, item };
- this->Target->ResolveLinkerWrapper(linkerFlag, this->GetLinkLanguage(),
- /* joinItems = */ true);
- if (!linkerFlag.empty()) {
- this->Items.emplace_back(linkerFlag.front(), ItemIsPath::No);
- }
- return;
- }
- // Parse out the prefix, base, and suffix components of the
- // library name. If the name matches that of a shared or static
- // library then set the link type accordingly.
- //
- // Search for shared library names first because some platforms
- // have shared libraries with names that match the static library
- // pattern. For example cygwin and msys use the convention
- // libfoo.dll.a for import libraries and libfoo.a for static
- // libraries. On AIX a library with the name libfoo.a can be
- // shared!
- std::string lib;
- if (this->ExtractSharedLibraryName.find(item.Value)) {
- // This matches a shared library file name.
- #ifdef CM_COMPUTE_LINK_INFO_DEBUG
- fprintf(stderr, "shared regex matched [%s] [%s] [%s]\n",
- this->ExtractSharedLibraryName.match(1).c_str(),
- this->ExtractSharedLibraryName.match(2).c_str(),
- this->ExtractSharedLibraryName.match(3).c_str());
- #endif
- // Set the link type to shared.
- this->SetCurrentLinkType(LinkShared);
- // Use just the library name so the linker will search.
- lib = this->ExtractSharedLibraryName.match(2);
- } else if (this->ExtractStaticLibraryName.find(item.Value)) {
- // This matches a static library file name.
- #ifdef CM_COMPUTE_LINK_INFO_DEBUG
- fprintf(stderr, "static regex matched [%s] [%s] [%s]\n",
- this->ExtractStaticLibraryName.match(1).c_str(),
- this->ExtractStaticLibraryName.match(2).c_str(),
- this->ExtractStaticLibraryName.match(3).c_str());
- #endif
- // Set the link type to static.
- this->SetCurrentLinkType(LinkStatic);
- // Use just the library name so the linker will search.
- lib = this->ExtractStaticLibraryName.match(2);
- } else if (this->ExtractAnyLibraryName.find(item.Value)) {
- // This matches a library file name.
- #ifdef CM_COMPUTE_LINK_INFO_DEBUG
- fprintf(stderr, "any regex matched [%s] [%s] [%s]\n",
- this->ExtractAnyLibraryName.match(1).c_str(),
- this->ExtractAnyLibraryName.match(2).c_str(),
- this->ExtractAnyLibraryName.match(3).c_str());
- #endif
- // Restore the target link type since this item does not specify
- // one.
- this->SetCurrentLinkType(this->StartLinkType);
- // Use just the library name so the linker will search.
- lib = this->ExtractAnyLibraryName.match(2);
- } else {
- // We must ask the linker to search for a library with this name.
- // Restore the target link type since this item does not specify
- // one.
- this->SetCurrentLinkType(this->StartLinkType);
- lib = item.Value;
- }
- // Create an option to ask the linker to search for the library.
- auto out = cmStrCat(this->LibLinkFlag, lib, this->LibLinkSuffix);
- if (entry.Feature != DEFAULT) {
- auto const& feature = this->GetLibraryFeature(entry.Feature);
- this->Items.emplace_back(
- BT<std::string>(
- feature.GetDecoratedItem(cmStrCat(lib, this->LibLinkSuffix),
- item.Value, out, ItemIsPath::No),
- item.Backtrace),
- ItemIsPath::No);
- } else {
- this->Items.emplace_back(BT<std::string>(out, item.Backtrace),
- ItemIsPath::No);
- }
- // Here we could try to find the library the linker will find and
- // add a runtime information entry for it. It would probably not be
- // reliable and we want to encourage use of full paths for library
- // specification.
- }
- void cmComputeLinkInformation::AddFrameworkItem(LinkEntry const& entry)
- {
- std::string const& item = entry.Item.Value;
- // Try to separate the framework name and path.
- auto fwDescriptor = this->GlobalGenerator->SplitFrameworkPath(
- item,
- entry.Feature == DEFAULT ? cmGlobalGenerator::FrameworkFormat::Relaxed
- : cmGlobalGenerator::FrameworkFormat::Extended);
- if (!fwDescriptor) {
- std::ostringstream e;
- e << "Could not parse framework path \"" << item << "\" linked by target "
- << this->Target->GetName() << '.';
- cmSystemTools::Error(e.str());
- return;
- }
- const std::string& fw_path = fwDescriptor->Directory;
- if (!fw_path.empty()) {
- // Add the directory portion to the framework search path.
- this->AddFrameworkPath(fw_path);
- }
- // add runtime information
- this->AddLibraryRuntimeInfo(fwDescriptor->GetFullPath());
- if (entry.Feature == DEFAULT) {
- // ensure FRAMEWORK feature is loaded
- this->AddLibraryFeature("FRAMEWORK");
- }
- if (this->GlobalGenerator->IsXcode()) {
- // Add framework path - it will be handled by Xcode after it's added to
- // "Link Binary With Libraries" build phase
- this->Items.emplace_back(item, ItemIsPath::Yes, nullptr, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "FRAMEWORK"
- : entry.Feature));
- } else {
- this->Items.emplace_back(
- fwDescriptor->GetLinkName(), ItemIsPath::Yes, nullptr, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT ? "FRAMEWORK"
- : entry.Feature));
- }
- }
- void cmComputeLinkInformation::AddXcFrameworkItem(LinkEntry const& entry)
- {
- auto plist = cmParseXcFrameworkPlist(entry.Item.Value, *this->Makefile,
- entry.Item.Backtrace);
- if (!plist) {
- return;
- }
- if (auto const* lib =
- plist->SelectSuitableLibrary(*this->Makefile, entry.Item.Backtrace)) {
- if (this->GlobalGenerator->IsXcode()) {
- this->Items.emplace_back(
- entry.Item.Value, ItemIsPath::Yes, nullptr, nullptr,
- this->FindLibraryFeature(entry.Feature == DEFAULT
- ? "__CMAKE_LINK_XCFRAMEWORK"
- : entry.Feature));
- } else {
- auto libraryPath = cmStrCat(
- entry.Item.Value, '/', lib->LibraryIdentifier, '/', lib->LibraryPath);
- LinkEntry libraryEntry(
- BT<std::string>(libraryPath, entry.Item.Backtrace), entry.Target);
- if (cmSystemTools::IsPathToFramework(libraryPath) &&
- this->Target->IsApple()) {
- // This is a framework.
- this->AddFrameworkItem(libraryEntry);
- } else {
- this->Depends.push_back(libraryPath);
- this->AddFullItem(libraryEntry);
- this->AddLibraryRuntimeInfo(libraryPath);
- if (!lib->HeadersPath.empty()) {
- this->AddXcFrameworkHeaderPath(cmStrCat(entry.Item.Value, '/',
- lib->LibraryIdentifier, '/',
- lib->HeadersPath));
- }
- }
- }
- }
- }
- void cmComputeLinkInformation::DropDirectoryItem(BT<std::string> const& item)
- {
- // A full path to a directory was found as a link item. Warn the
- // user.
- this->CMakeInstance->IssueMessage(
- MessageType::WARNING,
- cmStrCat("Target \"", this->Target->GetName(),
- "\" requests linking to directory \"", item.Value,
- "\". Targets may link only to libraries. CMake is dropping "
- "the item."),
- item.Backtrace);
- }
- void cmComputeLinkInformation::ComputeFrameworkInfo()
- {
- // Avoid adding implicit framework paths.
- cmList implicitDirs;
- // Get platform-wide implicit directories.
- implicitDirs.assign(this->Makefile->GetDefinition(
- "CMAKE_PLATFORM_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES"));
- // Get language-specific implicit directories.
- std::string implicitDirVar = cmStrCat(
- "CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES");
- implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar));
- this->FrameworkPathsEmitted.insert(implicitDirs.begin(), implicitDirs.end());
- }
- void cmComputeLinkInformation::AddFrameworkPath(std::string const& p)
- {
- if (this->FrameworkPathsEmitted.insert(p).second) {
- this->FrameworkPaths.push_back(p);
- }
- }
- void cmComputeLinkInformation::AddXcFrameworkHeaderPath(std::string const& p)
- {
- this->XcFrameworkHeaderPaths.push_back(p);
- }
- bool cmComputeLinkInformation::CheckSharedLibNoSOName(LinkEntry const& entry)
- {
- // This platform will use the path to a library as its soname if the
- // library is given via path and was not built with an soname. If
- // this is a shared library that might be the case.
- std::string file = cmSystemTools::GetFilenameName(entry.Item.Value);
- if (this->ExtractSharedLibraryName.find(file)) {
- // If we can guess the soname fairly reliably then assume the
- // library has one. Otherwise assume the library has no builtin
- // soname.
- std::string soname;
- if (!cmSystemTools::GuessLibrarySOName(entry.Item.Value, soname)) {
- this->AddSharedLibNoSOName(entry);
- return true;
- }
- }
- return false;
- }
- void cmComputeLinkInformation::AddSharedLibNoSOName(LinkEntry const& entry)
- {
- // We have a full path to a shared library with no soname. We need
- // to ask the linker to locate the item because otherwise the path
- // we give to it will be embedded in the target linked. Then at
- // runtime the dynamic linker will search for the library using the
- // path instead of just the name.
- LinkEntry fileEntry{ entry };
- fileEntry.Item = cmSystemTools::GetFilenameName(entry.Item.Value);
- this->AddUserItem(fileEntry);
- // Make sure the link directory ordering will find the library.
- this->OrderLinkerSearchPath->AddLinkLibrary(entry.Item.Value);
- }
- void cmComputeLinkInformation::LoadImplicitLinkInfo()
- {
- // Get platform-wide implicit directories.
- cmList implicitDirs{ this->Makefile->GetDefinition(
- "CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES") };
- // Append library architecture to all implicit platform directories
- // and add them to the set
- if (cmValue libraryArch =
- this->Makefile->GetDefinition("CMAKE_LIBRARY_ARCHITECTURE")) {
- for (auto const& i : implicitDirs) {
- this->ImplicitLinkDirs.insert(cmStrCat(i, '/', *libraryArch));
- }
- }
- // Get language-specific implicit directories.
- std::string implicitDirVar =
- cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_DIRECTORIES");
- implicitDirs.append(this->Makefile->GetDefinition(implicitDirVar));
- // Store implicit link directories.
- this->ImplicitLinkDirs.insert(implicitDirs.begin(), implicitDirs.end());
- // Get language-specific implicit libraries.
- std::string implicitLibVar =
- cmStrCat("CMAKE_", this->LinkLanguage, "_IMPLICIT_LINK_LIBRARIES");
- cmList implicitLibs{ this->Makefile->GetDefinition(implicitLibVar) };
- // Store implicit link libraries.
- for (auto const& item : implicitLibs) {
- // Items starting in '-' but not '-l' are flags, not libraries,
- // and should not be filtered by this implicit list.
- if (item[0] != '-' || item[1] == 'l') {
- this->ImplicitLinkLibs.insert(item);
- }
- }
- // Get platform specific rpath link directories
- cmList::append(this->RuntimeLinkDirs,
- this->Makefile->GetDefinition("CMAKE_PLATFORM_RUNTIME_PATH"));
- }
- std::vector<std::string> const&
- cmComputeLinkInformation::GetRuntimeSearchPath() const
- {
- return this->OrderRuntimeSearchPath->GetOrderedDirectories();
- }
- void cmComputeLinkInformation::AddLibraryRuntimeInfo(
- std::string const& fullPath, cmGeneratorTarget const* target)
- {
- // Ignore targets on Apple where install_name is not @rpath.
- // The dependenty library can be found with other means such as
- // @loader_path or full paths.
- if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
- if (!target->HasMacOSXRpathInstallNameDir(this->Config)) {
- return;
- }
- }
- // Libraries with unknown type must be handled using just the file
- // on disk.
- if (target->GetType() == cmStateEnums::UNKNOWN_LIBRARY) {
- this->AddLibraryRuntimeInfo(fullPath);
- return;
- }
- // Skip targets that are not shared libraries (modules cannot be linked).
- if (target->GetType() != cmStateEnums::SHARED_LIBRARY) {
- return;
- }
- // Skip targets that do not have a known runtime artifact.
- if (!target->HasKnownRuntimeArtifactLocation(this->Config)) {
- return;
- }
- // Try to get the soname of the library. Only files with this name
- // could possibly conflict.
- std::string soName = target->GetSOName(this->Config);
- const char* soname = soName.empty() ? nullptr : soName.c_str();
- // Include this library in the runtime path ordering.
- this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath, soname);
- if (this->LinkWithRuntimePath) {
- this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath, soname);
- }
- }
- void cmComputeLinkInformation::AddLibraryRuntimeInfo(
- std::string const& fullPath)
- {
- // Get the name of the library from the file name.
- bool is_shared_library = false;
- std::string file = cmSystemTools::GetFilenameName(fullPath);
- if (this->Makefile->IsOn("CMAKE_PLATFORM_HAS_INSTALLNAME")) {
- // Check that @rpath is part of the install name.
- // If it isn't, return.
- std::string soname;
- if (!cmSystemTools::GuessLibraryInstallName(fullPath, soname)) {
- return;
- }
- if (soname.find("@rpath") == std::string::npos) {
- return;
- }
- }
- is_shared_library = this->ExtractSharedLibraryName.find(file);
- if (!is_shared_library) {
- // On some platforms (AIX) a shared library may look static.
- if (this->ArchivesMayBeShared) {
- if (this->ExtractStaticLibraryName.find(file)) {
- // This is the name of a shared library or archive.
- is_shared_library = true;
- }
- }
- }
- // It could be an Apple framework
- if (!is_shared_library) {
- is_shared_library =
- this->GlobalGenerator
- ->SplitFrameworkPath(fullPath,
- cmGlobalGenerator::FrameworkFormat::Strict)
- .has_value();
- }
- if (!is_shared_library) {
- return;
- }
- // Include this library in the runtime path ordering.
- this->OrderRuntimeSearchPath->AddRuntimeLibrary(fullPath);
- if (this->LinkWithRuntimePath) {
- this->OrderLinkerSearchPath->AddRuntimeLibrary(fullPath);
- }
- }
- static void cmCLI_ExpandListUnique(std::string const& str,
- std::vector<std::string>& out,
- std::set<std::string>& emitted)
- {
- cmList tmp{ str };
- for (std::string const& i : tmp) {
- if (emitted.insert(i).second) {
- out.push_back(i);
- }
- }
- }
- void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
- bool for_install) const
- {
- // Select whether to generate runtime search directories.
- bool outputRuntime =
- !this->Makefile->IsOn("CMAKE_SKIP_RPATH") && !this->RuntimeFlag.empty();
- // Select whether to generate an rpath for the install tree or the
- // build tree.
- bool linking_for_install =
- (for_install ||
- this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
- bool use_install_rpath =
- (outputRuntime && this->Target->HaveInstallTreeRPATH(this->Config) &&
- linking_for_install);
- bool use_build_rpath =
- (outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
- !linking_for_install);
- bool use_link_rpath = outputRuntime && linking_for_install &&
- !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
- this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
- // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree.
- std::string const& originToken = this->Makefile->GetSafeDefinition(
- "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN");
- std::string targetOutputDir = this->Target->GetDirectory(this->Config);
- bool use_relative_build_rpath =
- this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") &&
- !originToken.empty() && !targetOutputDir.empty();
- // Construct the RPATH.
- std::set<std::string> emitted;
- if (use_install_rpath) {
- std::string install_rpath;
- this->Target->GetInstallRPATH(this->Config, install_rpath);
- cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
- }
- if (use_build_rpath) {
- // Add directories explicitly specified by user
- std::string build_rpath;
- if (this->Target->GetBuildRPATH(this->Config, build_rpath)) {
- // This will not resolve entries to use $ORIGIN, the user is expected
- // to do that if necessary.
- cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
- }
- }
- if (use_build_rpath || use_link_rpath) {
- std::string rootPath;
- if (cmValue sysrootLink =
- this->Makefile->GetDefinition("CMAKE_SYSROOT_LINK")) {
- rootPath = *sysrootLink;
- } else {
- rootPath = this->Makefile->GetSafeDefinition("CMAKE_SYSROOT");
- }
- cmValue stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX");
- std::string const& installPrefix =
- this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
- cmSystemTools::ConvertToUnixSlashes(rootPath);
- std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
- std::string const& topBinaryDir =
- this->CMakeInstance->GetHomeOutputDirectory();
- for (std::string const& ri : rdirs) {
- // Put this directory in the rpath if using build-tree rpath
- // support or if using the link path as an rpath.
- if (use_build_rpath) {
- std::string d = ri;
- if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
- d.erase(0, rootPath.size());
- } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
- d.erase(0, (*stagePath).size());
- d = cmStrCat(installPrefix, '/', d);
- cmSystemTools::ConvertToUnixSlashes(d);
- } else if (use_relative_build_rpath) {
- // If expansion of the $ORIGIN token is supported and permitted per
- // policy, use relative paths in the RPATH.
- if (cmSystemTools::ComparePath(d, topBinaryDir) ||
- cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
- d = cmSystemTools::RelativePath(targetOutputDir, d);
- if (!d.empty()) {
- d = cmStrCat(originToken, "/", d);
- } else {
- d = originToken;
- }
- }
- }
- if (emitted.insert(d).second) {
- runtimeDirs.push_back(std::move(d));
- }
- } else if (use_link_rpath) {
- // Do not add any path inside the source or build tree.
- std::string const& topSourceDir =
- this->CMakeInstance->GetHomeDirectory();
- if (!cmSystemTools::ComparePath(ri, topSourceDir) &&
- !cmSystemTools::ComparePath(ri, topBinaryDir) &&
- !cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
- !cmSystemTools::IsSubDirectory(ri, topBinaryDir)) {
- std::string d = ri;
- if (!rootPath.empty() && cmHasPrefix(d, rootPath)) {
- d.erase(0, rootPath.size());
- } else if (cmNonempty(stagePath) && cmHasPrefix(d, *stagePath)) {
- d.erase(0, (*stagePath).size());
- d = cmStrCat(installPrefix, '/', d);
- cmSystemTools::ConvertToUnixSlashes(d);
- }
- if (emitted.insert(d).second) {
- runtimeDirs.push_back(std::move(d));
- }
- }
- }
- }
- }
- // Add runtime paths required by the languages to always be
- // present. This is done even when skipping rpath support.
- {
- cmGeneratorTarget::LinkClosure const* lc =
- this->Target->GetLinkClosure(this->Config);
- for (std::string const& li : lc->Languages) {
- std::string useVar = cmStrCat(
- "CMAKE_", li, "_USE_IMPLICIT_LINK_DIRECTORIES_IN_RUNTIME_PATH");
- if (this->Makefile->IsOn(useVar)) {
- std::string dirVar =
- cmStrCat("CMAKE_", li, "_IMPLICIT_LINK_DIRECTORIES");
- if (cmValue dirs = this->Makefile->GetDefinition(dirVar)) {
- cmCLI_ExpandListUnique(*dirs, runtimeDirs, emitted);
- }
- }
- }
- }
- // Add runtime paths required by the platform to always be
- // present. This is done even when skipping rpath support.
- cmCLI_ExpandListUnique(this->RuntimeAlways, runtimeDirs, emitted);
- }
- std::string cmComputeLinkInformation::GetRPathString(bool for_install) const
- {
- // Get the directories to use.
- std::vector<std::string> runtimeDirs;
- this->GetRPath(runtimeDirs, for_install);
- // Concatenate the paths.
- std::string rpath = cmJoin(runtimeDirs, this->GetRuntimeSep());
- // If the rpath will be replaced at install time, prepare space.
- if (!for_install && this->RuntimeUseChrpath) {
- if (!rpath.empty()) {
- // Add one trailing separator so the linker does not reuse the
- // rpath .dynstr entry for a symbol name that happens to match
- // the end of the rpath string.
- rpath += this->GetRuntimeSep();
- }
- // Make sure it is long enough to hold the replacement value.
- std::string::size_type minLength = this->GetChrpathString().length();
- while (rpath.length() < minLength) {
- rpath += this->GetRuntimeSep();
- }
- }
- return rpath;
- }
- std::string cmComputeLinkInformation::GetChrpathString() const
- {
- if (!this->RuntimeUseChrpath) {
- return "";
- }
- return this->GetRPathString(true);
- }
|