Commit d29ed8a1 authored by Kyle Edwards's avatar Kyle Edwards

BUILD_RPATH/INSTALL_RPATH: Add generator expression support

Fixes: #19423
parent 1009fd18
......@@ -8,3 +8,6 @@ tree. See also the :prop_tgt:`INSTALL_RPATH` target property.
This property is initialized by the value of the variable
:variable:`CMAKE_BUILD_RPATH` if it is set when a target is created.
This property supports
:manual:`generator expressions <cmake-generator-expressions(7)>`.
......@@ -7,3 +7,6 @@ A semicolon-separated list specifying the rpath to use in installed
targets (for platforms that support it). This property is initialized
by the value of the variable :variable:`CMAKE_INSTALL_RPATH` if it is set when
a target is created.
This property supports
:manual:`generator expressions <cmake-generator-expressions(7)>`.
build-install-rpath-genex
-------------------------
* :prop_tgt:`BUILD_RPATH` and :prop_tgt:`INSTALL_RPATH` now support
:manual:`generator expressions <cmake-generator-expressions(7)>`.
......@@ -1695,7 +1695,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
(for_install ||
this->Target->GetPropertyAsBool("BUILD_WITH_INSTALL_RPATH"));
bool use_install_rpath =
(outputRuntime && this->Target->HaveInstallTreeRPATH() &&
(outputRuntime && this->Target->HaveInstallTreeRPATH(this->Config) &&
linking_for_install);
bool use_build_rpath =
(outputRuntime && this->Target->HaveBuildTreeRPATH(this->Config) &&
......@@ -1715,15 +1715,17 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs,
// Construct the RPATH.
std::set<std::string> emitted;
if (use_install_rpath) {
const char* install_rpath = this->Target->GetProperty("INSTALL_RPATH");
cmCLI_ExpandListUnique(install_rpath, runtimeDirs, emitted);
std::string install_rpath;
this->Target->GetInstallRPATH(this->Config, install_rpath);
cmCLI_ExpandListUnique(install_rpath.c_str(), runtimeDirs, emitted);
}
if (use_build_rpath) {
// Add directories explicitly specified by user
if (const char* build_rpath = this->Target->GetProperty("BUILD_RPATH")) {
std::string build_rpath;
if (this->Target->GetBuildRPATH(this->Config, 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);
cmCLI_ExpandListUnique(build_rpath.c_str(), runtimeDirs, emitted);
}
}
if (use_build_rpath || use_link_rpath) {
......
......@@ -1612,7 +1612,7 @@ bool cmGeneratorTarget::NeedRelinkBeforeInstall(
// will likely change between the build tree and install tree and
// this target must be relinked.
bool have_rpath =
this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH();
this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(config);
bool is_ninja =
this->LocalGenerator->GetGlobalGenerator()->GetName() == "Ninja";
......@@ -5479,13 +5479,41 @@ bool cmGeneratorTarget::ComputePDBOutputDir(const std::string& kind,
return true;
}
bool cmGeneratorTarget::HaveInstallTreeRPATH() const
bool cmGeneratorTarget::HaveInstallTreeRPATH(const std::string& config) const
{
const char* install_rpath = this->GetProperty("INSTALL_RPATH");
return (install_rpath && *install_rpath) &&
std::string install_rpath;
this->GetInstallRPATH(config, install_rpath);
return !install_rpath.empty() &&
!this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH");
}
bool cmGeneratorTarget::GetBuildRPATH(const std::string& config,
std::string& rpath) const
{
return this->GetRPATH(config, "BUILD_RPATH", rpath);
}
bool cmGeneratorTarget::GetInstallRPATH(const std::string& config,
std::string& rpath) const
{
return this->GetRPATH(config, "INSTALL_RPATH", rpath);
}
bool cmGeneratorTarget::GetRPATH(const std::string& config,
const std::string& prop,
std::string& rpath) const
{
const char* value = this->GetProperty(prop);
if (!value) {
return false;
}
cmGeneratorExpression ge;
rpath = ge.Parse(value)->Evaluate(this->LocalGenerator, config);
return true;
}
void cmGeneratorTarget::ComputeLinkInterfaceLibraries(
const std::string& config, cmOptionalLinkInterface& iface,
cmGeneratorTarget const* headTarget, bool usage_requirements_only) const
......@@ -6085,7 +6113,8 @@ bool cmGeneratorTarget::HaveBuildTreeRPATH(const std::string& config) const
if (this->GetPropertyAsBool("SKIP_BUILD_RPATH")) {
return false;
}
if (this->GetProperty("BUILD_RPATH")) {
std::string build_rpath;
if (this->GetBuildRPATH(config, build_rpath)) {
return true;
}
if (cmLinkImplementationLibraries const* impl =
......
......@@ -674,7 +674,10 @@ public:
class TargetPropertyEntry;
bool HaveInstallTreeRPATH() const;
bool HaveInstallTreeRPATH(const std::string& config) const;
bool GetBuildRPATH(const std::string& config, std::string& rpath) const;
bool GetInstallRPATH(const std::string& config, std::string& rpath) const;
/** Whether this library has \@rpath and platform supports it. */
bool HasMacOSXRpathInstallNameDir(const std::string& config) const;
......@@ -913,6 +916,9 @@ private:
ManagedType CheckManagedType(std::string const& propval) const;
bool GetRPATH(const std::string& config, const std::string& prop,
std::string& rpath) const;
public:
const std::vector<const cmGeneratorTarget*>& GetLinkImplementationClosure(
const std::string& config) const;
......
enable_language(C)
add_library(A STATIC A.c)
add_executable(buildge main.c)
target_link_libraries(buildge A)
set_target_properties(buildge PROPERTIES
BUILD_RPATH $<1:/opt/foo/lib>
)
add_executable(buildnoge main.c)
target_link_libraries(buildnoge A)
set_target_properties(buildnoge PROPERTIES
BUILD_RPATH /opt/foo/lib
)
add_executable(installge main.c)
target_link_libraries(installge A)
set_target_properties(installge PROPERTIES
INSTALL_RPATH $<1:/opt/foo/lib>
BUILD_WITH_INSTALL_RPATH 1
)
add_executable(installnoge main.c)
target_link_libraries(installnoge A)
set_target_properties(installnoge PROPERTIES
INSTALL_RPATH /opt/foo/lib
BUILD_WITH_INSTALL_RPATH 1
)
file(GLOB_RECURSE files "${dir}/*")
foreach(file IN LISTS files)
if(file MATCHES "/(build|install)(no)?ge$")
file(RPATH_CHANGE FILE "${file}" OLD_RPATH "/opt/foo/lib" NEW_RPATH "/opt/bar/lib")
endif()
endforeach()
include(RunCMake)
function(run_SymlinkImplicit)
function(run_RuntimePath name)
# Use a single build tree for a few tests without cleaning.
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SymlinkImplicit-build)
set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${name}-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(SymlinkImplicit)
run_cmake_command(SymlinkImplicit-build ${CMAKE_COMMAND} --build . --config Debug)
run_cmake_command(SymlinkImplicitCheck
${CMAKE_COMMAND} -Ddir=${RunCMake_TEST_BINARY_DIR} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
run_cmake(${name})
run_cmake_command(${name}-build ${CMAKE_COMMAND} --build . --config Debug)
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()
run_RuntimePath(SymlinkImplicit)
run_cmake_command(SymlinkImplicitCheck
${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/SymlinkImplicit-build -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake)
run_RuntimePath(Relative)
# FIXME: Run RelativeCheck (appears to be broken currently)
run_RuntimePath(Genex)
run_cmake_command(GenexCheck
${CMAKE_COMMAND} -Ddir=${RunCMake_BINARY_DIR}/Genex-build -P ${RunCMake_SOURCE_DIR}/GenexCheck.cmake)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment