build: Tell cmake to set 'rpath' intelligently

Before this commit, when QPDF's products were installed in an
unorthodox location, it was possible for one of the executable
products not to be able to find the necessary library product
(i.e., the necessary 'libqpdf'); that is, an executable didn't
inform the dynamic linker where to look. For example:

  $ ldd /path/to/installed/files/bin/qpdf
          linux-gate.so.1 (0xb7ee6000)
          libqpdf.so.29 => not found
          [...]

Now, because of this commit, an executable's 'rpath' setting
(or equivalent) is set upon installation, thereby providing the
required search directory:

  $ ldd /path/to/installed/files/bin/qpdf
          linux-gate.so.1 (0xb7ee6000)
          libqpdf.so.29 => /path/to/installed/files/lib/libqpdf.so.29 (0xb7bc3000)
          [...]

There is some intelligence behind whether rpath is set at all:

  * If 'CMAKE_INSTALL_RPATH' is set, then it is used; this
    allows the user to set a single, overriding value, and it
    allows the 'AppImage' build script to continue working in
    exactly the same way that it has been doing so far.

  * Otherwise, the base-case rpath is determined by the following:

      "${CMAKE_INSTALL_FULL_LIBDIR}"

    If that path is a standard location, then the base-case rpath
    is the empty string (meaning, in the base case, no rpath will
    be set); otherwise, the base-case rpath is set to that path.

  * The base-case rpath is used to set various targets' 'INSTALL_RPATH'
    property. This is done explicitly, so as to avoid the setting of
    an rpath unnecessarily on some target; for instance, as of this
    commit, only some of the executable targets have this property set,
    but the 'libqpdf' target does not. In the long run, having such
    fine-grained control will likely be the best policy.

  * In addition, cmake has been instructed to add to each target's
    rpath any directories that it thinks might contain potential
    unorthodox dependencies from outside the project; most of the time,
    there will be no such dependencies, and so nothing will be added.
    However, this is a simple way to account for unforeseen needs.

Of course, this will only help on a system that supports an rpath
feature known to cmake; for example, Windows has no such feature,
and so all of this will presumably be ignored when building under
that system.
This commit is contained in:
Michael Witten 2024-04-25 20:37:48 +00:00
parent 58c31fdd5e
commit 2371d70132
4 changed files with 18 additions and 0 deletions

View File

@ -250,6 +250,21 @@ endif()
include(GNUInstallDirs)
if (DEFINED CMAKE_INSTALL_RPATH)
set(Base_rpath "${CMAKE_INSTALL_RPATH}")
else()
if(BUILD_SHARED_LIBS)
set(p "${CMAKE_INSTALL_FULL_LIBDIR}")
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${p}" i)
if("${i}" STREQUAL "-1")
set(Base_rpath "${p}")
endif()
endif()
endif()
# Append non-standard external dependency directories, if any.
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
# Compiler flags
#
# **NOTE** -- each flag must have its own cache variable.

View File

@ -32,6 +32,7 @@ foreach(PROG ${EXAMPLE_C_PROGRAMS})
target_link_libraries(${PROG} libqpdf)
set_property(TARGET ${PROG} PROPERTY LINKER_LANGUAGE CXX)
endforeach()
set_target_properties(${EXAMPLE_CXX_PROGRAMS} ${EXAMPLE_C_PROGRAMS} PROPERTIES INSTALL_RPATH "${Base_rpath}")
target_include_directories(pdf-create PRIVATE ${JPEG_INCLUDE})
# extend-c-api contains a mixture of C and C++ files.

View File

@ -28,6 +28,7 @@ foreach(PROG ${MAIN_C_PROGRAMS})
target_link_libraries(${PROG} libqpdf)
set_property(TARGET ${PROG} PROPERTY LINKER_LANGUAGE CXX)
endforeach()
set_target_properties(${MAIN_CXX_PROGRAMS} ${MAIN_C_PROGRAMS} PROPERTIES INSTALL_RPATH "${Base_rpath}")
target_include_directories(sizes PRIVATE ${JPEG_INCLUDE})
set(needs_private_headers

View File

@ -1,5 +1,6 @@
add_executable(zlib-flate zlib-flate.cc)
target_link_libraries(zlib-flate libqpdf)
set_target_properties(zlib-flate PROPERTIES INSTALL_RPATH "${Base_rpath}")
add_test(
NAME zlib-flate