From 12d0495d7518b028da9f8ab291981d0b33c36b11 Mon Sep 17 00:00:00 2001 From: mohammad shariq Date: Sat, 28 Mar 2026 01:50:35 +0530 Subject: [PATCH 1/2] build: implement unified RPath patching API for Darwin and Linux --- cmake/PatchRPath.cmake | 66 ++++++++++++++++++++ source/loaders/rs_loader/rust/CMakeLists.txt | 42 ++++--------- 2 files changed, 77 insertions(+), 31 deletions(-) create mode 100644 cmake/PatchRPath.cmake diff --git a/cmake/PatchRPath.cmake b/cmake/PatchRPath.cmake new file mode 100644 index 0000000000..d1e7ad6f81 --- /dev/null +++ b/cmake/PatchRPath.cmake @@ -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 +# +# 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/ && -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() diff --git a/source/loaders/rs_loader/rust/CMakeLists.txt b/source/loaders/rs_loader/rust/CMakeLists.txt index 7f0fbb3719..48faa52069 100644 --- a/source/loaders/rs_loader/rust/CMakeLists.txt +++ b/source/loaders/rs_loader/rust/CMakeLists.txt @@ -55,37 +55,17 @@ 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) -else() - # TODO: Implement patchelf equivalent (if needed) for other platforms - set(RUSTC_LIBS ${Rust_RUSTC_LIBRARIES}) -endif() +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() + +add_custom_target(${target}_rpath DEPENDS ${target}_runtime) +metacall_patch_rpath(${target}_rpath "${RUSTC_LIBS}" "${PROJECT_OUTPUT_DIR}") +set(TARGET_DEPENDENCY ${target}_rpath) 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 From 9d5759c5888d9b8ed0862434591a4bec7763b7b2 Mon Sep 17 00:00:00 2001 From: mohammad shariq Date: Sat, 28 Mar 2026 02:34:17 +0530 Subject: [PATCH 2/2] build: finalize unified rpath api and fix darwin linker flags --- source/loaders/rs_loader/rust/.cargo/config | 2 +- .../loaders/rs_loader/rust/.cargo/config.in | 3 +++ source/loaders/rs_loader/rust/CMakeLists.txt | 23 +++++++++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 source/loaders/rs_loader/rust/.cargo/config.in diff --git a/source/loaders/rs_loader/rust/.cargo/config b/source/loaders/rs_loader/rust/.cargo/config index c3920ae7c8..6d4959e395 100644 --- a/source/loaders/rs_loader/rust/.cargo/config +++ b/source/loaders/rs_loader/rust/.cargo/config @@ -1,3 +1,3 @@ parallel-compiler = true [build] -rustflags = ["-C", "link-args=-Wl,-rpath=$ORIGIN"] +rustflags = ["-C", "link-args=-Wl,-undefined,dynamic_lookup"] diff --git a/source/loaders/rs_loader/rust/.cargo/config.in b/source/loaders/rs_loader/rust/.cargo/config.in new file mode 100644 index 0000000000..585b386c53 --- /dev/null +++ b/source/loaders/rs_loader/rust/.cargo/config.in @@ -0,0 +1,3 @@ +parallel-compiler = true +[build] +rustflags = [@CARGO_RUSTFLAGS@] diff --git a/source/loaders/rs_loader/rust/CMakeLists.txt b/source/loaders/rs_loader/rust/CMakeLists.txt index 48faa52069..9538fbc041 100644 --- a/source/loaders/rs_loader/rust/CMakeLists.txt +++ b/source/loaders/rs_loader/rust/CMakeLists.txt @@ -55,6 +55,20 @@ add_custom_target(${target}_runtime COMMAND ${CMAKE_COMMAND} -E copy_if_different ${Rust_RUSTC_LIBRARIES} ${PROJECT_OUTPUT_DIR} ) +# 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() + 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) @@ -63,9 +77,10 @@ foreach(rustc_lib ${Rust_RUSTC_LIBRARIES}) list(APPEND RUSTC_LIBS "${PROJECT_OUTPUT_DIR}/${rustc_lib_name}") endforeach() -add_custom_target(${target}_rpath DEPENDS ${target}_runtime) -metacall_patch_rpath(${target}_rpath "${RUSTC_LIBS}" "${PROJECT_OUTPUT_DIR}") -set(TARGET_DEPENDENCY ${target}_rpath) +# 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 @@ -78,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}