From fc38bf30471421421d0acb55d8952f4c230f0245 Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Fri, 14 Nov 2025 00:07:38 +0100 Subject: [PATCH 1/2] [CMake] Add path to Fortran libraries to RPATH for h2root on macOS So far, we have only solved this problem by adding the path to `DYLD_LIBRARY_PATH` when running the test, but this is not a complete solution, as the libraries won't be found automatically if this is not set. That affects in particular the users that want to use `h2root` from the install tree. Using the RPATH mechanism is more appropriate here. --- hist/hbook/CMakeLists.txt | 14 ++++++++++++++ main/CMakeLists.txt | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/hist/hbook/CMakeLists.txt b/hist/hbook/CMakeLists.txt index 3a34254435f2e..75ca4b0b2c2b9 100644 --- a/hist/hbook/CMakeLists.txt +++ b/hist/hbook/CMakeLists.txt @@ -31,3 +31,17 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Hbook TreePlayer RIO ) + +# This is needed in particular for macOS, where the path of the GNU Fortran +# library might not be in the default DYLD_LIBRARY_PATH, but it gets picked +# up with enable_language(Fortran). +if(APPLE AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + # Compute path to quadmath + execute_process( + COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.dylib + OUTPUT_VARIABLE LIBGFORTRAN_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + get_filename_component(LIBGFORTRAN_DIR "${LIBGFORTRAN_PATH}" DIRECTORY) + set_property(TARGET Hbook APPEND PROPERTY BUILD_RPATH "${LIBGFORTRAN_DIR}") + set_property(TARGET Hbook APPEND PROPERTY INSTALL_RPATH "${LIBGFORTRAN_DIR}") +endif() diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 0a35172a60050..98e50fd87e853 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -55,6 +55,20 @@ if(fortran AND CMAKE_Fortran_COMPILER) ROOT_EXECUTABLE(g2root g2root.f LIBRARIES minicern CMAKENOEXPORT) set_target_properties(g2root PROPERTIES COMPILE_FLAGS "-w") ROOT_EXECUTABLE(h2root h2root.cxx LIBRARIES Core RIO Net Hist Graf Graf3d Gpad Tree Matrix MathCore Thread minicern CMAKENOEXPORT) + + # This is needed in particular for macOS, where the path of the GNU Fortran + # library might not be in the default DYLD_LIBRARY_PATH, but it gets picked + # up with enable_language(Fortran). + if(APPLE AND CMAKE_Fortran_COMPILER_ID STREQUAL "GNU") + # Compute path to quadmath + execute_process( + COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.dylib + OUTPUT_VARIABLE LIBGFORTRAN_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + get_filename_component(LIBGFORTRAN_DIR "${LIBGFORTRAN_PATH}" DIRECTORY) + set_property(TARGET h2root APPEND PROPERTY BUILD_RPATH "${LIBGFORTRAN_DIR}") + set_property(TARGET h2root APPEND PROPERTY INSTALL_RPATH "${LIBGFORTRAN_DIR}") + endif() endif() file(GLOB utils RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} python/root*) From ca5317f867f8088c11f84508d1c36a813409c37a Mon Sep 17 00:00:00 2001 From: Jonas Rembser Date: Thu, 13 Nov 2025 00:39:56 +0100 Subject: [PATCH 2/2] [CMake] Don't set LD_LIBRARY_PATH in test macros This should not be needed anymore because of the runpath mechanism, and by leaving it out from the test environment we are making sure that this keeps working. --- CMakeLists.txt | 5 ++--- bindings/tpython/test/CMakeLists.txt | 2 -- cmake/modules/RootMacros.cmake | 10 ++-------- roottest/CMakeLists.txt | 20 +------------------ .../ntuple/makeproject/rntuple/CMakeLists.txt | 11 +--------- .../ntuple/makeproject/ttree/CMakeLists.txt | 12 ++--------- tutorials/CMakeLists.txt | 1 - 7 files changed, 8 insertions(+), 53 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd226232cfca2..e6af6274dd623 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -556,8 +556,7 @@ if(runtime_cxxmodules) set(modules_idx_cmd COMMAND ${CMAKE_COMMAND} -E env PATH="${library_output_dir}\\\;%PATH%" ROOTIGNOREPREFIX=1 ROOT_HIST=0 $ -l -q -b) else() - set(modules_idx_cmd COMMAND ${ld_library_path}=${library_output_dir}:$ENV{${ld_library_path}} - ROOT_INCLUDE_PATH=${DEFAULT_ROOT_INCLUDE_PATH} + set(modules_idx_cmd COMMAND ROOT_INCLUDE_PATH=${DEFAULT_ROOT_INCLUDE_PATH} ROOTIGNOREPREFIX=1 ROOT_HIST=0 $ -l -q -b) endif() add_custom_command(OUTPUT ${library_output_dir}/modules.idx @@ -582,7 +581,7 @@ if(WIN32) ROOT_INCLUDE_PATH=${DEFAULT_ROOT_INCLUDE_PATH} ROOTIGNOREPREFIX=1 ROOT_HIST=0 $ -l -q -b -n -x ${CMAKE_SOURCE_DIR}/tutorials/hsimple.C -e return) else() - set(hsimple_cmd COMMAND ROOT_INCLUDE_PATH=${DEFAULT_ROOT_INCLUDE_PATH} ${ld_library_path}=${CMAKE_LIBRARY_OUTPUT_DIRECTORY}:$ENV{${ld_library_path}} + set(hsimple_cmd COMMAND ROOT_INCLUDE_PATH=${DEFAULT_ROOT_INCLUDE_PATH} ROOTIGNOREPREFIX=1 ROOT_HIST=0 $ -l -q -b -n -x ${CMAKE_SOURCE_DIR}/tutorials/hsimple.C -e return) endif() add_custom_command(OUTPUT tutorials/hsimple.root diff --git a/bindings/tpython/test/CMakeLists.txt b/bindings/tpython/test/CMakeLists.txt index e2d313f7d4986..f56b36306cfa5 100644 --- a/bindings/tpython/test/CMakeLists.txt +++ b/bindings/tpython/test/CMakeLists.txt @@ -14,8 +14,6 @@ if(MSVC) PYTHONPATH=${ROOTSYS}/bin;$ENV{PYTHONPATH}) else() set(tpython_gtest_env - PATH=${ROOTSYS}/bin:$ENV{PATH} - LD_LIBRARY_PATH=${ROOTSYS}/lib:$ENV{LD_LIBRARY_PATH} PYTHONPATH=${ROOTSYS}/lib:$ENV{PYTHONPATH}) endif() diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 6c2f8f7a6bd6f..d06a0fcb6440c 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -1884,7 +1884,6 @@ function(ROOT_ADD_PYUNITTESTS name) else() set(ROOT_ENV PATH=${ROOTSYS}/bin:$ENV{PATH} - ${ld_library_path}=${ROOTSYS}/lib:$ENV{${ld_library_path}} PYTHONPATH=${ROOTSYS}/lib:$ENV{PYTHONPATH}) endif() string(REGEX REPLACE "[_]" "-" good_name "${name}") @@ -1910,7 +1909,6 @@ function(ROOT_ADD_PYUNITTEST name file) else() set(ROOT_ENV PATH=${ROOTSYS}/bin:$ENV{PATH} - ${ld_library_path}=${ROOTSYS}/lib:$ENV{${ld_library_path}} PYTHONPATH=${ROOTSYS}/lib:$ENV{PYTHONPATH}) endif() string(REGEX REPLACE "[_]" "-" good_name "${name}") @@ -3130,15 +3128,13 @@ function(ROOTTEST_ADD_TEST testname) else() string(REPLACE ";" ":" _path "${ROOTTEST_ENV_PATH}") string(REPLACE ";" ":" _pythonpath "${ROOTTEST_ENV_PYTHONPATH}") - string(REPLACE ";" ":" _librarypath "${ROOTTEST_ENV_LIBRARYPATH}") set(environment ENVIRONMENT ${ROOTTEST_ENV_EXTRA} ${ARG_ENVIRONMENT} PATH=${_path}:$ENV{PATH} - PYTHONPATH=${_pythonpath}:$ENV{PYTHONPATH} - ${ld_library_path}=${_librarypath}:$ENV{${ld_library_path}}) + PYTHONPATH=${_pythonpath}:$ENV{PYTHONPATH}) endif() if(ARG_WORKING_DIR) @@ -3383,15 +3379,13 @@ function(ROOTTEST_ADD_UNITTEST_DIR) else() string(REPLACE ";" ":" _path "${ROOTTEST_ENV_PATH}") string(REPLACE ";" ":" _pythonpath "${ROOTTEST_ENV_PYTHONPATH}") - string(REPLACE ";" ":" _librarypath "${ROOTTEST_ENV_LIBRARYPATH}") set(environment ENVIRONMENT ${ROOTTEST_ENV_EXTRA} ${ARG_ENVIRONMENT} PATH=${_path}:$ENV{PATH} - PYTHONPATH=${_pythonpath}:$ENV{PYTHONPATH} - ${ld_library_path}=${_librarypath}:$ENV{${ld_library_path}}) + PYTHONPATH=${_pythonpath}:$ENV{PYTHONPATH}) endif() ROOT_ADD_TEST(${fulltestname} COMMAND ${binary} diff --git a/roottest/CMakeLists.txt b/roottest/CMakeLists.txt index 4f009fef75cf9..2ce0eda3549b0 100644 --- a/roottest/CMakeLists.txt +++ b/roottest/CMakeLists.txt @@ -230,25 +230,8 @@ if(MSVC) else() set(ROOTTEST_ENV_PYTHONPATH ${ROOT_LIBRARY_DIR}) endif() -set(ROOTTEST_ENV_LIBRARYPATH ${ROOT_LIBRARY_DIR}) set(ROOTTEST_ENV_EXTRA) -# Optionally, add Fortran link directories. This is needed in particular for -# macOS, where the path of the Fortran library might not be in the default -# DYLD_LIBRARY_PATH, but it gets picked up with enable_language(Fortran). -if(APPLE AND fortran) - # Convert Fortran link dirs to colon-separated string - string(REPLACE ";" ":" FORTRAN_LINK_PATH "${CMAKE_Fortran_IMPLICIT_LINK_DIRECTORIES}") - - # Append to ROOTTEST_ENV_LIBRARYPATH - set(ROOTTEST_ENV_LIBRARYPATH "${ROOTTEST_ENV_LIBRARYPATH}:${FORTRAN_LINK_PATH}") - - # Deduplicate ROOTTEST_ENV_LIBRARYPATH - string(REPLACE ":" ";" _tmp "${ROOTTEST_ENV_LIBRARYPATH}") - list(REMOVE_DUPLICATES _tmp) - string(REPLACE ";" ":" ROOTTEST_ENV_LIBRARYPATH "${_tmp}") -endif() - if(MSVC) set(ROOTTEST_ENVIRONMENT PYTHONPATH=${ROOTTEST_ENV_PYTHONPATH}) @@ -257,8 +240,7 @@ else() string(REGEX REPLACE ":$" "" TESTPYTHONPATH "${ROOTTEST_ENV_PYTHONPATH}:$ENV{PYTHONPATH}") set(ROOTTEST_ENVIRONMENT PATH=${ROOTTEST_ENV_PATH}:$ENV{PATH} - PYTHONPATH=${TESTPYTHONPATH} - ${ld_library_path}=${ROOTTEST_ENV_LIBRARYPATH}:$ENV{${ld_library_path}}) + PYTHONPATH=${TESTPYTHONPATH}) if (gnuinstall) set(ROOTTEST_ENVIRONMENT ${ROOTTEST_ENVIRONMENT} ROOTIGNOREPREFIX=1) endif() diff --git a/roottest/root/ntuple/makeproject/rntuple/CMakeLists.txt b/roottest/root/ntuple/makeproject/rntuple/CMakeLists.txt index 6350493a69afc..f5c14200eb2e0 100644 --- a/roottest/root/ntuple/makeproject/rntuple/CMakeLists.txt +++ b/roottest/root/ntuple/makeproject/rntuple/CMakeLists.txt @@ -53,17 +53,8 @@ target_link_directories(read_rntuple PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/librntu # Need to also explicitly set the LD_LIBRARY_PATH (at least on MacOS), so that # the generated library with the custom class can be loaded by the read test. -# Setting the value of ${ld_library_path} in the ENVIRONMENT argument of the -# ROOTTEST_ADD_TEST function will not work, because that function sets the same -# variable internally, thus overriding our choice. The simplest thing to do is -# to append our directory to the ${ROOTTEST_ENV_LIBRARYPATH} contents, which -# are automatically used by ROOTTEST_ADD_TEST -set(_roottest_env_librarypath ${ROOTTEST_ENV_LIBRARYPATH}) -set(ROOTTEST_ENV_LIBRARYPATH "${ROOTTEST_ENV_LIBRARYPATH}:${CMAKE_CURRENT_BINARY_DIR}/librntuplestltest") ROOTTEST_ADD_TEST(read_rntuple EXEC ./read_rntuple FIXTURES_REQUIRED read_rntuple_executable # PATH is used on Windows to find libraries for loading - ENVIRONMENT PATH=${CMAKE_CURRENT_BINARY_DIR}/librntuplestltest) -set(ROOTTEST_ENV_LIBRARYPATH ${_roottest_env_librarypath}) - + ENVIRONMENT ${ld_library_path}=${CMAKE_CURRENT_BINARY_DIR}/librntuplestltest) diff --git a/roottest/root/ntuple/makeproject/ttree/CMakeLists.txt b/roottest/root/ntuple/makeproject/ttree/CMakeLists.txt index afe03634fd858..4787ee6e526a7 100644 --- a/roottest/root/ntuple/makeproject/ttree/CMakeLists.txt +++ b/roottest/root/ntuple/makeproject/ttree/CMakeLists.txt @@ -54,16 +54,8 @@ target_link_directories(read_ttree PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/libttrees # Need to also explicitly set the LD_LIBRARY_PATH (at least on MacOS), so that # the generated library with the custom class can be loaded by the read test. -# Setting the value of ${ld_library_path} in the ENVIRONMENT argument of the -# ROOTTEST_ADD_TEST function will not work, because that function sets the same -# variable internally, thus overriding our choice. The simplest thing to do is -# to append our directory to the ${ROOTTEST_ENV_LIBRARYPATH} contents, which -# are automatically used by ROOTTEST_ADD_TEST -set(_roottest_env_librarypath ${ROOTTEST_ENV_LIBRARYPATH}) -set(ROOTTEST_ENV_LIBRARYPATH "${ROOTTEST_ENV_LIBRARYPATH}:${CMAKE_CURRENT_BINARY_DIR}/libttreestltest") ROOTTEST_ADD_TEST(read_ttree EXEC ./read_ttree - FIXTURES_REQUIRED makeproject_read_ttree_executable + FIXTURES_REQUIRED makeproject_read_ttree_executable # PATH is used on Windows to find libraries for loading - ENVIRONMENT PATH=${CMAKE_CURRENT_BINARY_DIR}/libttreestltest) -set(ROOTTEST_ENV_LIBRARYPATH ${_roottest_env_librarypath}) + ENVIRONMENT ${ld_library_path}=${CMAKE_CURRENT_BINARY_DIR}/libttreestltest) diff --git a/tutorials/CMakeLists.txt b/tutorials/CMakeLists.txt index 0a8ea310234bd..4320a5104be84 100644 --- a/tutorials/CMakeLists.txt +++ b/tutorials/CMakeLists.txt @@ -18,7 +18,6 @@ if(DEFINED ROOT_SOURCE_DIR) # Testing using the binary tree set(ROOT_root_CMD root.exe) if(NOT MSVC) # Ignore environment on Windows set(ROOT_environ PATH=${CMAKE_BINARY_DIR}/bin:$ENV{PATH} - ${ld_library_path}=${CMAKE_BINARY_DIR}/lib:$ENV{${ld_library_path}} ROOT_INCLUDE_PATH=${CMAKE_BINARY_DIR}/tutorials/io/tree:${DEFAULT_ROOT_INCLUDE_PATH} PYTHONPATH=${CMAKE_BINARY_DIR}/lib:$ENV{PYTHONPATH}) else()