Browse Source

ENH: Use builtin chrpath instead of relinking ELF targets

  - Add cmSystemTools::ChangeRPath method
  - Add undocumented file(CHRPATH) command
  - When installing use file(CHRPATH) to change the rpath
    instead of relinking
  - Remove CMAKE_CHRPATH lookup from CMakeFindBinUtils
  - Remove CMAKE_USE_CHRPATH option since this should
    always work
Brad King 18 years ago
parent
commit
34c76d4304

+ 0 - 13
Modules/CMakeFindBinUtils.cmake

@@ -74,16 +74,3 @@ IF(APPLE)
 
   MARK_AS_ADVANCED(CMAKE_INSTALL_NAME_TOOL)
 ENDIF(APPLE)
-
-# if we are on an ELF system, search for chrpath
-# according to the binutils mailing list chrpath has problems when cross compiling
-# i.e. if the target has different endianness than the host
-IF("${CMAKE_EXECUTABLE_FORMAT}" STREQUAL "ELF"  AND NOT  CMAKE_CROSSCOMPILING)
-  # on ELF platforms there might be chrpath, which works similar to install_name_tool
-  OPTION(CMAKE_USE_CHRPATH "Enable this to use chrpath if available" OFF)
-
-  FIND_PROGRAM(CMAKE_CHRPATH chrpath PATHS ${_CMAKE_TOOLCHAIN_LOCATION} NO_DEFAULT_PATH)
-  FIND_PROGRAM(CMAKE_CHRPATH chrpath)
-
-  MARK_AS_ADVANCED(CMAKE_CHRPATH CMAKE_USE_CHRPATH)
-ENDIF("${CMAKE_EXECUTABLE_FORMAT}" STREQUAL "ELF"  AND NOT  CMAKE_CROSSCOMPILING)

+ 0 - 6
Source/cmComputeLinkInformation.cxx

@@ -1476,9 +1476,3 @@ std::string cmComputeLinkInformation::GetChrpathString()
 
   return this->GetRPathString(true);
 }
-
-//----------------------------------------------------------------------------
-std::string cmComputeLinkInformation::GetChrpathTool()
-{
-  return this->Makefile->GetSafeDefinition("CMAKE_CHRPATH");
-}

+ 0 - 1
Source/cmComputeLinkInformation.h

@@ -58,7 +58,6 @@ public:
   void GetRPath(std::vector<std::string>& runtimeDirs, bool for_install);
   std::string GetRPathString(bool for_install);
   std::string GetChrpathString();
-  std::string GetChrpathTool();
   std::set<cmTarget*> const& GetSharedLibrariesLinked();
 
   std::string const& GetRPathLinkFlag() const { return this->RPathLinkFlag; }

+ 32 - 0
Source/cmFileCommand.cxx

@@ -112,6 +112,10 @@ bool cmFileCommand
     {
     return this->HandleInstallCommand(args);
     }
+  else if ( subCommand == "CHRPATH" )
+    {
+    return this->HandleChrpathCommand(args);
+    }
   else if ( subCommand == "RELATIVE_PATH" )
     {
     return this->HandleRelativePathCommand(args);
@@ -1326,6 +1330,34 @@ bool cmFileCommand::HandleInstallDestination(cmFileInstaller& installer,
   return true;
 }
 
+//----------------------------------------------------------------------------
+bool cmFileCommand::HandleChrpathCommand(std::vector<std::string> const& args)
+{
+  if(args.size() != 3)
+    {
+    this->SetError("CHRPATH must be given a file and a new rpath.");
+    return false;
+    }
+  if(!cmSystemTools::FileExists(args[1].c_str(), true))
+    {
+    this->SetError("CHRPATH given file that does not exist.");
+    return false;
+    }
+  std::string emsg;
+  if(cmSystemTools::ChangeRPath(args[1], args[2], &emsg))
+    {
+    return true;
+    }
+  else
+    {
+    cmOStringStream e;
+    e << "CHRPATH could not write new RPATH to the file: "
+      << emsg;
+    this->SetError(e.str().c_str());
+    return false;
+    }
+}
+
 //----------------------------------------------------------------------------
 bool cmFileCommand::HandleInstallCommand(std::vector<std::string> const& args)
 {

+ 1 - 0
Source/cmFileCommand.h

@@ -171,6 +171,7 @@ protected:
   bool HandleRelativePathCommand(std::vector<std::string> const& args);
   bool HandleCMakePathCommand(std::vector<std::string> const& args,
                               bool nativePath);
+  bool HandleChrpathCommand(std::vector<std::string> const& args);
 
   // file(INSTALL ...) related functions
   bool HandleInstallCommand(std::vector<std::string> const& args);

+ 2 - 5
Source/cmInstallTargetGenerator.cxx

@@ -576,12 +576,9 @@ cmInstallTargetGenerator
   // Get the install RPATH from the link information.
   std::string newRpath = cli->GetChrpathString();
 
-  // 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;
-  os << "\" -r \"" << newRpath << "\" \"" << toDestDirPath << "\")\n";
+  os << indent
+     << "FILE(CHRPATH \"" << toDestDirPath << "\" \"" << newRpath << "\")\n";
 }
 
 //----------------------------------------------------------------------------

+ 83 - 0
Source/cmSystemTools.cxx

@@ -2195,3 +2195,86 @@ bool cmSystemTools::GuessLibrarySOName(std::string const& fullPath,
     }
   return false;
 }
+
+//----------------------------------------------------------------------------
+bool cmSystemTools::ChangeRPath(std::string const& file,
+                                std::string const& newRPath,
+                                std::string* emsg)
+{
+#if defined(CMAKE_USE_ELF_PARSER)
+  unsigned long rpathPosition = 0;
+  unsigned long rpathSize = 0;
+  {
+  cmELF elf(file.c_str());
+  if(cmELF::StringEntry const* se = elf.GetRPath())
+    {
+    rpathPosition = se->Position;
+    rpathSize = se->Size;
+    }
+  else
+    {
+    if(emsg)
+      {
+      *emsg = "No valid ELF RPATH entry exists in the file.";
+      }
+    return false;
+    }
+  }
+  // Make sure there is enough room to store the new rpath and at
+  // least one null terminator.
+  if(rpathSize < newRPath.length()+1)
+    {
+    if(emsg)
+      {
+      *emsg = "The replacement RPATH is too long.";
+      }
+    return false;
+    }
+
+  // Open the file for update and seek to the RPATH position.
+  std::ofstream f(file.c_str(),
+                  std::ios::in | std::ios::out | std::ios::binary);
+  if(!f)
+    {
+    if(emsg)
+      {
+      *emsg = "Error opening file for update.";
+      }
+    return false;
+    }
+  if(!f.seekp(rpathPosition))
+    {
+    if(emsg)
+      {
+      *emsg = "Error seeking to RPATH position.";
+      }
+    return false;
+    }
+
+  // Write the new rpath.  Follow it with enough null terminators to
+  // fill the string table entry.
+  f << newRPath;
+  for(unsigned long i=newRPath.length(); i < rpathSize; ++i)
+    {
+    f << '\0';
+    }
+
+  // Make sure everything was okay.
+  if(f)
+    {
+    return true;
+    }
+  else
+    {
+    if(emsg)
+      {
+      *emsg = "Error writing the new rpath to the file.";
+      }
+    return false;
+    }
+#else
+  (void)file;
+  (void)newRPath;
+  return false;
+#endif
+}

+ 5 - 0
Source/cmSystemTools.h

@@ -381,6 +381,11 @@ public:
   static bool GuessLibrarySOName(std::string const& fullPath,
                                  std::string& soname);
 
+  /** Try to set the RPATH in an ELF binary.  */
+  static bool ChangeRPath(std::string const& file,
+                          std::string const& newRPath,
+                          std::string* emsg = 0);
+
 private:
   static bool s_ForceUnixPaths;
   static bool s_RunCommandHideConsole;

+ 9 - 5
Source/cmTarget.cxx

@@ -3006,8 +3006,9 @@ void cmTarget::GetLanguages(std::set<cmStdString>& languages) const
 //----------------------------------------------------------------------------
 bool cmTarget::IsChrpathUsed()
 {
-  // Enable use of "chrpath" if it is available, the user has turned
-  // on the feature, and the rpath flag uses a separator.
+#if defined(CMAKE_USE_ELF_PARSER)
+  // Enable if the rpath flag uses a separator and the target uses ELF
+  // binaries.
   if(const char* ll = this->GetLinkerLanguage(
        this->Makefile->GetLocalGenerator()->GetGlobalGenerator()))
     {
@@ -3017,13 +3018,16 @@ bool cmTarget::IsChrpathUsed()
     const char* sep = this->Makefile->GetDefinition(sepVar.c_str());
     if(sep && *sep)
       {
-      if(this->Makefile->IsSet("CMAKE_CHRPATH") &&
-         this->Makefile->IsOn("CMAKE_USE_CHRPATH"))
+      // TODO: Add ELF check to ABI detection and get rid of
+      // CMAKE_EXECUTABLE_FORMAT.
+      if(const char* fmt =
+         this->Makefile->GetDefinition("CMAKE_EXECUTABLE_FORMAT"))
         {
-        return true;
+        return strcmp(fmt, "ELF") == 0;
         }
       }
     }
+#endif
   return false;
 }
 

+ 1 - 1
Source/cmTarget.h

@@ -335,7 +335,7 @@ public:
   bool HaveBuildTreeRPATH();
   bool HaveInstallTreeRPATH();
 
-  /** Return true if chrpath might work for this target */
+  /** Return true if builtin chrpath will work for this target */
   bool IsChrpathUsed();
 
   std::string GetInstallNameDirForBuildTree(const char* config);