summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Help/manual/cmake-properties.7.rst1
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst24
-rw-r--r--Help/release/dev/relative-rpath.rst8
-rw-r--r--Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst7
-rw-r--r--Modules/Platform/Linux.cmake1
-rw-r--r--Source/cmComputeLinkInformation.cxx29
-rw-r--r--Source/cmTarget.cxx1
-rw-r--r--Tests/RunCMake/RuntimePath/Relative.cmake69
-rw-r--r--Tests/RunCMake/RuntimePath/RelativeCheck.cmake4
-rw-r--r--Tests/RunCMake/RuntimePath/RunCMakeTest.cmake14
-rw-r--r--Tests/RunCMake/RuntimePath/main.c4
12 files changed, 159 insertions, 4 deletions
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 5c3eb81..1651114 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -138,6 +138,7 @@ Properties on Targets
/prop_tgt/AUTORCC_OPTIONS
/prop_tgt/BINARY_DIR
/prop_tgt/BUILD_RPATH
+ /prop_tgt/BUILD_RPATH_USE_ORIGIN
/prop_tgt/BUILD_WITH_INSTALL_NAME_DIR
/prop_tgt/BUILD_WITH_INSTALL_RPATH
/prop_tgt/BUNDLE_EXTENSION
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 9dd36ed..b88c661 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -322,6 +322,7 @@ Variables that Control the Build
/variable/CMAKE_AUTOUIC_OPTIONS
/variable/CMAKE_AUTOUIC_SEARCH_PATHS
/variable/CMAKE_BUILD_RPATH
+ /variable/CMAKE_BUILD_RPATH_USE_ORIGIN
/variable/CMAKE_BUILD_WITH_INSTALL_NAME_DIR
/variable/CMAKE_BUILD_WITH_INSTALL_RPATH
/variable/CMAKE_COMPILE_PDB_OUTPUT_DIRECTORY
diff --git a/Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst b/Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst
new file mode 100644
index 0000000..511de7a
--- /dev/null
+++ b/Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst
@@ -0,0 +1,24 @@
+BUILD_RPATH_USE_ORIGIN
+----------------------
+
+Whether to use relative paths for the build ``RPATH``.
+
+This property is initialized by the value of the variable
+:variable:`CMAKE_BUILD_RPATH_USE_ORIGIN`.
+
+On platforms that support runtime paths (``RPATH``) with the
+``$ORIGIN`` token, setting this property to ``TRUE`` enables relative
+paths in the build ``RPATH`` for executables that point to shared
+libraries in the same build tree.
+
+Normally the build ``RPATH`` of an executable contains absolute paths
+to the directory of shared libraries. Directories contained within the
+build tree can be made relative to enable relocatable builds and to
+help achieving reproducible builds by omitting the build directory
+from the build environment.
+
+This property has no effect on platforms that do not support the
+``$ORIGIN`` token in ``RPATH``, or when the :variable:`CMAKE_SKIP_RPATH`
+variable is set. The runtime path set through the
+:prop_tgt:`BUILD_RPATH` target property is also unaffected by this
+property.
diff --git a/Help/release/dev/relative-rpath.rst b/Help/release/dev/relative-rpath.rst
new file mode 100644
index 0000000..5c62b10
--- /dev/null
+++ b/Help/release/dev/relative-rpath.rst
@@ -0,0 +1,8 @@
+relative-rpath
+--------------
+
+* A :variable:`CMAKE_BUILD_RPATH_USE_ORIGIN` variable and corresponding
+ :prop_tgt:`BUILD_RPATH_USE_ORIGIN` target property were added to
+ enable use of relative runtime paths (RPATHs). This helps achieving
+ relocatable and reproducible builds that are invariant of the build
+ directory.
diff --git a/Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst b/Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst
new file mode 100644
index 0000000..e34ede6
--- /dev/null
+++ b/Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst
@@ -0,0 +1,7 @@
+CMAKE_BUILD_RPATH_USE_ORIGIN
+----------------------------
+
+Whether to use relative paths for the build ``RPATH``.
+
+This is used to initialize the :prop_tgt:`BUILD_RPATH_USE_ORIGIN` target
+property for all targets, see that property for more details.
diff --git a/Modules/Platform/Linux.cmake b/Modules/Platform/Linux.cmake
index 1f8c1b4..b5d5464 100644
--- a/Modules/Platform/Linux.cmake
+++ b/Modules/Platform/Linux.cmake
@@ -1,6 +1,7 @@
set(CMAKE_DL_LIBS "dl")
set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "-Wl,-rpath,")
set(CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG_SEP ":")
+set(CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN "\$ORIGIN")
set(CMAKE_SHARED_LIBRARY_RPATH_LINK_C_FLAG "-Wl,-rpath-link,")
set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,")
set(CMAKE_EXE_EXPORTS_C_FLAG "-Wl,--export-dynamic")
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index 0e48ca8..27b8599 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -421,7 +421,8 @@ std::string cmComputeLinkInformation::GetRPathLinkString() const
return "";
}
- // Construct the linker runtime search path.
+ // Construct the linker runtime search path. These MUST NOT contain tokens
+ // such as $ORIGIN, see https://sourceware.org/bugzilla/show_bug.cgi?id=16936
return cmJoin(this->OrderDependentRPath->GetOrderedDirectories(), ":");
}
@@ -1702,6 +1703,14 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
!this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") &&
this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH");
+ // Select whether to use $ORIGIN in RPATHs for artifacts in the build tree.
+ std::string const& originToken = this->Makefile->GetSafeDefinition(
+ "CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN");
+ std::string targetOutputDir = this->Target->GetDirectory(this->Config);
+ bool use_relative_build_rpath =
+ this->Target->GetPropertyAsBool("BUILD_RPATH_USE_ORIGIN") &&
+ !originToken.empty() && !targetOutputDir.empty();
+
// Construct the RPATH.
std::set<std::string> emitted;
if (use_install_rpath) {
@@ -1711,6 +1720,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
if (use_build_rpath) {
// Add directories explicitly specified by user
if (const char* build_rpath = this->Target->GetProperty("BUILD_RPATH")) {
+ // This will not resolve entries to use $ORIGIN, the user is expected to
+ // do that if necessary.
cmCLI_ExpandListUnique(build_rpath, runtimeDirs, emitted);
}
}
@@ -1728,6 +1739,8 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
cmSystemTools::ConvertToUnixSlashes(rootPath);
std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath();
+ std::string const& topBinaryDir =
+ this->CMakeInstance->GetHomeOutputDirectory();
for (std::string const& ri : rdirs) {
// Put this directory in the rpath if using build-tree rpath
// support or if using the link path as an rpath.
@@ -1741,6 +1754,18 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
d += "/";
d += suffix;
cmSystemTools::ConvertToUnixSlashes(d);
+ } else if (use_relative_build_rpath) {
+ // If expansion of the $ORIGIN token is supported and permitted per
+ // policy, use relative paths in the RPATH.
+ if (cmSystemTools::ComparePath(d, topBinaryDir) ||
+ cmSystemTools::IsSubDirectory(d, topBinaryDir)) {
+ d = cmSystemTools::RelativePath(targetOutputDir, d);
+ if (!d.empty()) {
+ d = originToken + "/" + d;
+ } else {
+ d = originToken;
+ }
+ }
}
if (emitted.insert(d).second) {
runtimeDirs.push_back(std::move(d));
@@ -1749,8 +1774,6 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
// Do not add any path inside the source or build tree.
std::string const& topSourceDir =
this->CMakeInstance->GetHomeDirectory();
- std::string const& topBinaryDir =
- this->CMakeInstance->GetHomeOutputDirectory();
if (!cmSystemTools::ComparePath(ri, topSourceDir) &&
!cmSystemTools::ComparePath(ri, topBinaryDir) &&
!cmSystemTools::IsSubDirectory(ri, topSourceDir) &&
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 1458f01..987bdb3 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -218,6 +218,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
this->SetPropertyDefault("ANDROID_ASSETS_DIRECTORIES", nullptr);
this->SetPropertyDefault("ANDROID_ANT_ADDITIONAL_OPTIONS", nullptr);
this->SetPropertyDefault("BUILD_RPATH", nullptr);
+ this->SetPropertyDefault("BUILD_RPATH_USE_ORIGIN", nullptr);
this->SetPropertyDefault("INSTALL_NAME_DIR", nullptr);
this->SetPropertyDefault("INSTALL_RPATH", "");
this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF");
diff --git a/Tests/RunCMake/RuntimePath/Relative.cmake b/Tests/RunCMake/RuntimePath/Relative.cmake
new file mode 100644
index 0000000..203241f
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/Relative.cmake
@@ -0,0 +1,69 @@
+enable_language(C)
+
+if(NOT CMAKE_SHARED_LIBRARY_RPATH_ORIGIN_TOKEN)
+ if(CMAKE_C_PLATFORM_ID STREQUAL "Linux")
+ # Sanity check for platform that is definitely known to support $ORIGIN.
+ message(FATAL_ERROR "Platform fails to report relative RPATH support")
+ else()
+ message(STATUS "Platform does not support relative RPATHs, skipping")
+ endif()
+ return()
+endif()
+set(CMAKE_BUILD_RPATH_USE_ORIGIN ON)
+
+function(CheckRpath target rpath)
+ add_custom_command(
+ TARGET ${target}
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -Dfile=$<TARGET_FILE:${target}> -Drpath=${rpath}
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/RelativeCheck.cmake"
+ VERBATIM
+ )
+endfunction()
+
+if(CMAKE_C_COMPILER_ID STREQUAL "XL" AND CMAKE_BINARY_DIR MATCHES " ")
+ # XL 16.1.0.0 fails building the library if the output path contains a space.
+ set(externDir)
+ message(STATUS "Skipping external library test because of a toolchain bug")
+else()
+ get_filename_component(externDir "${CMAKE_BINARY_DIR}" DIRECTORY)
+ set(externDir "${externDir}/Relative-extern")
+endif()
+
+add_library(utils SHARED A.c)
+add_library(utils-sub SHARED A.c)
+set_property(TARGET utils-sub PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/libs)
+if(externDir)
+ add_library(utils-extern SHARED A.c)
+ set_property(TARGET utils-extern PROPERTY LIBRARY_OUTPUT_DIRECTORY ${externDir})
+endif()
+
+add_executable(main main.c)
+target_link_libraries(main utils)
+CheckRpath(main "\$ORIGIN")
+
+add_executable(main-norel main.c)
+target_link_libraries(main-norel utils)
+set_property(TARGET main-norel PROPERTY BUILD_RPATH_USE_ORIGIN OFF)
+CheckRpath(main-norel "${CMAKE_CURRENT_BINARY_DIR}")
+
+add_executable(mainsub main.c)
+target_link_libraries(mainsub utils)
+set_property(TARGET mainsub PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
+CheckRpath(mainsub "\$ORIGIN/../")
+
+add_executable(main-sub main.c)
+target_link_libraries(main-sub utils-sub)
+CheckRpath(main-sub "\$ORIGIN/libs")
+
+add_executable(mainsub-sub main.c)
+target_link_libraries(mainsub-sub utils-sub)
+set_property(TARGET mainsub-sub PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
+CheckRpath(mainsub-sub "\$ORIGIN/../libs")
+
+if(externDir)
+ # Binaries linking to libraries outside the build tree should have an absolute RPATH.
+ add_executable(main-extern main.c)
+ target_link_libraries(main-extern utils-extern)
+ CheckRpath(main-extern "${externDir}")
+endif()
diff --git a/Tests/RunCMake/RuntimePath/RelativeCheck.cmake b/Tests/RunCMake/RuntimePath/RelativeCheck.cmake
new file mode 100644
index 0000000..9ee403f
--- /dev/null
+++ b/Tests/RunCMake/RuntimePath/RelativeCheck.cmake
@@ -0,0 +1,4 @@
+file(RPATH_CHECK FILE "${file}" RPATH "${rpath}")
+if(NOT EXISTS "${file}")
+ message(FATAL_ERROR "RPATH for ${file} did not contain the expected value")
+endif()
diff --git a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
index 3f238f2..6f1baa1 100644
--- a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
+++ b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake
@@ -16,3 +16,17 @@ function(run_SymlinkImplicit)
${CMAKE_COMMAND} -Ddir=${RunCMake_TEST_BINARY_DIR} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
endfunction()
run_SymlinkImplicit()
+
+function(run_Relative)
+ # Use a single build tree for a few tests without cleaning.
+ set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/Relative-build)
+ set(RunCMake_TEST_NO_CLEAN 1)
+ if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
+ set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
+ endif()
+ file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+ file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+ run_cmake(Relative)
+ run_cmake_command(Relative-build ${CMAKE_COMMAND} --build . --config Debug)
+endfunction()
+run_Relative()
diff --git a/Tests/RunCMake/RuntimePath/main.c b/Tests/RunCMake/RuntimePath/main.c
index 8488f4e..181cd09 100644
--- a/Tests/RunCMake/RuntimePath/main.c
+++ b/Tests/RunCMake/RuntimePath/main.c
@@ -1,4 +1,6 @@
+extern int libA(void);
+
int main(void)
{
- return 0;
+ return libA();
}