瀏覽代碼

ENH: Implemented RPATH specification support. It is documented by the command SET_TARGET_PROPERTIES.

Brad King 19 年之前
父節點
當前提交
537e2b4ed5

+ 24 - 0
Source/cmGlobalUnixMakefileGenerator3.cxx

@@ -152,6 +152,11 @@ void cmGlobalUnixMakefileGenerator3::WriteMainMakefile2()
                     "The main recursive all target", "all", 
                     depends, no_commands, true);
 
+  // Write an empty preinstall:
+  lg->WriteMakeRule(makefileStream,
+                    "The main recursive preinstall target", "preinstall",
+                    depends, no_commands, true);
+
   lg->WriteMakeVariables(makefileStream);
 
   // Write out the "special" stuff
@@ -731,6 +736,25 @@ cmGlobalUnixMakefileGenerator3
       lg->WriteMakeRule(ruleFileStream, "Convenience name for target.",
                         t->second.GetName(), depends, commands, true);
 
+      // Add rules to prepare the target for installation.
+      if(t->second.NeedRelinkBeforeInstall())
+        {
+        localName = lg->GetRelativeTargetDirectory(t->second);
+        localName += "/preinstall";
+        depends.clear();
+        commands.clear();
+        commands.push_back(lg->GetRecursiveMakeCall
+                           (makefileName.c_str(), localName.c_str()));
+        this->AppendGlobalTargetDepends(depends,t->second);
+        lg->WriteMakeRule(ruleFileStream, "Pre-intsall relink rule for target.",
+                          localName.c_str(), depends, commands, true);
+        depends.clear();
+        depends.push_back(localName);
+        commands.clear();
+        lg->WriteMakeRule(ruleFileStream, "Prepare target for install.",
+                          "preinstall", depends, commands, true);
+        }
+
       // add the clean rule
       localName = lg->GetRelativeTargetDirectory(t->second);
       makeTargetName = localName;

+ 39 - 11
Source/cmLocalGenerator.cxx

@@ -353,6 +353,7 @@ void cmLocalGenerator::GenerateInstallRules()
     // EXECUTABLE_OUTPUT_PATH not defined
     exeOutPath = currdir + "/";
     }
+  std::string relinkDir = currdir + "/CMakeFiles/CMakeRelink.dir/";
 
   // Include user-specified install scripts.
   std::vector<std::string> const& installScripts =
@@ -375,6 +376,7 @@ void cmLocalGenerator::GenerateInstallRules()
       }
     if (l->second.GetInstallPath() != "")
       {
+      bool need_relink = l->second.NeedRelinkBeforeInstall();
       destination = "${CMAKE_INSTALL_PREFIX}" + l->second.GetInstallPath();
       cmSystemTools::ConvertToUnixSlashes(destination);
       const char* dest = destination.c_str();
@@ -398,7 +400,7 @@ void cmLocalGenerator::GenerateInstallRules()
           if ( ext == ".dll" )
             {
             // Install the .lib separately.
-            std::string libname = libOutPath;
+            std::string libname = need_relink? relinkDir : libOutPath;
             libname += this->GetInstallReference(l->second, config,
                                                  configurationTypes,
                                                  true);
@@ -438,7 +440,7 @@ void cmLocalGenerator::GenerateInstallRules()
         case cmTarget::STATIC_LIBRARY:
         case cmTarget::MODULE_LIBRARY:
           {
-          fname = libOutPath;
+          fname = need_relink? relinkDir : libOutPath;
           fname += this->GetInstallReference(l->second, config,
                                              configurationTypes);
           files = fname.c_str();
@@ -460,7 +462,7 @@ void cmLocalGenerator::GenerateInstallRules()
             }
           std::string exeName =
             this->GetInstallReference(l->second, config, configurationTypes);
-          fname = exeOutPath;
+          fname = need_relink? relinkDir : exeOutPath;
           fname += exeName;
           if(l->second.GetPropertyAsBool("MACOSX_BUNDLE"))
             {
@@ -1117,7 +1119,11 @@ const char* cmLocalGenerator::GetIncludeFlags(const char* lang)
     }
   flags += m_Makefile->GetDefineFlags();
   m_LanguageToIncludeFlags[lang] = flags;
-  return m_LanguageToIncludeFlags[lang].c_str();
+
+  // Use this temorary variable for the return value to work-around a
+  // bogus GCC 2.95 warning.
+  const char* ret = m_LanguageToIncludeFlags[lang].c_str();
+  return ret;
 }
 
 //----------------------------------------------------------------------------
@@ -1246,7 +1252,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
         linkFlags += " ";
         }  
       cmOStringStream linklibsStr;
-      this->OutputLinkLibraries(linklibsStr, target);
+      this->OutputLinkLibraries(linklibsStr, target, false);
       linkLibs = linklibsStr.str();
       }
       break;
@@ -1279,7 +1285,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
       flags += m_Makefile->GetSafeDefinition(sharedFlagsVar.c_str());
       flags += " ";
       cmOStringStream linklibs;
-      this->OutputLinkLibraries(linklibs, target);
+      this->OutputLinkLibraries(linklibs, target, false);
       linkLibs = linklibs.str();
       if(cmSystemTools::IsOn(m_Makefile->GetDefinition("BUILD_SHARED_LIBS")))
         {
@@ -1319,7 +1325,8 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs,
  * to the name of the library.  This will not link a library against itself.
  */
 void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
-                                           cmTarget &tgt)
+                                           cmTarget& tgt,
+                                           bool relink)
 {
   // Try to emit each search path once
   std::set<cmStdString> emitted;
@@ -1327,7 +1334,6 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
   bool outputRuntime = true;
   std::string runtimeFlag;
   std::string runtimeSep;
-  std::vector<std::string> runtimeDirs;
 
   const char* config = m_Makefile->GetDefinition("CMAKE_BUILD_TYPE");
   const char* linkLanguage = tgt.GetLinkerLanguage(this->GetGlobalGenerator());
@@ -1347,7 +1353,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
   
   // concatenate all paths or no?
   bool runtimeConcatenate = ( runtimeSep!="" );
-  if(runtimeFlag == "" || m_Makefile->IsOn("CMAKE_SKIP_RPATH") )
+  if(runtimeFlag == "" || m_Makefile->IsOn("CMAKE_SKIP_RPATH"))
     {
     outputRuntime = false;
     }
@@ -1375,6 +1381,28 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
   std::vector<cmStdString> libDirs;
   this->ComputeLinkInformation(tgt, config, libNames, libDirs);
 
+  // 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;
+
+  // Construct the RPATH.
+  std::vector<std::string> runtimeDirs;
+  if(use_install_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)
@@ -1397,7 +1425,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
          && libDir->find("${") == std::string::npos)
         {
         linkLibs += libPathFlag;
-        if(outputRuntime)
+        if(use_build_rpath)
           {
           runtimeDirs.push_back( fullLibPath );
           }
@@ -1417,7 +1445,7 @@ void cmLocalGenerator::OutputLinkLibraries(std::ostream& fout,
 
   fout << linkLibs;
 
-  if(outputRuntime && runtimeDirs.size()>0)
+  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

+ 1 - 1
Source/cmLocalGenerator.h

@@ -175,7 +175,7 @@ protected:
                       cmTarget&target);
   
   ///! put all the libraries for a target on into the given stream
-  virtual void OutputLinkLibraries(std::ostream&, cmTarget&);
+  virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink);
 
   /** Compute the string to use to refer to a target in an install
       file.  */

+ 16 - 2
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -1288,6 +1288,7 @@ void cmLocalUnixMakefileGenerator3
   // Write special "install" target to run cmake_install.cmake script.
   {
   std::vector<std::string> depends;
+  depends.push_back("preinstall");
   std::vector<std::string> commands;
   std::string cmd;
   if(m_Makefile->GetDefinition("CMake_BINARY_DIR"))
@@ -1304,6 +1305,12 @@ void cmLocalUnixMakefileGenerator3
     }
   cmd += " -P cmake_install.cmake";
   commands.push_back(cmd);
+  this->WriteMakeRule(ruleFileStream,
+                      "Special rule to run installation script.",
+                      "install", depends, commands, true);
+
+  commands.clear();
+  depends.clear();
   const char* noall =
     m_Makefile->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY");
   if(!noall || cmSystemTools::IsOff(noall))
@@ -1311,9 +1318,16 @@ void cmLocalUnixMakefileGenerator3
     // Drive the build before installing.
     depends.push_back("all");
     }
+  else
+    {
+    // At least make sure the build system is up to date.
+    depends.push_back("cmake_check_build_system");
+    }
+  commands.push_back(this->GetRecursiveMakeCall
+                     ("CMakeFiles/Makefile2", "preinstall"));
   this->WriteMakeRule(ruleFileStream,
-                      "Special rule to run installation script.",
-                      "install", depends, commands, true);
+                      "Prepare targets for installation.",
+                      "preinstall", depends, commands, true);
   }
 
   // Write special "rebuild_cache" target to re-run cmake.

+ 16 - 4
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -39,7 +39,12 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
   this->WriteTargetDependRules();
 
   // write the link rules
-  this->WriteExecutableRule();
+  this->WriteExecutableRule(false);
+  if(this->Target->NeedRelinkBeforeInstall())
+    {
+    // Write rules to link an installable version of the target.
+    this->WriteExecutableRule(true);
+    }
 
   // Write the requires target.
   this->WriteTargetRequiresRules();
@@ -54,7 +59,7 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
 
 
 //----------------------------------------------------------------------------
-void cmMakefileExecutableTargetGenerator::WriteExecutableRule()
+void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
 {
   std::vector<std::string> commands;
 
@@ -132,6 +137,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule()
                                                     false, false, false);
     }
 #endif
+  if(relink)
+    {
+    outpath = this->Makefile->GetStartOutputDirectory();
+    outpath += "/CMakeFiles/CMakeRelink.dir";
+    cmSystemTools::MakeDirectory(outpath.c_str());
+    outpath += "/";
+    }
   std::string targetFullPath = outpath + targetName;
   std::string targetFullPathReal = outpath + targetNameReal;
 
@@ -259,7 +271,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule()
 
   // Collect up flags to link in needed libraries.
   cmOStringStream linklibs;
-  this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target);
+  this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
 
   // Construct object file lists that may be needed to expand the
   // rule.
@@ -316,7 +328,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule()
   dir += "/";
   dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
   std::string buildTargetRuleName = dir;
-  buildTargetRuleName += "/build";
+  buildTargetRuleName += relink?"/preinstall":"/build";
   buildTargetRuleName = 
     this->Convert(buildTargetRuleName.c_str(),
                   cmLocalGenerator::HOME_OUTPUT,

+ 1 - 1
Source/cmMakefileExecutableTargetGenerator.h

@@ -27,7 +27,7 @@ public:
   virtual void WriteRuleFiles();
   
 protected:
-  virtual void WriteExecutableRule();
+  virtual void WriteExecutableRule(bool relink);
   
 };
 

+ 42 - 15
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -46,10 +46,20 @@ void cmMakefileLibraryTargetGenerator::WriteRuleFiles()
       this->WriteStaticLibraryRules();
       break;
     case cmTarget::SHARED_LIBRARY:
-      this->WriteSharedLibraryRules();
+      this->WriteSharedLibraryRules(false);
+      if(this->Target->NeedRelinkBeforeInstall())
+        {
+        // Write rules to link an installable version of the target.
+        this->WriteSharedLibraryRules(true);
+        }
       break;
     case cmTarget::MODULE_LIBRARY:
-      this->WriteModuleLibraryRules();
+      this->WriteModuleLibraryRules(false);
+      if(this->Target->NeedRelinkBeforeInstall())
+        {
+        // Write rules to link an installable version of the target.
+        this->WriteModuleLibraryRules(true);
+        }
       break;
     default:
       // If language is not known, this is an error.
@@ -82,11 +92,11 @@ void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
 
   std::string extraFlags;
   this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("STATIC_LIBRARY_FLAGS"));
-  this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str());
+  this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), false);
 }
 
 //----------------------------------------------------------------------------
-void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules()
+void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
 {
   const char* linkLanguage =
     this->Target->GetLinkerLanguage(this->GlobalGenerator);
@@ -115,11 +125,11 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules()
         }
       }
     }
-  this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str());
+  this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
 }
 
 //----------------------------------------------------------------------------
-void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules()
+void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
 {
   const char* linkLanguage =
     this->Target->GetLinkerLanguage(this->GlobalGenerator);
@@ -134,12 +144,12 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules()
   this->LocalGenerator->AppendFlags(extraFlags, this->Target->GetProperty("LINK_FLAGS"));
   this->LocalGenerator->AddConfigVariableFlags(extraFlags, "CMAKE_MODULE_LINKER_FLAGS");
   // TODO: .def files should be supported here also.
-  this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str());
+  this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
 }
 
 //----------------------------------------------------------------------------
 void cmMakefileLibraryTargetGenerator::WriteLibraryRules
-(const char* linkRuleVar, const char* extraFlags)
+(const char* linkRuleVar, const char* extraFlags, bool relink)
 {
   // TODO: Merge the methods that call this method to avoid
   // code duplication.
@@ -202,6 +212,13 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
     outpath = this->Makefile->GetStartOutputDirectory();
     outpath += "/";
     }
+  if(relink)
+    {
+    outpath = this->Makefile->GetStartOutputDirectory();
+    outpath += "/CMakeFiles/CMakeRelink.dir";
+    cmSystemTools::MakeDirectory(outpath.c_str());
+    outpath += "/";
+    }
   std::string targetFullPath = outpath + targetName;
   std::string targetFullPathSO = outpath + targetNameSO;
   std::string targetFullPathReal = outpath + targetNameReal;
@@ -285,9 +302,15 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
                                         this->Makefile->GetHomeOutputDirectory());
   commands.insert(commands.end(), commands1.begin(), commands1.end());
   commands1.clear();
-  // Add the pre-build and pre-link rules.
-  this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
-  this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
+
+  // Add the pre-build and pre-link rules building but not when relinking.
+  if(!relink)
+    {
+    this->LocalGenerator
+      ->AppendCustomCommands(commands, this->Target->GetPreBuildCommands());
+    this->LocalGenerator
+      ->AppendCustomCommands(commands, this->Target->GetPreLinkCommands());
+    }
 
   // Construct the main link rule.
   std::string linkRule = this->Makefile->GetRequiredDefinition(linkRuleVar);
@@ -314,12 +337,16 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
     commands.insert(commands.end(), commands1.begin(), commands1.end());
     }
 
-  // Add the post-build rules.
-  this->LocalGenerator->AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
+  // Add the post-build rules when building but not when relinking.
+  if(!relink)
+    {
+    this->LocalGenerator->
+      AppendCustomCommands(commands, this->Target->GetPostBuildCommands());
+    }
 
   // Collect up flags to link in needed libraries.
   cmOStringStream linklibs;
-  this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target);
+  this->LocalGenerator->OutputLinkLibraries(linklibs, *this->Target, relink);
 
   // Construct object file lists that may be needed to expand the
   // rule.
@@ -381,7 +408,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
   dir += "/";
   dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
   std::string buildTargetRuleName = dir;
-  buildTargetRuleName += "/build";
+  buildTargetRuleName += relink?"/preinstall":"/build";
   buildTargetRuleName = 
     this->Convert(buildTargetRuleName.c_str(),
                   cmLocalGenerator::HOME_OUTPUT,cmLocalGenerator::MAKEFILE);

+ 4 - 3
Source/cmMakefileLibraryTargetGenerator.h

@@ -29,9 +29,10 @@ public:
   
 protected:
   void WriteStaticLibraryRules();
-  void WriteSharedLibraryRules();
-  void WriteModuleLibraryRules();
-  void WriteLibraryRules(const char *linkRule, const char *extraFlags);
+  void WriteSharedLibraryRules(bool relink);
+  void WriteModuleLibraryRules(bool relink);
+  void WriteLibraryRules(const char *linkRule, const char *extraFlags,
+                         bool relink);
 };
 
 #endif

+ 14 - 1
Source/cmSetTargetPropertiesCommand.h

@@ -79,7 +79,20 @@ public:
         "When building or installing appropriate symlinks are created if "
         "the platform supports symlinks. "
         "The OUTPUT_NAME can be used to set an output name that is "
-        "used in place of the target name when creating executables. "
+        "used in place of the target name when creating executables.\n"
+        "There are a few properties used to specify RPATH rules. "
+        "INSTALL_RPATH is a semicolon-separated list specifying the rpath "
+        "to use in installed targets (for platforms that support it). "
+        "SKIP_BUILD_RPATH is a boolean specifying whether to skip automatic "
+        "generation of an rpath allowing the target to run from the "
+        "build tree. "
+        "BUILD_WITH_INSTALL_RPATH is a boolean specifying whether to link "
+        "the target in the build tree with the INSTALL_RPATH.  This takes "
+        "precedence over SKIP_BUILD_RPATH and avoids the need for relinking "
+        "before installation. When the target is created the values of "
+        "the variables CMAKE_INSTALL_RPATH, CMAKE_SKIP_BUILD_RPATH, and "
+        "CMAKE_BUILD_WITH_INSTALL_RPATH are used to initialize these "
+        "properties.\n"
         "PROJECT_LABEL can be used to change the name of "
         "the target in an IDE like visual studio.  VS_KEYWORD can be set "
         "to change the visual studio keyword, for example QT integration "

+ 101 - 0
Source/cmTarget.cxx

@@ -44,6 +44,17 @@ void cmTarget::SetType(TargetType type, const char* name)
   }
 }
 
+//----------------------------------------------------------------------------
+void cmTarget::SetMakefile(cmMakefile* mf)
+{
+  // Set our makefile.
+  m_Makefile = mf;
+
+  // Setup default property values.
+  this->SetPropertyDefault("INSTALL_RPATH", "");
+  this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF");
+  this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF");
+}
 
 void cmTarget::TraceVSDependencies(std::string projFile, 
                                    cmMakefile *makefile)
@@ -1309,3 +1320,93 @@ void cmTarget::GetExecutableNamesInternal(std::string& name,
     realName += version;
     }
 }
+
+//----------------------------------------------------------------------------
+void cmTarget::SetPropertyDefault(const char* property,
+                                  const char* default_value)
+{
+  // Compute the name of the variable holding the default value.
+  std::string var = "CMAKE_";
+  var += property;
+
+  if(const char* value = m_Makefile->GetDefinition(var.c_str()))
+    {
+    this->SetProperty(property, value);
+    }
+  else if(default_value)
+    {
+    this->SetProperty(property, default_value);
+    }
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HaveBuildTreeRPATH()
+{
+  return (!this->GetPropertyAsBool("SKIP_BUILD_RPATH") &&
+          !m_LinkLibraries.empty());
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::HaveInstallTreeRPATH()
+{
+  const char* install_rpath = this->GetProperty("INSTALL_RPATH");
+  return install_rpath && *install_rpath;
+}
+
+//----------------------------------------------------------------------------
+bool cmTarget::NeedRelinkBeforeInstall()
+{
+  // Only executables and shared libraries can have an rpath and may
+  // need relinking.
+  if(m_TargetType != cmTarget::EXECUTABLE &&
+     m_TargetType != cmTarget::SHARED_LIBRARY &&
+     m_TargetType != cmTarget::MODULE_LIBRARY)
+    {
+    return false;
+    }
+
+  // If there is no install location this target will not be installed
+  // and therefore does not need relinking.
+  if(this->GetInstallPath().empty())
+    {
+    return false;
+    }
+
+  // If skipping all rpaths completely then no relinking is needed.
+  if(m_Makefile->IsOn("CMAKE_SKIP_RPATH"))
+    {
+    return false;
+    }
+
+  // If building with the install-tree rpath no relinking is needed.
+  if(this->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"))
+    {
+    return false;
+    }
+
+  // Check for rpath support on this platform.
+  if(const char* ll = this->GetLinkerLanguage(
+       m_Makefile->GetLocalGenerator()->GetGlobalGenerator()))
+    {
+    std::string flagVar = "CMAKE_SHARED_LIBRARY_RUNTIME_";
+    flagVar += ll;
+    flagVar += "_FLAG";
+    if(!m_Makefile->IsSet(flagVar.c_str()))
+      {
+      // There is no rpath support on this platform so nothing needs
+      // relinking.
+      return false;
+      }
+    }
+  else
+    {
+    // No linker language is known.  This error will be reported by
+    // other code.
+    return false;
+    }
+
+  // If either a build or install tree rpath is set then the rpath
+  // will likely change between the build tree and install tree and
+  // this target must be relinked.
+  return this->HaveBuildTreeRPATH() || this->HaveInstallTreeRPATH();
+}

+ 14 - 2
Source/cmTarget.h

@@ -63,7 +63,7 @@ public:
   void SetInAll(bool f) { this->SetProperty("IN_ALL", (f) ?"TRUE" : "FALSE"); }
 
   ///! Set the cmMakefile that owns this target
-  void SetMakefile(cmMakefile *mf) { m_Makefile = mf; };
+  void SetMakefile(cmMakefile *mf);
   cmMakefile *GetMakefile() { return m_Makefile;};
   
   /**
@@ -209,6 +209,15 @@ public:
       executable target.  */
   void GetExecutableCleanNames(std::string& name, std::string& realName,
                                const char* config);
+
+  /**
+   * Compute whether this target must be relinked before installing.
+   */
+  bool NeedRelinkBeforeInstall();
+
+  bool HaveBuildTreeRPATH();
+  bool HaveInstallTreeRPATH();
+
 private:
   /**
    * A list of direct dependencies. Use in conjunction with DependencyMap.
@@ -281,7 +290,10 @@ private:
 
   // update the value of the LOCATION var
   void UpdateLocation();
-  
+
+  // Use a makefile variable to set a default for the given property.
+  // If the variable is not defined use the given default instead.
+  void SetPropertyDefault(const char* property, const char* default_value);
 private:
   std::string m_Name;
   std::vector<cmCustomCommand> m_PreBuildCommands;

+ 3 - 0
Tests/SimpleInstall/CMakeLists.txt

@@ -8,6 +8,9 @@ SET(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
 # avoids infinite loops when the post-build rule below installs.
 SET(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1)
 
+# Make sure the test executable can run from the install tree.
+SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
+
 SET(CMAKE_DEBUG_POSTFIX "_test_debug_postfix")
 
 SET(EXTRA_INSTALL_FLAGS)

+ 3 - 0
Tests/SimpleInstallS2/CMakeLists.txt

@@ -8,6 +8,9 @@ SET(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
 # avoids infinite loops when the post-build rule below installs.
 SET(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY 1)
 
+# Make sure the test executable can run from the install tree.
+SET(CMAKE_INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib)
+
 SET(CMAKE_DEBUG_POSTFIX "_test_debug_postfix")
 
 SET(EXTRA_INSTALL_FLAGS)