浏览代码

file(GET_RUNTIME_DEPENDENCIES): Add undocumented RPATH_PREFIX option

Kyle Edwards 4 年之前
父节点
当前提交
2ef3ea394f

+ 14 - 8
Source/cmBinUtilsMacOSMachOLinker.cxx

@@ -65,18 +65,18 @@ bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
   if (!executableFile.empty()) {
     executablePath = cmSystemTools::GetFilenamePath(executableFile);
   }
-  return this->ScanDependencies(file, executablePath);
-}
-
-bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
-  std::string const& file, std::string const& executablePath)
-{
   std::vector<std::string> libs;
   std::vector<std::string> rpaths;
   if (!this->Tool->GetFileInfo(file, libs, rpaths)) {
     return false;
   }
+  return this->ScanDependencies(file, libs, rpaths, executablePath);
+}
 
+bool cmBinUtilsMacOSMachOLinker::ScanDependencies(
+  std::string const& file, std::vector<std::string> const& libs,
+  std::vector<std::string> const& rpaths, std::string const& executablePath)
+{
   std::string loaderPath = cmSystemTools::GetFilenamePath(file);
   return this->GetFileDependencies(libs, executablePath, loaderPath, rpaths);
 }
@@ -98,8 +98,14 @@ bool cmBinUtilsMacOSMachOLinker::GetFileDependencies(
             !IsMissingSystemDylib(path)) {
           auto filename = cmSystemTools::GetFilenameName(path);
           bool unique;
-          this->Archive->AddResolvedPath(filename, path, unique);
-          if (unique && !this->ScanDependencies(path, executablePath)) {
+          std::vector<std::string> libs;
+          std::vector<std::string> depRpaths;
+          if (!this->Tool->GetFileInfo(path, libs, depRpaths)) {
+            return false;
+          }
+          this->Archive->AddResolvedPath(filename, path, unique, depRpaths);
+          if (unique &&
+              !this->ScanDependencies(path, libs, depRpaths, executablePath)) {
             return false;
           }
         }

+ 2 - 0
Source/cmBinUtilsMacOSMachOLinker.h

@@ -27,6 +27,8 @@ private:
   std::unique_ptr<cmBinUtilsMacOSMachOGetRuntimeDependenciesTool> Tool;
 
   bool ScanDependencies(std::string const& file,
+                        std::vector<std::string> const& libs,
+                        std::vector<std::string> const& rpaths,
                         std::string const& executablePath);
 
   bool GetFileDependencies(std::vector<std::string> const& names,

+ 7 - 0
Source/cmFileCommand.cxx

@@ -3032,6 +3032,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
     std::string ResolvedDependenciesVar;
     std::string UnresolvedDependenciesVar;
     std::string ConflictingDependenciesPrefix;
+    std::string RPathPrefix;
     std::string BundleExecutable;
     std::vector<std::string> Executables;
     std::vector<std::string> Libraries;
@@ -3053,6 +3054,7 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
             &Arguments::UnresolvedDependenciesVar)
       .Bind("CONFLICTING_DEPENDENCIES_PREFIX"_s,
             &Arguments::ConflictingDependenciesPrefix)
+      .Bind("RPATH_PREFIX"_s, &Arguments::RPathPrefix)
       .Bind("BUNDLE_EXECUTABLE"_s, &Arguments::BundleExecutable)
       .Bind("EXECUTABLES"_s, &Arguments::Executables)
       .Bind("LIBRARIES"_s, &Arguments::Libraries)
@@ -3135,6 +3137,11 @@ bool HandleGetRuntimeDependenciesCommand(std::vector<std::string> const& args,
 
     if (unique) {
       deps.push_back(firstPath);
+      if (!parsedArgs.RPathPrefix.empty()) {
+        status.GetMakefile().AddDefinition(
+          parsedArgs.RPathPrefix + "_" + firstPath,
+          cmJoin(archive.GetRPaths().at(firstPath), ";"));
+      }
     } else if (!parsedArgs.ConflictingDependenciesPrefix.empty()) {
       conflictingDeps.push_back(val.first);
       std::vector<std::string> paths;

+ 10 - 3
Source/cmRuntimeDependencyArchive.cxx

@@ -354,9 +354,9 @@ bool cmRuntimeDependencyArchive::IsPostExcluded(const std::string& name) const
       fileSearch(this->PostExcludeFiles)));
 }
 
-void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
-                                                 const std::string& path,
-                                                 bool& unique)
+void cmRuntimeDependencyArchive::AddResolvedPath(
+  const std::string& name, const std::string& path, bool& unique,
+  std::vector<std::string> rpaths)
 {
   auto it = this->ResolvedPaths.emplace(name, std::set<std::string>{}).first;
   unique = true;
@@ -367,6 +367,7 @@ void cmRuntimeDependencyArchive::AddResolvedPath(const std::string& name,
     }
   }
   it->second.insert(path);
+  this->RPaths[path] = std::move(rpaths);
 }
 
 void cmRuntimeDependencyArchive::AddUnresolvedPath(const std::string& name)
@@ -390,3 +391,9 @@ const std::set<std::string>& cmRuntimeDependencyArchive::GetUnresolvedPaths()
 {
   return this->UnresolvedPaths;
 }
+
+const std::map<std::string, std::vector<std::string>>&
+cmRuntimeDependencyArchive::GetRPaths() const
+{
+  return this->RPaths;
+}

+ 3 - 1
Source/cmRuntimeDependencyArchive.h

@@ -45,12 +45,13 @@ public:
   bool IsPostExcluded(const std::string& name) const;
 
   void AddResolvedPath(const std::string& name, const std::string& path,
-                       bool& unique);
+                       bool& unique, std::vector<std::string> rpaths = {});
   void AddUnresolvedPath(const std::string& name);
 
   cmMakefile* GetMakefile() const;
   const std::map<std::string, std::set<std::string>>& GetResolvedPaths() const;
   const std::set<std::string>& GetUnresolvedPaths() const;
+  const std::map<std::string, std::vector<std::string>>& GetRPaths() const;
 
 private:
   cmExecutionStatus& Status;
@@ -70,4 +71,5 @@ private:
   std::vector<std::string> PostExcludeFilesStrict;
   std::map<std::string, std::set<std::string>> ResolvedPaths;
   std::set<std::string> UnresolvedPaths;
+  std::map<std::string, std::vector<std::string>> RPaths;
 };

+ 1 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/RunCMakeTest.cmake

@@ -36,6 +36,7 @@ endfunction()
 if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin")
   if(NOT CMake_INSTALL_NAME_TOOL_BUG)
     run_install_test(macos)
+    run_install_test(macos-rpath)
     run_install_test(macos-unresolved)
     run_install_test(macos-conflict)
     run_install_test(macos-notfile)

+ 35 - 0
Tests/RunCMake/file-GET_RUNTIME_DEPENDENCIES/macos-rpath.cmake

@@ -0,0 +1,35 @@
+enable_language(C)
+
+file(WRITE "${CMAKE_BINARY_DIR}/toplib.c" "extern void sublib1(void);\nextern void sublib2(void);\nvoid toplib(void)\n{\n  sublib1();\n  sublib2();\n}\n")
+add_library(toplib SHARED "${CMAKE_BINARY_DIR}/toplib.c")
+file(WRITE "${CMAKE_BINARY_DIR}/sublib1.c" "extern void sublib2(void);\nvoid sublib1(void)\n{\n  sublib2();\n}\n")
+add_library(sublib1 SHARED "${CMAKE_BINARY_DIR}/sublib1.c")
+file(WRITE "${CMAKE_BINARY_DIR}/sublib2.c" "void sublib2(void)\n{\n}\n")
+add_library(sublib2 SHARED "${CMAKE_BINARY_DIR}/sublib2.c")
+target_link_libraries(toplib PRIVATE sublib1 sublib2)
+target_link_libraries(sublib1 PRIVATE sublib2)
+set_property(TARGET toplib PROPERTY INSTALL_RPATH "@loader_path/d1;@loader_path/d2")
+set_property(TARGET sublib1 PROPERTY INSTALL_RPATH "@loader_path/;@loader_path/../d2")
+install(TARGETS toplib DESTINATION lib)
+install(TARGETS sublib1 DESTINATION lib/d1)
+install(TARGETS sublib2 DESTINATION lib/d2)
+
+install(CODE [[
+  file(GET_RUNTIME_DEPENDENCIES
+    LIBRARIES
+      "${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:toplib>"
+    RPATH_PREFIX _rpaths
+    )
+
+  set(_expected_rpath "(^|;)@loader_path/;@loader_path/\\.\\./d2$")
+  set(_actual_rpath "${_rpaths_${CMAKE_INSTALL_PREFIX}/lib/d1/$<TARGET_FILE_NAME:sublib1>}")
+  if(NOT _actual_rpath MATCHES "${_expected_rpath}")
+    message(FATAL_ERROR "Expected rpath:\n  ${_expected_rpath}\nActual rpath:\n  ${_actual_rpath}")
+  endif()
+
+  # Since RPATH_PREFIX is an undocumented option for install(), we don't really need the rpath
+  # for the top files anyway.
+  if(DEFINED "_rpaths_${CMAKE_INSTALL_PREFIX}/lib/$<TARGET_FILE_NAME:toplib>")
+    message(FATAL_ERROR "rpath for top library should not be defined")
+  endif()
+  ]])