diff options
author | Brad King <brad.king@kitware.com> | 2008-01-22 14:13:04 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2008-01-22 14:13:04 (GMT) |
commit | 96fd5909d9dd1ffe740230ce652d574cd01c62d5 (patch) | |
tree | e83b3ce2d5066660256a69cacb6caa7d2d95c416 /Source/cmLocalGenerator.cxx | |
parent | 0df9e6904cd2416336a85d6d7972ce84dcbab417 (diff) | |
download | CMake-96fd5909d9dd1ffe740230ce652d574cd01c62d5.zip CMake-96fd5909d9dd1ffe740230ce652d574cd01c62d5.tar.gz CMake-96fd5909d9dd1ffe740230ce652d574cd01c62d5.tar.bz2 |
ENH: Implement linking with paths to library files instead of -L and -l separation. See bug #3832
- This is purely an implementation improvement. No interface has changed.
- Create cmComputeLinkInformation class
- Move and re-implement logic from:
cmLocalGenerator::ComputeLinkInformation
cmOrderLinkDirectories
- Link libraries to targets with their full path (if it is known)
- Dirs specified with link_directories command still added with -L
- Make link type specific to library names without paths
(name libfoo.a without path becomes -Wl,-Bstatic -lfoo)
- Make directory ordering specific to a runtime path computation feature
(look for conflicting SONAMEs instead of library names)
- Implement proper rpath support on HP-UX and AIX.
Diffstat (limited to 'Source/cmLocalGenerator.cxx')
-rw-r--r-- | Source/cmLocalGenerator.cxx | 478 |
1 files changed, 112 insertions, 366 deletions
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index c2b14b2..60a6b72 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -16,6 +16,7 @@ =========================================================================*/ #include "cmLocalGenerator.h" +#include "cmComputeLinkInformation.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmInstallGenerator.h" @@ -23,7 +24,6 @@ #include "cmInstallScriptGenerator.h" #include "cmInstallTargetGenerator.h" #include "cmMakefile.h" -#include "cmOrderLinkDirectories.h" #include "cmSourceFile.h" #include "cmTest.h" #include "cmake.h" @@ -477,7 +477,7 @@ void cmLocalGenerator::GenerateInstallRules() } //---------------------------------------------------------------------------- -void cmLocalGenerator::GenerateTargetManifest(cmTargetManifest& manifest) +void cmLocalGenerator::GenerateTargetManifest() { // Collect the set of configuration types. std::vector<std::string> configNames; @@ -500,34 +500,17 @@ void cmLocalGenerator::GenerateTargetManifest(cmTargetManifest& manifest) for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t) { cmTarget& target = t->second; - cmTarget::TargetType type = target.GetType(); - if(type == cmTarget::STATIC_LIBRARY || - type == cmTarget::SHARED_LIBRARY || - type == cmTarget::MODULE_LIBRARY || - type == cmTarget::EXECUTABLE) + if(configNames.empty()) { - if(configNames.empty()) + target.GenerateTargetManifest(0); + } + else + { + for(std::vector<std::string>::iterator ci = configNames.begin(); + ci != configNames.end(); ++ci) { - manifest[""].insert(target.GetFullPath(0, false)); - if(type == cmTarget::SHARED_LIBRARY && - this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) - { - manifest[""].insert(target.GetFullPath(0, true)); - } - } - else - { - for(std::vector<std::string>::iterator ci = configNames.begin(); - ci != configNames.end(); ++ci) - { - const char* config = ci->c_str(); - manifest[config].insert(target.GetFullPath(config, false)); - if(type == cmTarget::SHARED_LIBRARY && - this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) - { - manifest[config].insert(target.GetFullPath(config, true)); - } - } + const char* config = ci->c_str(); + target.GenerateTargetManifest(config); } } } @@ -1478,50 +1461,53 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, // collect all the flags needed for linking libraries linkLibs = ""; - // Try to emit each search path once - std::set<cmStdString> emitted; + const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); + + cmComputeLinkInformation cli(&tgt, config); + if(!cli.Compute()) + { + return false; + } + + const char* linkLanguage = cli.GetLinkLanguage(); + // Embed runtime search paths if possible and if required. - bool outputRuntime = true; + bool outputRuntime = !this->Makefile->IsOn("CMAKE_SKIP_RPATH"); + + // Lookup rpath specification flags. std::string runtimeFlag; std::string runtimeSep; - - const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); - const char* linkLanguage = - tgt.GetLinkerLanguage(this->GetGlobalGenerator()); - if(!linkLanguage) + if(tgt.GetType() != cmTarget::STATIC_LIBRARY) { - cmSystemTools:: - Error("CMake can not determine linker language for target:", - tgt.GetName()); - return false; + std::string runTimeFlagVar = "CMAKE_"; + if(tgt.GetType() == cmTarget::EXECUTABLE) + { + runTimeFlagVar += "EXECUTABLE"; + } + else + { + runTimeFlagVar += "SHARED_LIBRARY"; + } + runTimeFlagVar += "_RUNTIME_"; + runTimeFlagVar += linkLanguage; + runTimeFlagVar += "_FLAG"; + std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP"; + runtimeFlag = this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str()); + runtimeSep = this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str()); } - std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; - runTimeFlagVar += linkLanguage; - runTimeFlagVar += "_FLAG"; - std::string runTimeFlagSepVar = runTimeFlagVar + "_SEP"; - runtimeFlag = this->Makefile->GetSafeDefinition(runTimeFlagVar.c_str()); - runtimeSep = this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str()); - // concatenate all paths or no? - bool runtimeConcatenate = ( runtimeSep!="" ); - if(runtimeFlag == "" || this->Makefile->IsOn("CMAKE_SKIP_RPATH")) + bool runtimeConcatenate = !runtimeSep.empty(); + + const char* runtimeAlways = + this->Makefile->GetDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"); + + // Turn off rpath support if no flag is available to specify it. + if(runtimeFlag.empty()) { outputRuntime = false; + runtimeAlways = 0; } - // Some search paths should never be emitted - emitted.insert(""); - if(const char* implicitLinks = - (this->Makefile->GetDefinition - ("CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES"))) - { - std::vector<std::string> implicitLinkVec; - cmSystemTools::ExpandListArgument(implicitLinks, implicitLinkVec); - for(unsigned int k = 0; k < implicitLinkVec.size(); ++k) - { - emitted.insert(implicitLinkVec[k]); - } - } std::string libPathFlag = this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG"); std::string libPathTerminator = @@ -1539,10 +1525,43 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, linkLibs += " "; } - // Compute the link library and directory information. - std::vector<cmStdString> libNames; - std::vector<cmStdString> libDirs; - this->ComputeLinkInformation(tgt, config, libNames, libDirs); + // Append the framework search path flags. + std::vector<std::string> const& fwDirs = cli.GetFrameworkPaths(); + for(std::vector<std::string>::const_iterator fdi = fwDirs.begin(); + fdi != fwDirs.end(); ++fdi) + { + linkLibs += "-F"; + linkLibs += this->Convert(fdi->c_str(), NONE, SHELL, false); + linkLibs += " "; + } + + // Append the library search path flags. + std::vector<std::string> const& libDirs = cli.GetDirectories(); + for(std::vector<std::string>::const_iterator libDir = libDirs.begin(); + libDir != libDirs.end(); ++libDir) + { + std::string libpath = this->ConvertToOutputForExisting(libDir->c_str()); + linkLibs += libPathFlag; + linkLibs += libpath; + linkLibs += libPathTerminator; + linkLibs += " "; + } + + // Append the link items. + typedef cmComputeLinkInformation::ItemVector ItemVector; + ItemVector const& items = cli.GetItems(); + for(ItemVector::const_iterator li = items.begin(); li != items.end(); ++li) + { + if(li->IsPath) + { + linkLibs += this->Convert(li->Value.c_str(), START_OUTPUT, SHELL); + } + else + { + linkLibs += li->Value; + } + linkLibs += " "; + } // Select whether to generate an rpath for the install tree or the // build tree. @@ -1562,68 +1581,46 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, { const char* install_rpath = tgt.GetProperty("INSTALL_RPATH"); cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs); - for(unsigned int i=0; i < runtimeDirs.size(); ++i) - { - runtimeDirs[i] = - this->Convert(runtimeDirs[i].c_str(), FULL, SHELL, false); - } } - - // Append the library search path flags. - for(std::vector<cmStdString>::const_iterator libDir = libDirs.begin(); - libDir != libDirs.end(); ++libDir) + if(use_build_rpath || use_link_rpath) { - std::string libpath = this->ConvertToOutputForExisting(libDir->c_str()); - if(emitted.insert(libpath).second) + std::vector<std::string> const& rdirs = cli.GetRuntimeSearchPath(); + for(std::vector<std::string>::const_iterator ri = rdirs.begin(); + ri != rdirs.end(); ++ri) { - std::string fullLibPath; - if(!this->WindowsShell && this->UseRelativePaths) + // 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) { - fullLibPath = "\"`cd "; + runtimeDirs.push_back(*ri); } - fullLibPath += libpath; - if(!this->WindowsShell && this->UseRelativePaths) + else if(use_link_rpath) { - fullLibPath += ";pwd`\""; - } - std::string::size_type pos = libDir->find(libPathFlag.c_str()); - if((pos == std::string::npos || pos > 0) - && libDir->find("${") == std::string::npos) - { - linkLibs += libPathFlag; - linkLibs += fullLibPath; - linkLibs += libPathTerminator; - linkLibs += " "; - - // 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) - { - runtimeDirs.push_back(fullLibPath); - } - else if(use_link_rpath) + // Do not add any path inside the source or build tree. + const char* topSourceDir = this->Makefile->GetHomeDirectory(); + const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory(); + if(!cmSystemTools::ComparePath(ri->c_str(), topSourceDir) && + !cmSystemTools::ComparePath(ri->c_str(), topBinaryDir) && + !cmSystemTools::IsSubDirectory(ri->c_str(), topSourceDir) && + !cmSystemTools::IsSubDirectory(ri->c_str(), topBinaryDir)) { - // Do not add any path inside the source or build tree. - const char* topSourceDir = this->Makefile->GetHomeDirectory(); - const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory(); - if(!cmSystemTools::ComparePath(libDir->c_str(), topSourceDir) && - !cmSystemTools::ComparePath(libDir->c_str(), topBinaryDir) && - !cmSystemTools::IsSubDirectory(libDir->c_str(), topSourceDir) && - !cmSystemTools::IsSubDirectory(libDir->c_str(), topBinaryDir)) - { - runtimeDirs.push_back(fullLibPath); - } + runtimeDirs.push_back(*ri); } } } } + if(runtimeAlways) + { + // Add runtime paths required by the platform to always be + // present. This is done even when skipping rpath support. + cmSystemTools::ExpandListArgument(runtimeAlways, runtimeDirs); + } - // Append the link libraries. - for(std::vector<cmStdString>::iterator lib = libNames.begin(); - lib != libNames.end(); ++lib) + // Convert the runtime directory names for use in the build file. + for(std::vector<std::string>::iterator ri = runtimeDirs.begin(); + ri != runtimeDirs.end(); ++ri) { - linkLibs += *lib; - linkLibs += " "; + *ri = this->Convert(ri->c_str(), FULL, SHELL, false); } if(!runtimeDirs.empty()) @@ -1715,257 +1712,6 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, } //---------------------------------------------------------------------------- -void cmLocalGenerator -::ComputeLinkInformation(cmTarget& target, - const char* config, - std::vector<cmStdString>& outLibs, - std::vector<cmStdString>& outDirs, - std::vector<cmStdString>* fullPathLibs) -{ - // Compute which library configuration to link. - cmTarget::LinkLibraryType linkType = cmTarget::OPTIMIZED; - if(config && cmSystemTools::UpperCase(config) == "DEBUG") - { - linkType = cmTarget::DEBUG; - } - - // Get the language used for linking. - const char* linkLanguage = - target.GetLinkerLanguage(this->GetGlobalGenerator()); - - // Check whether we should use an import library for linking a target. - bool implib = - this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")?true:false; - - // 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. - const char* loader_flag = 0; - if(!implib && target.GetType() == cmTarget::MODULE_LIBRARY) - { - if(!linkLanguage) - { - cmSystemTools:: - Error("CMake can not determine linker language for target:", - target.GetName()); - return; - } - std::string loader_flag_var = "CMAKE_SHARED_MODULE_LOADER_"; - loader_flag_var += linkLanguage; - loader_flag_var += "_FLAG"; - loader_flag = this->Makefile->GetDefinition(loader_flag_var.c_str()); - } - - // Get the list of libraries against which this target wants to link. - std::vector<std::string> linkLibraries; - const cmTarget::LinkLibraryVectorType& inLibs = target.GetLinkLibraries(); - for(cmTarget::LinkLibraryVectorType::const_iterator j = inLibs.begin(); - j != inLibs.end(); ++j) - { - // For backwards compatibility variables may have been expanded - // inside library names. Clean up the resulting name. - std::string lib = j->first; - std::string::size_type pos = lib.find_first_not_of(" \t\r\n"); - if(pos != lib.npos) - { - lib = lib.substr(pos, lib.npos); - } - pos = lib.find_last_not_of(" \t\r\n"); - if(pos != lib.npos) - { - lib = lib.substr(0, pos+1); - } - if(lib.empty()) - { - continue; - } - // Link to a library if it is not the same target and is meant for - // this configuration type. - if((target.GetType() == cmTarget::EXECUTABLE || - lib != target.GetName()) && - (j->second == cmTarget::GENERAL || j->second == linkType)) - { - // Compute the proper name to use to link this library. - cmTarget* tgt = this->GlobalGenerator->FindTarget(0, lib.c_str(), false); - bool impexe = (tgt && - tgt->GetType() == cmTarget::EXECUTABLE && - tgt->GetPropertyAsBool("ENABLE_EXPORTS")); - if(impexe && !implib && !loader_flag) - { - // Skip linking to executables on platforms with no import - // libraries or loader flags. - continue; - } - else if(tgt && (tgt->GetType() == cmTarget::STATIC_LIBRARY || - tgt->GetType() == cmTarget::SHARED_LIBRARY || - tgt->GetType() == cmTarget::MODULE_LIBRARY || - impexe)) - { - // This is a CMake target. Ask the target for its real name. - std::string linkItem; - if(impexe && loader_flag) - { - // 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 exe = tgt->GetFullPath(config, implib); - linkItem += loader_flag; - linkItem += this->Convert(exe.c_str(), NONE, SHELL, false); - } - else - { - // Pass the full path to the target file but purposely leave - // off the per-configuration subdirectory. The link directory - // ordering knows how to deal with this. - linkItem += tgt->GetDirectory(0, implib); - // on apple if the FRAMEWORK prop is set, then - // do not add the target full name but just use the directory - // name -#ifdef __APPLE__ - if (!(tgt->GetType() == cmTarget::SHARED_LIBRARY && - tgt->GetPropertyAsBool("FRAMEWORK"))) -#endif - { - linkItem += "/"; - linkItem += tgt->GetFullName(config, implib); - } - } - linkLibraries.push_back(linkItem); - // For full path, use the true location. - if(fullPathLibs) - { - fullPathLibs->push_back(tgt->GetFullPath(config, implib)); - } - } - else - { - // This is not a CMake target. Use the name given. - linkLibraries.push_back(lib); - - // Add to the list of full paths if this library is one. - if(fullPathLibs && - cmSystemTools::FileIsFullPath(lib.c_str()) && - !cmSystemTools::FileIsDirectory(lib.c_str())) - { - fullPathLibs->push_back(lib); - } - } - } - } - - // Get the list of directories the target wants to search for libraries. - const std::vector<std::string>& - linkDirectories = target.GetLinkDirectories(); - - // Lookup link type selection flags. - const char* static_link_type_flag = 0; - const char* shared_link_type_flag = 0; - const char* target_type_str = 0; - switch(target.GetType()) - { - case cmTarget::EXECUTABLE: target_type_str = "EXE"; break; - case cmTarget::SHARED_LIBRARY: target_type_str = "SHARED_LIBRARY"; break; - case cmTarget::MODULE_LIBRARY: target_type_str = "SHARED_MODULE"; break; - default: break; - } - if(target_type_str) - { - if(!linkLanguage) - { - cmSystemTools:: - Error("CMake can not determine linker language for target:", - target.GetName()); - return; - } - 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 += linkLanguage; - static_link_type_flag_var += "_FLAGS"; - static_link_type_flag = - this->Makefile->GetDefinition(static_link_type_flag_var.c_str()); - - 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 += linkLanguage; - shared_link_type_flag_var += "_FLAGS"; - shared_link_type_flag = - this->Makefile->GetDefinition(shared_link_type_flag_var.c_str()); - } - - // Compute the link directory order needed to link the libraries. - cmOrderLinkDirectories orderLibs; - orderLibs.SetLinkTypeInformation(cmOrderLinkDirectories::LinkShared, - static_link_type_flag, - shared_link_type_flag); - orderLibs.AddLinkPrefix( - this->Makefile->GetDefinition("CMAKE_STATIC_LIBRARY_PREFIX")); - orderLibs.AddLinkPrefix( - this->Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_PREFIX")); - - // Import library names should be matched and treated as shared - // libraries for the purposes of linking. - orderLibs.AddLinkExtension( - this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - cmOrderLinkDirectories::LinkShared); - orderLibs.AddLinkExtension( - this->Makefile->GetDefinition("CMAKE_STATIC_LIBRARY_SUFFIX"), - cmOrderLinkDirectories::LinkStatic); - orderLibs.AddLinkExtension( - this->Makefile->GetDefinition("CMAKE_SHARED_LIBRARY_SUFFIX"), - cmOrderLinkDirectories::LinkShared); - orderLibs.AddLinkExtension( - this->Makefile->GetDefinition("CMAKE_LINK_LIBRARY_SUFFIX")); - if(const char* linkSuffixes = - this->Makefile->GetDefinition("CMAKE_EXTRA_LINK_EXTENSIONS")) - { - std::vector<std::string> linkSuffixVec; - cmSystemTools::ExpandListArgument(linkSuffixes, linkSuffixVec); - for(std::vector<std::string>::iterator i = linkSuffixVec.begin(); - i != linkSuffixVec.end(); ++i) - { - orderLibs.AddLinkExtension(i->c_str()); - } - } - std::string configSubdir; - cmGlobalGenerator* gg = this->GetGlobalGenerator(); - gg->AppendDirectoryForConfig("", config, "", configSubdir); - orderLibs.SetLinkInformation(target.GetName(), - linkLibraries, - linkDirectories, - gg->GetTargetManifest(), - configSubdir.c_str()); - orderLibs.DetermineLibraryPathOrder(); - std::vector<cmStdString> orderedLibs; - orderLibs.GetLinkerInformation(outDirs, orderedLibs); - - // Make sure libraries are linked with the proper syntax. - std::string libLinkFlag = - this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG"); - std::string libLinkSuffix = - this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"); - for(std::vector<cmStdString>::iterator l = orderedLibs.begin(); - l != orderedLibs.end(); ++l) - { - std::string lib = *l; - if(lib[0] == '-' || lib[0] == '$' || lib[0] == '`') - { - // The library is linked with special syntax by the user. - outLibs.push_back(lib); - } - else - { - // Generate the proper link syntax. - lib = libLinkFlag; - lib += *l; - lib += libLinkSuffix; - outLibs.push_back(lib); - } - } -} - -//---------------------------------------------------------------------------- void cmLocalGenerator::AddLanguageFlags(std::string& flags, const char* lang, const char* config) |