diff options
Diffstat (limited to 'Modules/Internal/CPack/CPackDeb.cmake')
-rw-r--r-- | Modules/Internal/CPack/CPackDeb.cmake | 101 |
1 files changed, 94 insertions, 7 deletions
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake index 5a78e3f..d4a47e4 100644 --- a/Modules/Internal/CPack/CPackDeb.cmake +++ b/Modules/Internal/CPack/CPackDeb.cmake @@ -56,6 +56,65 @@ function(extract_so_info shared_object libname version) endif() endfunction() +#extract RUNPATH and RPATH for given shared object or executable +function(extract_runpath_and_rpath shared_object_or_executable runpath rpath) + if(CPACK_READELF_EXECUTABLE) + execute_process(COMMAND "${CPACK_READELF_EXECUTABLE}" -d "${shared_object_or_executable}" + WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}" + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(result EQUAL 0) + string(REGEX MATCH "\\(?RUNPATH\\)?[^\n]*\\[([^\n]+)\\]" found_runpath "${output}") + string(REPLACE ":" ";" found_runpath "${CMAKE_MATCH_1}") + list(REMOVE_DUPLICATES found_runpath) + string(REGEX MATCH "\\(?RPATH\\)?[^\n]*\\[([^\n]+)\\]" found_rpath "${output}") + string(REPLACE ":" ";" found_rpath "${CMAKE_MATCH_1}") + list(REMOVE_DUPLICATES found_rpath) + set(${runpath} "${found_runpath}" PARENT_SCOPE) + set(${rpath} "${found_rpath}" PARENT_SCOPE) + else() + message(WARNING "Error running readelf for \"${shared_object_or_executable}\"") + endif() + else() + message(FATAL_ERROR "Readelf utility is not available.") + endif() +endfunction() + +#sanitizes the given directory name if required +function(get_sanitized_dirname dirname outvar) + # NOTE: This pattern has to stay in sync with the 'prohibited_chars' variable + # defined in the C++ function `CPackGenerator::GetSanitizedDirOrFileName`! + set(prohibited_chars_pattern "[<]|[>]|[\"]|[/]|[\\]|[|]|[?]|[*]|[`]") + if("${dirname}" MATCHES "${prohibited_chars_pattern}") + string(MD5 santized_dirname "${dirname}") + set(${outvar} "${sanitized_dirname}" PARENT_SCOPE) + else() + set(${outvar} "${dirname}" PARENT_SCOPE) + endif() +endfunction() + +#retrieve packaging directories of components the current component depends on +# Note: May only be called from within 'cpack_deb_prepare_package_var'! +function(get_packaging_dirs_of_dependencies outvar) + if(CPACK_DEB_PACKAGE_COMPONENT) + if(NOT DEFINED WDIR OR NOT DEFINED _local_component_name) + message(FATAL_ERROR "CPackDeb: Function '${CMAKE_CURRENT_FUNCTION}' not called from correct function scope!") + endif() + set(result_list) + foreach(dependency_name IN LISTS CPACK_COMPONENT_${_local_component_name}_DEPENDS) + get_sanitized_dirname("${dependency_name}" dependency_name) + cmake_path(APPEND_STRING WDIR "/../${dependency_name}" OUTPUT_VARIABLE dependency_packaging_dir) + cmake_path(NORMAL_PATH dependency_packaging_dir) + list(APPEND result_list "${dependency_packaging_dir}") + endforeach() + set(${outvar} "${result_list}" PARENT_SCOPE) # Set return variable. + else() + set(${outvar} "" PARENT_SCOPE) # Clear return variable. + endif() +endfunction() + function(cpack_deb_check_description SUMMARY LINES RESULT_VARIABLE) set(_result TRUE) @@ -310,16 +369,44 @@ function(cpack_deb_prepare_package_vars) set(IGNORE_MISSING_INFO_FLAG "--ignore-missing-info") endif() - if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS) + # Add -l option if the tool supports it? + if(DEFINED SHLIBDEPS_EXECUTABLE_VERSION AND SHLIBDEPS_EXECUTABLE_VERSION VERSION_GREATER_EQUAL 1.17.0) unset(PRIVATE_SEARCH_DIR_OPTIONS) - # Add -l option if the tool supports it - if(DEFINED SHLIBDEPS_EXECUTABLE_VERSION AND SHLIBDEPS_EXECUTABLE_VERSION VERSION_GREATER_EQUAL 1.17.0) - foreach(dir IN LISTS CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS) - list(APPEND PRIVATE_SEARCH_DIR_OPTIONS "-l${dir}") + + # Use directories provided via CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS + if(NOT "${CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS}" STREQUAL "") + foreach(path IN LISTS CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS) + cmake_path(NORMAL_PATH path) # Required for dpkg-shlibdeps! + list(APPEND PRIVATE_SEARCH_DIR_OPTIONS "-l${path}") endforeach() - else() - message(WARNING "CPackDeb: dkpg-shlibdeps is too old. \"CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS\" is therefore ignored.") endif() + + # Use directories extracted from RUNPATH/RPATH + get_packaging_dirs_of_dependencies(deps_packaging_dirs) + foreach(exe IN LISTS CPACK_DEB_BINARY_FILES) + cmake_path(GET exe PARENT_PATH exe_dir) + extract_runpath_and_rpath(${exe} runpath rpath) + # If RUNPATH is available, RPATH will be ignored. Therefore we have to do the same here! + if (NOT "${runpath}" STREQUAL "") + set(selected_rpath "${runpath}") + else() + set(selected_rpath "${rpath}") + endif() + foreach(search_path IN LISTS selected_rpath) + if ("${search_path}" MATCHES "^[$]ORIGIN" OR "${search_path}" MATCHES "^[$][{]ORIGIN[}]") + foreach(deps_pkgdir IN LISTS deps_packaging_dirs) + string(REPLACE "\$ORIGIN" "${deps_pkgdir}/${exe_dir}" path "${search_path}") + string(REPLACE "\${ORIGIN}" "${deps_pkgdir}/${exe_dir}" path "${path}") + cmake_path(NORMAL_PATH path) # Required for dpkg-shlibdeps! + list(APPEND PRIVATE_SEARCH_DIR_OPTIONS "-l${path}") + endforeach() + endif() + endforeach() + endforeach() + + list(REMOVE_DUPLICATES PRIVATE_SEARCH_DIR_OPTIONS) + elseif(NOT "${CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS}" STREQUAL "") + message(WARNING "CPackDeb: dkpg-shlibdeps is too old. \"CPACK_DEBIAN_PACKAGE_SHLIBDEPS_PRIVATE_DIRS\" is therefore ignored.") endif() # Execute dpkg-shlibdeps |