Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions cmake/PatchRPath.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# CMake PatchRPath by Parra Studios
# Unified RPath patching for ELF (patchelf) and Mach-O (install_name_tool).
#
# Copyright (C) 2016 - 2026 Vicente Eduardo Ferrer Garcia <vic798@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

include_guard(GLOBAL)

# metacall_patch_rpath(TARGET_NAME LIBRARIES OUTPUT_DIR)
#
# Attach POST_BUILD commands to TARGET_NAME that fix the rpath of each library
# in LIBRARIES so sibling libraries resolve relative to the binary's location.
#
# On macOS: install_name_tool -id @rpath/<basename> && -add_rpath @loader_path
# On Linux: patchelf --set-rpath $ORIGIN

function(metacall_patch_rpath TARGET_NAME LIBRARIES OUTPUT_DIR)
if(APPLE)
find_program(INSTALL_NAME_TOOL_EXECUTABLE NAMES install_name_tool)

if(NOT INSTALL_NAME_TOOL_EXECUTABLE)
message(WARNING "install_name_tool not found, skipping Mach-O rpath patching for ${TARGET_NAME}")
return()
endif()

foreach(lib_path ${LIBRARIES})
get_filename_component(lib_basename "${lib_path}" NAME)

add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${INSTALL_NAME_TOOL_EXECUTABLE}" -id "@rpath/${lib_basename}" "${lib_path}"
COMMAND "${INSTALL_NAME_TOOL_EXECUTABLE}" -add_rpath @loader_path "${lib_path}"
COMMENT "Applying Mach-O rpath fixes for ${lib_basename}"
)
endforeach()

elseif(PROJECT_OS_FAMILY MATCHES "unix")
find_package(Patchelf)

if(NOT Patchelf_FOUND)
message(WARNING "patchelf not found, skipping ELF rpath patching for ${TARGET_NAME}")
return()
endif()

foreach(lib_path ${LIBRARIES})
get_filename_component(lib_basename "${lib_path}" NAME)

add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
COMMAND "${Patchelf_EXECUTABLE}" --set-rpath "$ORIGIN" "${lib_path}"
COMMENT "Applying ELF rpath fixes for ${lib_basename}"
)
endforeach()
endif()
endfunction()
2 changes: 1 addition & 1 deletion source/loaders/rs_loader/rust/.cargo/config
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
parallel-compiler = true
[build]
rustflags = ["-C", "link-args=-Wl,-rpath=$ORIGIN"]
rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"]
3 changes: 3 additions & 0 deletions source/loaders/rs_loader/rust/.cargo/config.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
parallel-compiler = true
[build]
rustflags = [@CARGO_RUSTFLAGS@]
55 changes: 25 additions & 30 deletions source/loaders/rs_loader/rust/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,38 +55,33 @@ add_custom_target(${target}_runtime
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${Rust_RUSTC_LIBRARIES} ${PROJECT_OUTPUT_DIR}
)

# On Linux, execute patchelf in order to patch rpath in the dependencies
if(PROJECT_OS_FAMILY MATCHES "unix" OR PROJECT_OS_FAMILY MATCHES "macos")
# Find Patchelf
find_package(Patchelf)

if(NOT Patchelf_FOUND)
include(InstallPatchelf)

if(NOT Patchelf_FOUND)
message(SEND_ERROR "Patchelf not found")
return()
endif()

set(TARGET_INSTALL_DEPENDENCY Patchelf)
endif()

set(RUSTC_LIBS)
add_custom_target(${target}_patchelf DEPENDS ${target}_runtime ${TARGET_INSTALL_DEPENDENCY})
foreach(rustc_lib ${Rust_RUSTC_LIBRARIES})
get_filename_component(rustc_lib_name ${rustc_lib} NAME)
list(APPEND RUSTC_LIBS ${PROJECT_OUTPUT_DIR}/${rustc_lib_name})
add_custom_command(TARGET ${target}_patchelf POST_BUILD
COMMAND ${Patchelf_EXECUTABLE} --set-rpath [=["\$$ORIGIN"]=] ${PROJECT_OUTPUT_DIR}/${rustc_lib_name}
)
endforeach()

set(TARGET_DEPENDENCY ${target}_patchelf)
# Darwin: allow undefined metacall symbols (resolved at runtime via dynamic_lookup)
# Linux: embed $ORIGIN rpath so sibling libraries resolve at load time
if(APPLE)
set(CARGO_RUSTFLAGS "\"-C\", \"link-args=-Wl,-undefined,dynamic_lookup\"")
else()
# TODO: Implement patchelf equivalent (if needed) for other platforms
set(RUSTC_LIBS ${Rust_RUSTC_LIBRARIES})
set(CARGO_RUSTFLAGS "\"-C\", \"link-args=-Wl,-rpath,$ORIGIN\"")
endif()

configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/.cargo/config.in"
"${CMAKE_CURRENT_SOURCE_DIR}/.cargo/config"
@ONLY
)

include(PatchRPath)

set(RUSTC_LIBS)
foreach(rustc_lib ${Rust_RUSTC_LIBRARIES})
get_filename_component(rustc_lib_name "${rustc_lib}" NAME)
list(APPEND RUSTC_LIBS "${PROJECT_OUTPUT_DIR}/${rustc_lib_name}")
endforeach()

# Patching runs after cargo build, not before
set(PATCH_LIBS "${TARGET_OUTPUT}" ${RUSTC_LIBS})
add_custom_target(${target}_rpath ALL DEPENDS ${target})
metacall_patch_rpath(${target}_rpath "${PATCH_LIBS}" "${PROJECT_OUTPUT_DIR}")

if(OPTION_BUILD_MUSL)
set(RUST_CTR_STATIC "-Ctarget-feature=-crt-static -Clink-self-contained=off -L/usr/lib/x86_64-linux-musl") #-Clink-args=--dynamic-linker /lib/ld-musl-x86_64.so.1
set(RUSTFLAGS ${CMAKE_COMMAND} -E env RUSTFLAGS=${RUST_CTR_STATIC})
Expand All @@ -98,7 +93,7 @@ add_custom_target(${target} ALL
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${RUSTFLAGS} ${Rust_CARGO_EXECUTABLE} build ${TARGET_BUILD_TYPE}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_BUILD_PATH} ${TARGET_OUTPUT}
DEPENDS ${target}_runtime ${TARGET_DEPENDENCY}
DEPENDS ${target}_runtime
)

set_property(TARGET ${target}
Expand Down
Loading