From ffac622a858cca4dc661caa896d961da666430cc Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 29 Jan 2008 15:07:33 -0500 Subject: ENH: Add cmTarget::GetLinkInformation method to allow several places in the generators to share link information while only computing it once per configuration for a target. Use it to simplify the chrpath feature. --- Source/cmComputeLinkInformation.cxx | 133 +++++++++++++++++++ Source/cmComputeLinkInformation.h | 10 ++ Source/cmGlobalXCodeGenerator.cxx | 5 +- Source/cmInstallTargetGenerator.cxx | 39 ++---- Source/cmInstallTargetGenerator.h | 1 + Source/cmLocalGenerator.cxx | 220 +++++++------------------------ Source/cmLocalGenerator.h | 7 - Source/cmLocalVisualStudio6Generator.cxx | 5 +- Source/cmLocalVisualStudio7Generator.cxx | 10 +- Source/cmTarget.cxx | 95 ++++++++----- Source/cmTarget.h | 12 +- 11 files changed, 286 insertions(+), 251 deletions(-) diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index b614de8..190ffb8 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -168,6 +168,12 @@ cmComputeLinkInformation // Get the language used for linking this target. this->LinkLanguage = this->Target->GetLinkerLanguage(this->GlobalGenerator); + if(!this->LinkLanguage) + { + // The Compute method will do nothing, so skip the rest of the + // initialization. + return; + } // Check whether we should use an import library for linking a target. this->UseImportLibrary = @@ -194,6 +200,31 @@ cmComputeLinkInformation this->LibLinkSuffix = this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_SUFFIX"); + // Get options needed to specify RPATHs. + this->RuntimeUseChrpath = false; + if(this->Target->GetType() != cmTarget::STATIC_LIBRARY) + { + std::string rtVar = "CMAKE_"; + if(this->Target->GetType() == cmTarget::EXECUTABLE) + { + rtVar += "EXECUTABLE"; + } + else + { + rtVar += "SHARED_LIBRARY"; + } + rtVar += "_RUNTIME_"; + rtVar += this->LinkLanguage; + rtVar += "_FLAG"; + std::string rtSepVar = rtVar + "_SEP"; + this->RuntimeFlag = this->Makefile->GetSafeDefinition(rtVar.c_str()); + this->RuntimeSep = this->Makefile->GetSafeDefinition(rtSepVar.c_str()); + this->RuntimeAlways = + (this->Makefile-> + GetSafeDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH")); + this->RuntimeUseChrpath = this->Target->IsChrpathUsed(); + } + // Get link type information. this->ComputeLinkTypeInfo(); @@ -1227,3 +1258,105 @@ void cmComputeLinkInformation::DiagnoseCycle() } cmSystemTools::Message(e.str().c_str()); } + +//---------------------------------------------------------------------------- +void cmComputeLinkInformation::GetRPath(std::vector& runtimeDirs, + bool for_install) +{ + // 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() && + linking_for_install); + bool use_build_rpath = + (outputRuntime && this->Target->HaveBuildTreeRPATH() && + !linking_for_install); + bool use_link_rpath = + outputRuntime && linking_for_install && + this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH"); + + // Construct the RPATH. + if(use_install_rpath) + { + const char* install_rpath = this->Target->GetProperty("INSTALL_RPATH"); + cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs); + } + if(use_build_rpath || use_link_rpath) + { + std::vector const& rdirs = this->GetRuntimeSearchPath(); + for(std::vector::const_iterator ri = rdirs.begin(); + ri != rdirs.end(); ++ri) + { + // 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(*ri); + } + 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)) + { + runtimeDirs.push_back(*ri); + } + } + } + } + + // Add runtime paths required by the platform to always be + // present. This is done even when skipping rpath support. + cmSystemTools::ExpandListArgument(this->RuntimeAlways.c_str(), runtimeDirs); +} + +//---------------------------------------------------------------------------- +std::string cmComputeLinkInformation::GetRPathString(bool for_install) +{ + // Get the directories to use. + std::vector runtimeDirs; + this->GetRPath(runtimeDirs, for_install); + + // Concatenate the paths. + std::string rpath; + const char* sep = ""; + for(std::vector::const_iterator ri = runtimeDirs.begin(); + ri != runtimeDirs.end(); ++ri) + { + // Separate from previous path. + rpath += sep; + sep = this->GetRuntimeSep().c_str(); + + // Add this path. + rpath += *ri; + } + return rpath; +} + +//---------------------------------------------------------------------------- +std::string cmComputeLinkInformation::GetChrpathString() +{ + if(!this->RuntimeUseChrpath) + { + return ""; + } + + return this->GetRPathString(true); +} + +//---------------------------------------------------------------------------- +std::string cmComputeLinkInformation::GetChrpathTool() +{ + return this->Makefile->GetSafeDefinition("CMAKE_CHRPATH"); +} diff --git a/Source/cmComputeLinkInformation.h b/Source/cmComputeLinkInformation.h index 993ad0f..96af2e4 100644 --- a/Source/cmComputeLinkInformation.h +++ b/Source/cmComputeLinkInformation.h @@ -50,6 +50,12 @@ public: std::vector const& GetFrameworkPaths(); const char* GetLinkLanguage() const { return this->LinkLanguage; } std::vector const& GetRuntimeSearchPath(); + std::string const& GetRuntimeFlag() const { return this->RuntimeFlag; } + std::string const& GetRuntimeSep() const { return this->RuntimeSep; } + void GetRPath(std::vector& runtimeDirs, bool for_install); + std::string GetRPathString(bool for_install); + std::string GetChrpathString(); + std::string GetChrpathTool(); private: void AddItem(std::string const& item, cmTarget* tgt); @@ -76,6 +82,10 @@ private: std::string LibLinkFlag; std::string LibLinkFileFlag; std::string LibLinkSuffix; + std::string RuntimeFlag; + std::string RuntimeSep; + std::string RuntimeAlways; + bool RuntimeUseChrpath; // Link type adjustment. void ComputeLinkTypeInfo(); diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index f1a2b71..ed1af64 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -2105,11 +2105,12 @@ void cmGlobalXCodeGenerator } // Compute the link library and directory information. - cmComputeLinkInformation cli(cmtarget, configName); - if(!cli.Compute()) + cmComputeLinkInformation* pcli = cmtarget->GetLinkInformation(configName); + if(!pcli) { continue; } + cmComputeLinkInformation& cli = *pcli; // Add dependencies directly on library files. { diff --git a/Source/cmInstallTargetGenerator.cxx b/Source/cmInstallTargetGenerator.cxx index 2cbb31e..4f6539a 100644 --- a/Source/cmInstallTargetGenerator.cxx +++ b/Source/cmInstallTargetGenerator.cxx @@ -16,6 +16,7 @@ =========================================================================*/ #include "cmInstallTargetGenerator.h" +#include "cmComputeLinkInformation.h" #include "cmGlobalGenerator.h" #include "cmLocalGenerator.h" #include "cmMakefile.h" @@ -283,7 +284,7 @@ cmInstallTargetGenerator os << indent << "IF(EXISTS \"" << toDestDirPath << "\")\n"; this->AddInstallNamePatchRule(os, indent.Next(), config, toDestDirPath); - this->AddChrpathPatchRule(os, indent.Next(), toDestDirPath); + this->AddChrpathPatchRule(os, indent.Next(), config, toDestDirPath); this->AddRanlibRule(os, indent.Next(), type, toDestDirPath); this->AddStripRule(os, indent.Next(), type, toDestDirPath); os << indent << "ENDIF(EXISTS \"" << toDestDirPath << "\")\n"; @@ -487,7 +488,7 @@ cmInstallTargetGenerator void cmInstallTargetGenerator ::AddChrpathPatchRule(std::ostream& os, Indent const& indent, - std::string const& toDestDirPath) + const char* config, std::string const& toDestDirPath) { if(this->ImportLibrary || !(this->Target->GetType() == cmTarget::SHARED_LIBRARY || @@ -497,40 +498,24 @@ cmInstallTargetGenerator return; } - if((this->Target->GetMakefile()->IsOn("CMAKE_USE_CHRPATH")==false) - || (this->Target->IsChrpathAvailable()==false)) + if(!this->Target->IsChrpathUsed()) { return; } - // Fix the RPATH in installed ELF binaries using chrpath. - std::string chrpathTool = - this->Target->GetMakefile()->GetSafeDefinition("CMAKE_CHRPATH"); - - std::string installRpath; - std::string dummy; - this->Target->GetMakefile()->GetLocalGenerator()->GetLinkerArgs( - installRpath, dummy, *this->Target, true, 0); - - const char* linkLanguage = this->Target->GetLinkerLanguage(this->Target-> - GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()); - if (linkLanguage==0) + // Get the link information for this target. + // It can provide the RPATH. + cmComputeLinkInformation* cli = this->Target->GetLinkInformation(config); + if(!cli) { return; } - std::string runTimeFlagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; - runTimeFlagVar += linkLanguage; - runTimeFlagVar += "_FLAG"; - - std::string runtimeFlag = - this->Target->GetMakefile()->GetSafeDefinition(runTimeFlagVar.c_str()); + // Get the install RPATH from the link information. + std::string newRpath = cli->GetChrpathString(); - const char* newRpath=installRpath.c_str(); - if (strstr(installRpath.c_str(), runtimeFlag.c_str())==installRpath.c_str()) - { - newRpath = installRpath.c_str()+strlen(runtimeFlag.c_str()); - } + // Fix the RPATH in installed ELF binaries using chrpath. + std::string chrpathTool = cli->GetChrpathTool(); // Write a rule to run chrpath to set the install-tree RPATH os << indent << "EXECUTE_PROCESS(COMMAND \"" << chrpathTool; diff --git a/Source/cmInstallTargetGenerator.h b/Source/cmInstallTargetGenerator.h index 01d36bb..64ad784 100644 --- a/Source/cmInstallTargetGenerator.h +++ b/Source/cmInstallTargetGenerator.h @@ -58,6 +58,7 @@ protected: const char* config, const std::string& toDestDirPath); void AddChrpathPatchRule(std::ostream& os, Indent const& indent, + const char* config, std::string const& toDestDirPath); void AddStripRule(std::ostream& os, Indent const& indent, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4812572..493d26e 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1483,70 +1483,33 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib) return this->Convert(lib.c_str(), START_OUTPUT, SHELL); } -bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, - std::string& linkLibs, - cmTarget& tgt, - bool relink, - unsigned int minRpathSize) +/** + * Output the linking rules on a command line. For executables, + * targetLibrary should be a NULL pointer. For libraries, it should point + * to the name of the library. This will not link a library against itself. + */ +void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, + cmTarget& tgt, + bool relink) { - rpath = ""; - // collect all the flags needed for linking libraries - linkLibs = ""; - const char* config = this->Makefile->GetDefinition("CMAKE_BUILD_TYPE"); - - cmComputeLinkInformation cli(&tgt, config); - if(!cli.Compute()) + cmComputeLinkInformation* pcli = tgt.GetLinkInformation(config); + if(!pcli) { - return false; - } - - const char* linkLanguage = cli.GetLinkLanguage(); - - // Embed runtime search paths if possible and if required. - bool outputRuntime = !this->Makefile->IsOn("CMAKE_SKIP_RPATH"); - - // Lookup rpath specification flags. - std::string runtimeFlag; - std::string runtimeSep; - if(tgt.GetType() != cmTarget::STATIC_LIBRARY) - { - 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()); + return; } - // concatenate all paths or no? - bool runtimeConcatenate = !runtimeSep.empty(); + cmComputeLinkInformation& cli = *pcli; - const char* runtimeAlways = - this->Makefile->GetDefinition("CMAKE_PLATFORM_REQUIRED_RUNTIME_PATH"); + // Collect library linking flags command line options. + std::string linkLibs; - // Turn off rpath support if no flag is available to specify it. - if(runtimeFlag.empty()) - { - outputRuntime = false; - runtimeAlways = 0; - } + const char* linkLanguage = cli.GetLinkLanguage(); std::string libPathFlag = this->Makefile->GetRequiredDefinition("CMAKE_LIBRARY_PATH_FLAG"); std::string libPathTerminator = this->Makefile->GetSafeDefinition("CMAKE_LIBRARY_PATH_TERMINATOR"); - std::string libLinkFlag = - this->Makefile->GetSafeDefinition("CMAKE_LINK_LIBRARY_FLAG"); - + // Flags to link an executable to shared libraries. std::string linkFlagsVar = "CMAKE_SHARED_LIBRARY_LINK_"; linkFlagsVar += linkLanguage; @@ -1595,146 +1558,55 @@ bool cmLocalGenerator::GetLinkerArgs(std::string& rpath, linkLibs += " "; } - // Select whether to generate an rpath for the install tree or the - // build tree. - bool linking_for_install = - relink || tgt.GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"); - bool use_install_rpath = - outputRuntime && tgt.HaveInstallTreeRPATH() && linking_for_install; - bool use_build_rpath = - outputRuntime && tgt.HaveBuildTreeRPATH() && !linking_for_install; - bool use_link_rpath = - outputRuntime && linking_for_install && - tgt.GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH"); + // Write the library flags to the build rule. + fout << linkLibs; - // Construct the RPATH. + // Get the RPATH entries. std::vector runtimeDirs; - if(use_install_rpath) - { - const char* install_rpath = tgt.GetProperty("INSTALL_RPATH"); - cmSystemTools::ExpandListArgument(install_rpath, runtimeDirs); - } - if(use_build_rpath || use_link_rpath) + cli.GetRPath(runtimeDirs, relink); + + // Check what kind of rpath flags to use. + if(cli.GetRuntimeSep().empty()) { - std::vector const& rdirs = cli.GetRuntimeSearchPath(); - for(std::vector::const_iterator ri = rdirs.begin(); - ri != rdirs.end(); ++ri) + // Each rpath entry gets its own option ("-R a -R b -R c") + std::string rpath; + for(std::vector::iterator ri = runtimeDirs.begin(); + ri != runtimeDirs.end(); ++ri) { - // 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(*ri); - } - 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)) - { - runtimeDirs.push_back(*ri); - } - } + rpath += cli.GetRuntimeFlag(); + rpath += this->Convert(ri->c_str(), FULL, SHELL, false); + rpath += " "; } + fout << rpath; } - 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); - } - - // Convert the runtime directory names for use in the build file. - for(std::vector::iterator ri = runtimeDirs.begin(); - ri != runtimeDirs.end(); ++ri) + else { - *ri = this->Convert(ri->c_str(), FULL, SHELL, false); - } + // All rpath entries are combined ("-Wl,-rpath,a:b:c"). + std::string rpath = cli.GetRPathString(relink); - if(!runtimeDirs.empty()) - { - // For the runtime search directories, do a "-Wl,-rpath,a:b:c" or - // a "-R a -R b -R c" type link line - rpath += runtimeFlag; - std::vector::iterator itr = runtimeDirs.begin(); - rpath += *itr; - ++itr; - for( ; itr != runtimeDirs.end(); ++itr ) + // If not relinking, make sure the rpath string is long enough to + // support a subsequent chrpath on installation. + if(!relink) { - if(runtimeConcatenate) + std::string::size_type minLength = cli.GetChrpathString().size(); + while(rpath.size() < minLength) { - rpath += runtimeSep; - rpath += *itr; - } - else - { - rpath += " "; - rpath += runtimeFlag; - rpath += *itr; + rpath += cli.GetRuntimeSep(); } } - } - while (rpath.size() < minRpathSize) - { - if (rpath.size()==0) + // Store the rpath option in the stream. + if(!rpath.empty()) { - rpath += runtimeFlag; + fout << cli.GetRuntimeFlag(); + fout << this->EscapeForShell(rpath.c_str(), true); + fout << " "; } - - rpath += runtimeSep; - } - return true; -} - -/** - * Output the linking rules on a command line. For executables, - * targetLibrary should be a NULL pointer. For libraries, it should point - * to the name of the library. This will not link a library against itself. - */ -void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout, - cmTarget& tgt, - bool relink) -{ - std::string rpath; - std::string linkLibs; - unsigned int minBuildRpathSize = 0; - - if ((relink==false) - && this->Makefile->IsOn("CMAKE_USE_CHRPATH") - && (tgt.IsChrpathAvailable())) - { - std::string installRpath; - std::string dummy; - this->GetLinkerArgs(installRpath, dummy, tgt, true, 0); - minBuildRpathSize = static_cast(installRpath.size()); } - if (!this->GetLinkerArgs(rpath, linkLibs, tgt, relink, minBuildRpathSize)) - { - return; - } - - const char* linkLanguage = - tgt.GetLinkerLanguage(this->GetGlobalGenerator()); - if(!linkLanguage) - { - cmSystemTools:: - Error("CMake can not determine linker language for target:", - tgt.GetName()); - return; - } - - fout << linkLibs; - fout << rpath << " "; - // Add standard libraries for this language. std::string standardLibsVar = "CMAKE_"; - standardLibsVar += linkLanguage; + standardLibsVar += cli.GetLinkLanguage(); standardLibsVar += "_STANDARD_LIBRARIES"; if(const char* stdLibs = this->Makefile->GetDefinition(standardLibsVar.c_str())) diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index f334163..d899747 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -248,13 +248,6 @@ public: */ virtual std::string GetTargetDirectory(cmTarget const& target) const; - ///! Determine the arguments for the linker call, used also by - /// cmInstallTargetGenerator - bool GetLinkerArgs(std::string& rpath, std::string& linkLibs, - cmTarget& tgt, bool relink, unsigned int minRpathSize); - - bool IsChrpathAvailable(const cmTarget& target); - /** * Get the level of backwards compatibility requested by the project * in this directory. This is the value of the CMake variable diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 258d027..c657a0e 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -1570,11 +1570,12 @@ void cmLocalVisualStudio6Generator std::string& options) { // Compute the link information for this configuration. - cmComputeLinkInformation cli(&target, configName); - if(!cli.Compute()) + cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + if(!pcli) { return; } + cmComputeLinkInformation& cli = *pcli; typedef cmComputeLinkInformation::ItemVector ItemVector; ItemVector const& linkLibs = cli.GetItems(); std::vector const& linkDirs = cli.GetDirectories(); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index b368f7c..5922884 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -762,11 +762,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, targetNameImport, targetNamePDB, configName); // Compute the link library and directory information. - cmComputeLinkInformation cli(&target, configName); - if(!cli.Compute()) + cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + if(!pcli) { return; } + cmComputeLinkInformation& cli = *pcli; const char* linkLanguage = cli.GetLinkLanguage(); // Compute the variable name to lookup standard libraries for this @@ -831,11 +832,12 @@ void cmLocalVisualStudio7Generator::OutputBuildTool(std::ostream& fout, targetNameImport, targetNamePDB, configName); // Compute the link library and directory information. - cmComputeLinkInformation cli(&target, configName); - if(!cli.Compute()) + cmComputeLinkInformation* pcli = target.GetLinkInformation(configName); + if(!pcli) { return; } + cmComputeLinkInformation& cli = *pcli; const char* linkLanguage = cli.GetLinkLanguage(); // Compute the variable name to lookup standard libraries for this diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index a6bf5d2..3691c47 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -20,6 +20,7 @@ #include "cmSourceFile.h" #include "cmLocalGenerator.h" #include "cmGlobalGenerator.h" +#include "cmComputeLinkInformation.h" #include #include #include @@ -41,6 +42,17 @@ cmTarget::cmTarget() } //---------------------------------------------------------------------------- +cmTarget::~cmTarget() +{ + for(std::map::iterator + i = this->LinkInformation.begin(); + i != this->LinkInformation.end(); ++i) + { + delete i->second; + } +} + +//---------------------------------------------------------------------------- void cmTarget::DefineProperties(cmake *cm) { cm->DefineProperty @@ -2531,12 +2543,6 @@ bool cmTarget::NeedRelinkBeforeInstall() return false; } - if(this->Makefile->IsOn("CMAKE_USE_CHRPATH") - && (this->IsChrpathAvailable())) - { - return false; - } - // If skipping all rpaths completely then no relinking is needed. if(this->Makefile->IsOn("CMAKE_SKIP_RPATH")) { @@ -2549,6 +2555,12 @@ bool cmTarget::NeedRelinkBeforeInstall() return false; } + // If chrpath is going to be used no relinking is needed. + if(this->IsChrpathUsed()) + { + return false; + } + // Check for rpath support on this platform. if(const char* ll = this->GetLinkerLanguage( this->Makefile->GetLocalGenerator()->GetGlobalGenerator())) @@ -2809,35 +2821,28 @@ void cmTarget::GetLanguages(std::set& languages) const } } -bool cmTarget::IsChrpathAvailable() +//---------------------------------------------------------------------------- +bool cmTarget::IsChrpathUsed() { - //only return true if chrpath has been found (happens only if the executable - // format is ELF) and if the separator is not empty - if (this->Makefile->IsSet("CMAKE_CHRPATH")==false) - { - return false; - } - - const char* linkLanguage = this->GetLinkerLanguage(this->Makefile-> - GetLocalGenerator()->GetGlobalGenerator()); - if (linkLanguage==0) - { - return false; - } - - std::string runTimeFlagSepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; - runTimeFlagSepVar += linkLanguage; - runTimeFlagSepVar += "_FLAG_SEP"; - - std::string runtimeSep = - this->Makefile->GetSafeDefinition(runTimeFlagSepVar.c_str()); - - if (runtimeSep.size()<=0) + // Enable use of "chrpath" if it is available, the user has turned + // on the feature, and the rpath flag uses a separator. + if(const char* ll = this->GetLinkerLanguage( + this->Makefile->GetLocalGenerator()->GetGlobalGenerator())) { - return 0; + std::string sepVar = "CMAKE_SHARED_LIBRARY_RUNTIME_"; + sepVar += ll; + sepVar += "_FLAG_SEP"; + const char* sep = this->Makefile->GetDefinition(sepVar.c_str()); + if(sep && *sep) + { + if(this->Makefile->IsSet("CMAKE_CHRPATH") && + this->Makefile->IsOn("CMAKE_USE_CHRPATH")) + { + return true; + } + } } - - return true; + return false; } //---------------------------------------------------------------------------- @@ -3044,3 +3049,29 @@ cmTarget::GetImportedLinkLibraries(const char* config) return 0; } } + +//---------------------------------------------------------------------------- +cmComputeLinkInformation* +cmTarget::GetLinkInformation(const char* config) +{ + // Lookup any existing information for this configuration. + std::map::iterator + i = this->LinkInformation.find(config?config:""); + if(i == this->LinkInformation.end()) + { + // Compute information for this configuration. + cmComputeLinkInformation* info = + new cmComputeLinkInformation(this, config); + if(!info || !info->Compute()) + { + delete info; + info = 0; + } + + // Store the information for this configuration. + std::map::value_type + entry(config?config:"", info); + i = this->LinkInformation.insert(entry).first; + } + return i->second; +} diff --git a/Source/cmTarget.h b/Source/cmTarget.h index c1de1a3..202190a 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -24,6 +24,7 @@ class cmake; class cmMakefile; class cmSourceFile; class cmGlobalGenerator; +class cmComputeLinkInformation; /** \class cmTarget * \brief Represent a library or executable target loaded from a makefile. @@ -35,6 +36,7 @@ class cmTarget { public: cmTarget(); + ~cmTarget(); enum TargetType { EXECUTABLE, STATIC_LIBRARY, SHARED_LIBRARY, MODULE_LIBRARY, UTILITY, GLOBAL_TARGET, INSTALL_FILES, INSTALL_PROGRAMS, INSTALL_DIRECTORY}; @@ -289,13 +291,15 @@ public: bool HaveBuildTreeRPATH(); bool HaveInstallTreeRPATH(); - - /// return true if chrpath might work for this target - bool IsChrpathAvailable(); + + /** Return true if chrpath might work for this target */ + bool IsChrpathUsed(); std::string GetInstallNameDirForBuildTree(const char* config); std::string GetInstallNameDirForInstallTree(const char* config); + cmComputeLinkInformation* GetLinkInformation(const char* config); + // Get the properties cmPropertyMap &GetProperties() { return this->Properties; }; @@ -462,6 +466,8 @@ private: ImportInfo const* GetImportInfo(const char* config); void ComputeImportInfo(std::string const& desired_config, ImportInfo& info); + std::map LinkInformation; + // The cmMakefile instance that owns this target. This should // always be set. cmMakefile* Makefile; -- cgit v0.12