diff options
-rw-r--r-- | Help/manual/cmake-properties.7.rst | 1 | ||||
-rw-r--r-- | Help/manual/cmake-variables.7.rst | 1 | ||||
-rw-r--r-- | Help/prop_tgt/BUILD_RPATH_USE_ORIGIN.rst | 24 | ||||
-rw-r--r-- | Help/release/dev/relative-rpath.rst | 8 | ||||
-rw-r--r-- | Help/variable/CMAKE_BUILD_RPATH_USE_ORIGIN.rst | 7 | ||||
-rw-r--r-- | Modules/Platform/Linux.cmake | 1 | ||||
-rw-r--r-- | Source/cmComputeLinkInformation.cxx | 29 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 1 | ||||
-rw-r--r-- | Tests/RunCMake/RuntimePath/Relative.cmake | 69 | ||||
-rw-r--r-- | Tests/RunCMake/RuntimePath/RelativeCheck.cmake | 4 | ||||
-rw-r--r-- | Tests/RunCMake/RuntimePath/RunCMakeTest.cmake | 14 | ||||
-rw-r--r-- | Tests/RunCMake/RuntimePath/main.c | 4 |
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(); } |