From 782e9f7ffe722fc7dac1353cd95a31e7140e5c6f Mon Sep 17 00:00:00 2001 From: Brad King Date: Thu, 21 Feb 2008 13:58:41 -0500 Subject: [PATCH] ENH: Improve linking to third-party shared libraries on soname platforms - Reduce false positives in cases of unknown soname - Make library extension regular expressions match only at end of string - When linking to libraries in implicit dirs convert to the -l option only if the file name is one that can be found by the linker (ex. /usr/lib/libfoo.so.1 should be linked by full path) - Add cmSystemTools::GuessLibrarySOName to guess the soname of a library based on presence of a symlink - In cmComputeLinkInformation try to guess an soname before assuming that a third-party library is built without an soname - In cmOrderDirectories guess the soname of shared libraries in cases it is otherwise unknown --- Source/cmComputeLinkInformation.cxx | 25 ++++++++++++++++++----- Source/cmOrderDirectories.cxx | 10 +++++++++- Source/cmSystemTools.cxx | 31 +++++++++++++++++++++++++++++ Source/cmSystemTools.h | 4 ++++ 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 1da512c08..1899bd2f6 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -27,6 +27,8 @@ #include +//#define CM_COMPUTE_LINK_INFO_DEBUG + /* Notes about linking on various platforms: @@ -905,7 +907,7 @@ cmComputeLinkInformation } // Finish the list. - libext += ").*"; + libext += ")$"; return libext; } @@ -1070,6 +1072,13 @@ bool cmComputeLinkInformation::CheckImplicitDirItem(std::string const& item) return false; } + // Only apply the policy below if the library file is one that can + // be found by the linker. + if(!this->ExtractAnyLibraryName.find(item)) + { + return false; + } + // Many system linkers support multiple architectures by // automatically selecting the implicit linker search path for the // current architecture. If the library appears in an implicit link @@ -1262,13 +1271,19 @@ bool cmComputeLinkInformation::CheckSharedLibNoSOName(std::string const& item) { // 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. TODO: Check if - // the lib is a symlink to detect that it actually has an soname. + // this is a shared library that might be the case. std::string file = cmSystemTools::GetFilenameName(item); if(this->ExtractSharedLibraryName.find(file)) { - this->AddSharedLibNoSOName(item); - return true; + // 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(item, soname)) + { + this->AddSharedLibNoSOName(item); + return true; + } } return false; } diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index 7bc5dd60f..a0ff9c11e 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -119,6 +119,15 @@ public: const char* soname): cmOrderDirectoriesConstraint(od, file), SOName(soname? soname : "") { + if(this->SOName.empty()) + { + // Try to guess the soname. + std::string soguess; + if(cmSystemTools::GuessLibrarySOName(file, soguess)) + { + this->SOName = soguess; + } + } } virtual void Report(std::ostream& e) @@ -164,7 +173,6 @@ bool cmOrderDirectoriesConstraintSOName::FindConflict(std::string const& dir) // Get the set of files that might conflict. Since we do not // know the soname just look at all files that start with the // file name. Usually the soname starts with the library name. - // TODO: Check if the library is a symlink and guess the soname. std::string base = this->FileName; std::set::const_iterator first = files.lower_bound(base); ++base[base.size()-1]; diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 002dc0ba9..8d13e11bd 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2150,3 +2150,34 @@ void cmSystemTools::MakefileColorEcho(int color, const char* message, } } #endif + +//---------------------------------------------------------------------------- +bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath, + std::string& soname) +{ + // If the file is not a symlink we have no guess for its soname. + if(!cmSystemTools::FileIsSymlink(fullPath.c_str())) + { + return false; + } + if(!cmSystemTools::ReadSymlink(fullPath.c_str(), soname)) + { + return false; + } + + // If the symlink has a path component we have no guess for the soname. + if(!cmSystemTools::GetFilenamePath(soname).empty()) + { + return false; + } + + // If the symlink points at an extended version of the same name + // assume it is the soname. + std::string name = cmSystemTools::GetFilenameName(fullPath); + if(soname.length() > name.length() && + soname.substr(0, name.length()) == name) + { + return true; + } + return false; +} diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 3bf22f78d..e03c24cd2 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -377,6 +377,10 @@ public: bool newLine, bool enabled); #endif + /** Try to guess the soname of a shared library. */ + static bool GuessLibrarySOName(std::string const& fullPath, + std::string& soname); + private: static bool s_ForceUnixPaths; static bool s_RunCommandHideConsole;