Browse Source

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.

Brad King 17 years ago
parent
commit
ffac622a85

+ 133 - 0
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<std::string>& 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<std::string> const& rdirs = this->GetRuntimeSearchPath();
+    for(std::vector<std::string>::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<std::string> runtimeDirs;
+  this->GetRPath(runtimeDirs, for_install);
+
+  // Concatenate the paths.
+  std::string rpath;
+  const char* sep = "";
+  for(std::vector<std::string>::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");
+}

+ 10 - 0
Source/cmComputeLinkInformation.h

@@ -50,6 +50,12 @@ public:
   std::vector<std::string> const& GetFrameworkPaths();
   const char* GetLinkLanguage() const { return this->LinkLanguage; }
   std::vector<std::string> const& GetRuntimeSearchPath();
+  std::string const& GetRuntimeFlag() const { return this->RuntimeFlag; }
+  std::string const& GetRuntimeSep() const { return this->RuntimeSep; }
+  void GetRPath(std::vector<std::string>& 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();

+ 3 - 2
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.
     {

+ 12 - 27
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;

+ 1 - 0
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,

+ 46 - 174
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<std::string> 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<std::string> const& rdirs = cli.GetRuntimeSearchPath();
-    for(std::vector<std::string>::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<std::string>::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<std::string>::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<std::string>::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<unsigned int>(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()))

+ 0 - 7
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

+ 3 - 2
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<std::string> const& linkDirs = cli.GetDirectories();

+ 6 - 4
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

+ 63 - 32
Source/cmTarget.cxx

@@ -20,6 +20,7 @@
 #include "cmSourceFile.h"
 #include "cmLocalGenerator.h"
 #include "cmGlobalGenerator.h"
+#include "cmComputeLinkInformation.h"
 #include <map>
 #include <set>
 #include <queue>
@@ -40,6 +41,17 @@ cmTarget::cmTarget()
   this->IsImportedTarget = false;
 }
 
+//----------------------------------------------------------------------------
+cmTarget::~cmTarget()
+{
+  for(std::map<cmStdString, cmComputeLinkInformation*>::iterator
+        i = this->LinkInformation.begin();
+      i != this->LinkInformation.end(); ++i)
+    {
+    delete i->second;
+    }
+}
+
 //----------------------------------------------------------------------------
 void cmTarget::DefineProperties(cmake *cm)
 {
@@ -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<cmStdString>& 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<cmStdString, cmComputeLinkInformation*>::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<cmStdString, cmComputeLinkInformation*>::value_type
+      entry(config?config:"", info);
+    i = this->LinkInformation.insert(entry).first;
+    }
+  return i->second;
+}

+ 9 - 3
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<cmStdString, cmComputeLinkInformation*> LinkInformation;
+
   // The cmMakefile instance that owns this target.  This should
   // always be set.
   cmMakefile* Makefile;