Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMake: honour CMAKE_INSTALL_RPATH for Python bindings (fixes #6371) #6382

Merged
merged 1 commit into from
Sep 20, 2022
Merged
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
9 changes: 8 additions & 1 deletion .github/workflows/cmake_builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,19 @@ jobs:
export LD_LIBRARY_PATH=$GITHUB_WORKSPACE/install-gdal/lib
$GITHUB_WORKSPACE/install-gdal/bin/gdalinfo --version
PYTHONPATH=$GITHUB_WORKSPACE/install-gdal/lib/python3/dist-packages python3 -c "from osgeo import gdal;print(gdal.VersionInfo(None))"
- name: CMake with rpath
run: |
export PATH=$CMAKE_DIR:/usr/local/bin:/usr/bin:/bin # Avoid CMake config from brew etc.
(cd $GITHUB_WORKSPACE/superbuild/build; cmake .. "-DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-gdal-with-rpath" "-DCMAKE_INSTALL_RPATH=$GITHUB_WORKSPACE/install-gdal-with-rpath/lib")
cmake --build $GITHUB_WORKSPACE/superbuild/build --target install -- -j$(nproc)
# For some reason, during the install phase of above invokation, the Python bindings are rebuilt after the build phase, and without the rpath... Can't reproduce that locally
# PYTHONPATH=$GITHUB_WORKSPACE/install-gdal-with-rpath/lib/python3/dist-packages python -c "from osgeo import gdal;print(gdal.VersionInfo(None))"
- name: Rerun using Mono
run: |
export PATH=$CMAKE_DIR:/usr/local/bin:/usr/bin:/bin # Avoid CMake config from brew etc.
cd $GITHUB_WORKSPACE/superbuild/build
rm -rf swig/csharp
cmake ${CMAKE_OPTIONS} -DCSHARP_MONO=ON -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-gdal -DCMAKE_UNITY_BUILD=${CMAKE_UNITY_BUILD} -DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror ..
cmake ${CMAKE_OPTIONS} -DCSHARP_MONO=ON -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-gdal -UCMAKE_INSTALL_RPATH -DCMAKE_UNITY_BUILD=${CMAKE_UNITY_BUILD} -DCMAKE_C_FLAGS=-Werror -DCMAKE_CXX_FLAGS=-Werror ..
cmake --build $GITHUB_WORKSPACE/superbuild/build --target install -- -j$(nproc)
# Below fails with errors like 'System.InvalidProgramException: Invalid IL code in CreateData:Main (string[]): IL_00c4: callvirt 0x0a00000c'
# ctest -V -R "^csharp.*"
Expand Down
3 changes: 3 additions & 0 deletions gdal.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,9 @@ else ()
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}
${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}
)
if( NOT "${CMAKE_INSTALL_PREFIX}" STREQUAL "" )
message(WARNING "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} will be ignored and replaced with ${base};${base}/${relDir} due to GDAL_SET_INSTALL_RELATIVE_RPATH being set")
endif()
set(CMAKE_INSTALL_RPATH ${base} ${base}/${relDir})
endif()
endif ()
Expand Down
60 changes: 57 additions & 3 deletions swig/python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,63 @@ if (Python_Interpreter_FOUND)
OUTPUT ${PY_SO_LIST}
COMMAND ${CMAKE_COMMAND} ${WERROR_DEV_FLAG} -P ${BUILD_EXT_FILENAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${GDAL_LIB_TARGET_NAME} ${GDAL_PYTHON_PYSOURCES} ${GDAL_PYTHON_CSOURCES})
DEPENDS ${GDAL_LIB_TARGET_NAME} ${GDAL_PYTHON_PYSOURCES} ${GDAL_PYTHON_CSOURCES} ${BUILD_EXT_FILENAME})

set(INSTALL_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
set(PY_SO_LIST_WITH_RPATH)
if (NOT ONLY_GENERATE_FOR_NON_DEBUG)
if(${GDAL_SET_INSTALL_RELATIVE_RPATH})
# TODO: we should support that, but that's involved as it requires
# knowing where Python will install the generated .so files
message(WARNING "The Python bindings target does not currently "
"support setting relative RPATH on the Python wrapper "
"shared libraries. "
"Disable GDAL_SET_INSTALL_RELATIVE_RPATH and set "
"an absolute value for CMAKE_INSTALL_RPATH")
elseif(NOT "${CMAKE_INSTALL_RPATH}" STREQUAL "")

# If a CMAKE_INSTALL_RPATH is specified, we need to do a build in a
# dedicated "for_install" subdirectory that adds --rpath to python setup.py build_ext
# and install that one when the "install" target is run
# We cannot set this install rpath to regular build artifacts, to avoid
# inconsistencies.
# This is admitedly quite convoluted because CMake cannot do the usual
# magic of setting/unsetting RPATH on binaries it is not aware of.

set(INSTALL_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/for_install")
file(MAKE_DIRECTORY "${INSTALL_WORKING_DIRECTORY}")
# We need to copy a few things from the build directory to the for_install one:
# the gdal-utils and extensions subdirectories, README.rst, and osgeo/*.py files
file(MAKE_DIRECTORY "${INSTALL_WORKING_DIRECTORY}/osgeo")
symlink_or_copy("${CMAKE_CURRENT_SOURCE_DIR}/gdal-utils" "${INSTALL_WORKING_DIRECTORY}/gdal-utils")
set(BUILD_EXT_WITH_RPATH_CONTENT)
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "configure_file(\"${CMAKE_CURRENT_SOURCE_DIR}/README.rst\" \"${INSTALL_WORKING_DIRECTORY}/README.rst\" @ONLY)\n")
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "file(COPY \"${CMAKE_CURRENT_BINARY_DIR}/extensions\" DESTINATION \"${INSTALL_WORKING_DIRECTORY}\")\n")
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "file(GLOB PY_FILES \"${CMAKE_CURRENT_BINARY_DIR}/osgeo/*.py\")\n")
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "foreach(_file IN LISTS PY_FILES)\n")
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT " file(COPY \"\${_file}\" DESTINATION \"${INSTALL_WORKING_DIRECTORY}/osgeo\")\n")
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "endforeach()\n")
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "execute_process(COMMAND ${Python_EXECUTABLE} ${SETUP_PY_FILENAME} build_ext --rpath=${CMAKE_INSTALL_RPATH} --inplace --force WORKING_DIRECTORY ${INSTALL_WORKING_DIRECTORY})\n")

foreach (f IN LISTS PY_SO_LIST)
list(APPEND PY_SO_LIST_WITH_RPATH "${INSTALL_WORKING_DIRECTORY}/${f}")
if (CMAKE_VERSION VERSION_GREATER 3.12)
string(APPEND BUILD_EXT_WITH_RPATH_CONTENT "file(TOUCH_NOCREATE \"${INSTALL_WORKING_DIRECTORY}/${f}\")\n")
endif ()
endforeach ()

set(BUILD_EXT_WITH_RPATH_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/build_ext_with_rpath.cmake)
file(WRITE ${BUILD_EXT_WITH_RPATH_FILENAME} "${BUILD_EXT_WITH_RPATH_CONTENT}")
add_custom_command(
OUTPUT ${PY_SO_LIST_WITH_RPATH}
COMMAND ${CMAKE_COMMAND} ${WERROR_DEV_FLAG} -P ${BUILD_EXT_WITH_RPATH_FILENAME}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${GDAL_LIB_TARGET_NAME} ${GDAL_PYTHON_PYSOURCES} ${GDAL_PYTHON_CSOURCES} ${BUILD_EXT_WITH_RPATH_FILENAME})

endif()
endif()

add_custom_target(python_binding ALL DEPENDS ${PY_SO_LIST} ${GDAL_PYTHON_PYSOURCES} ${GDAL_LIB_TARGET_NAME})
add_custom_target(python_binding ALL DEPENDS ${PY_SO_LIST} ${PY_SO_LIST_WITH_RPATH} ${GDAL_PYTHON_PYSOURCES} ${GDAL_LIB_TARGET_NAME})

# Generate wheel
if (ONLY_GENERATE_FOR_NON_DEBUG)
Expand Down Expand Up @@ -395,7 +449,7 @@ if (Python_Interpreter_FOUND)
@ONLY)
install(
CODE "execute_process(COMMAND ${CMAKE_COMMAND} ${WERROR_DEV_FLAG} -P ${CMAKE_CURRENT_BINARY_DIR}/install_python.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
WORKING_DIRECTORY ${INSTALL_WORKING_DIRECTORY})")

endif ()

Expand Down