From 33057a4a3c5aa28ff60f01a6949ad38289b4764b Mon Sep 17 00:00:00 2001 From: Ayaz Salikhov Date: Mon, 15 Jun 2026 14:48:08 +0100 Subject: [PATCH] build: Add PatchNixBinary util to make it easier to patch binaries --- .gersemi/definitions.cmake | 3 + .../workflows/reusable-build-test-config.yml | 7 --- CMakeLists.txt | 2 + cmake/PatchNixBinary.cmake | 55 +++++++++++++++++++ cmake/XrplCore.cmake | 1 + src/tests/libxrpl/CMakeLists.txt | 1 + tests/conan/CMakeLists.txt | 1 + 7 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 cmake/PatchNixBinary.cmake diff --git a/.gersemi/definitions.cmake b/.gersemi/definitions.cmake index 245f827f90a..58bc74c70a6 100644 --- a/.gersemi/definitions.cmake +++ b/.gersemi/definitions.cmake @@ -96,3 +96,6 @@ function(verbose_find_path variable name) ${ARGN} ) endfunction() + +function(patch_nix_binary target) +endfunction() diff --git a/.github/workflows/reusable-build-test-config.yml b/.github/workflows/reusable-build-test-config.yml index 8cb5f8c46af..5da6cd639d0 100644 --- a/.github/workflows/reusable-build-test-config.yml +++ b/.github/workflows/reusable-build-test-config.yml @@ -203,13 +203,6 @@ jobs: --parallel "${BUILD_NPROC}" \ --target "${CMAKE_TARGET}" - # This step is needed to allow running in non-Nix environments - - name: Patch binary to use default loader and remove rpath (Linux) - if: ${{ runner.os == 'Linux' && env.SANITIZERS_ENABLED == 'false' }} - run: | - loader="$(/tmp/loader-path.sh)" - patchelf --set-interpreter "${loader}" --remove-rpath "${{ env.BUILD_DIR }}/xrpld" - # We're only running aarch64 Linux builds in Ubuntu-based images, so this is kept simple - name: Install libatomic (Linux aarch64) if: ${{ runner.os == 'Linux' && runner.arch == 'ARM64' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dbe60a220e..bdc62442b3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,8 @@ if(target) ) endif() +include(PatchNixBinary) + include(XrplSanity) include(XrplVersion) include(XrplSettings) diff --git a/cmake/PatchNixBinary.cmake b/cmake/PatchNixBinary.cmake new file mode 100644 index 00000000000..c6355fefce4 --- /dev/null +++ b/cmake/PatchNixBinary.cmake @@ -0,0 +1,55 @@ +#[===================================================================[ + Patch executables to run in non-Nix environments. + + The Nix-based CI image links binaries against an ELF interpreter (loader) + that lives in the Nix store, so the resulting binaries don't run elsewhere + (including once installed from the .deb package). `patch_nix_binary` adds a + POST_BUILD step that resets the interpreter to the system default loader and + drops the rpath. + + This is only active inside the Nix-based image, detected by the presence of + /tmp/loader-path.sh (shipped by that image, resolves the default loader). It + is skipped for sanitizer builds, whose runtime libraries are resolved through + the rpath. Everywhere else `patch_nix_binary` is a no-op. +#]===================================================================] + +include_guard(GLOBAL) + +# Provided by the Nix-based CI image; prints the system default ELF loader path. +set(_loader_path_script "/tmp/loader-path.sh") + +if( + CMAKE_SYSTEM_NAME STREQUAL "Linux" + AND NOT SANITIZERS_ENABLED + AND EXISTS "${_loader_path_script}" +) + execute_process( + COMMAND "${_loader_path_script}" + OUTPUT_VARIABLE DEFAULT_LOADER_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + find_program(PATCHELF_COMMAND patchelf REQUIRED) + set(PATCH_NIX_BINARIES TRUE) + message( + STATUS + "Binaries will be patched to use loader '${DEFAULT_LOADER_PATH}'" + ) +else() + set(PATCH_NIX_BINARIES FALSE) +endif() + +function(patch_nix_binary target) + if(NOT PATCH_NIX_BINARIES) + return() + endif() + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND + "${PATCHELF_COMMAND}" --set-interpreter "${DEFAULT_LOADER_PATH}" + --remove-rpath "$" + COMMENT "Patching ${target}: set default loader, remove rpath" + VERBATIM + ) +endfunction() diff --git a/cmake/XrplCore.cmake b/cmake/XrplCore.cmake index 52d7714a99e..4d4a800d9a0 100644 --- a/cmake/XrplCore.cmake +++ b/cmake/XrplCore.cmake @@ -247,6 +247,7 @@ target_link_modules( if(xrpld) add_executable(xrpld) + patch_nix_binary(xrpld) if(tests) target_compile_definitions(xrpld PUBLIC ENABLE_TESTS) target_compile_definitions( diff --git a/src/tests/libxrpl/CMakeLists.txt b/src/tests/libxrpl/CMakeLists.txt index 2dae6fccb98..bd56028728a 100644 --- a/src/tests/libxrpl/CMakeLists.txt +++ b/src/tests/libxrpl/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable( helpers/TestSink.cpp helpers/TxTest.cpp ) +patch_nix_binary(xrpl_tests) set_target_properties( xrpl_tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" diff --git a/tests/conan/CMakeLists.txt b/tests/conan/CMakeLists.txt index 871c4c60c01..8e7ba8ed101 100644 --- a/tests/conan/CMakeLists.txt +++ b/tests/conan/CMakeLists.txt @@ -8,5 +8,6 @@ project(${name} VERSION ${version} LANGUAGES CXX) find_package(xrpl CONFIG REQUIRED) add_executable(example) +patch_nix_binary(example) target_sources(example PRIVATE src/example.cpp) target_link_libraries(example PRIVATE xrpl::libxrpl)