Ver código fonte

CPackRPM: Allow multiple path relocation prefixes for one package

Domen Vrankar 11 anos atrás
pai
commit
3ec0254727

+ 11 - 0
Help/release/dev/rpm_multi_prefix.rst

@@ -0,0 +1,11 @@
+rpm_multi_prefix
+----------------
+
+* The :module:`CPackRPM` module learned a new
+  :variable:`CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX` variable to
+  specify a component-specific value to use instead of
+  :variable:`CPACK_PACKAGING_INSTALL_PREFIX`.
+
+* The :module:`CPackRPM` module learned a new
+  :variable:`CPACK_RPM_RELOCATION_PATHS` variable to
+  specify multiple relocation prefixes for a single rpm package.

+ 104 - 11
Modules/CPackRPM.cmake

@@ -379,6 +379,34 @@
 #
 #  May be used to add more exclude path (directories or files) from the initial
 #  default list of excluded paths. See CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST.
+#
+# .. variable:: CPACK_RPM_RELOCATION_PATHS
+#
+#  * Mandatory : NO
+#  * Default   : -
+#
+#  May be used to specify more than one relocation path per relocatable RPM.
+#  Variable contains a list of relocation paths that if relative are prefixed
+#  by the value of CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX or by the value of
+#  CPACK_PACKAGING_INSTALL_PREFIX if the component version is not provided.
+#  Variable is not component based as its content can be used to set a different
+#  path prefix for e.g. binary dir and documentation dir at the same time.
+#  Only prefixes that are required by a certain component are added to that
+#  component - component must contain at least one file/directory/symbolic link
+#  with CPACK_RPM_RELOCATION_PATHS prefix for a certain relocation path
+#  to be added. Package will not contain any relocation paths if there are no
+#  files/directories/symbolic links on any of the provided prefix locations.
+#  Packages that either do not contain any relocation paths or contain
+#  files/directories/symbolic links that are outside relocation paths print
+#  out an AUTHOR_WARNING that RPM will be partially relocatable.
+#
+# .. variable:: CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
+#
+#  * Mandatory : NO
+#  * Default   : CPACK_PACKAGING_INSTALL_PREFIX
+#
+#  May be used to set per component CPACK_PACKAGING_INSTALL_PREFIX for
+#  relocatable RPM packages.
 
 #=============================================================================
 # Copyright 2007-2009 Kitware, Inc.
@@ -395,6 +423,62 @@
 
 # Author: Eric Noulard with the help of Alexander Neundorf.
 
+function(cpack_rpm_prepare_relocation_paths)
+  # set appropriate prefix, remove possible trailing slash and convert backslashes to slashes
+  if(CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX)
+    file(TO_CMAKE_PATH "${CPACK_RPM_${CPACK_RPM_PACKAGE_COMPONENT}_PACKAGE_PREFIX}" PATH_PREFIX)
+  else()
+    file(TO_CMAKE_PATH "${CPACK_PACKAGING_INSTALL_PREFIX}" PATH_PREFIX)
+  endif()
+
+  set(RPM_RELOCATION_PATHS "${CPACK_RPM_RELOCATION_PATHS}")
+  list(REMOVE_DUPLICATES RPM_RELOCATION_PATHS)
+
+  # set base path prefix
+  if(EXISTS "${WDIR}/${PATH_PREFIX}")
+    set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}Prefix: ${PATH_PREFIX}\n")
+    list(APPEND RPM_USED_PACKAGE_PREFIXES "${PATH_PREFIX}")
+  endif()
+
+  # set other path prefixes
+  foreach(RELOCATION_PATH ${RPM_RELOCATION_PATHS})
+    if(IS_ABSOLUTE "${RELOCATE_PATH}")
+      set(PREPARED_RELOCATION_PATH "${RELOCATION_PATH}")
+    else()
+      set(PREPARED_RELOCATION_PATH "${PATH_PREFIX}/${RELOCATION_PATH}")
+    endif()
+
+    if(EXISTS "${WDIR}/${PREPARED_RELOCATION_PATH}")
+      set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}Prefix: ${PREPARED_RELOCATION_PATH}\n")
+      list(APPEND RPM_USED_PACKAGE_PREFIXES "${PREPARED_RELOCATION_PATH}")
+    endif()
+  endforeach()
+
+  # warn about all the paths that are not relocatable
+  file(GLOB_RECURSE FILE_PATHS_ "${WDIR}/*")
+  foreach(TMP_PATH ${FILE_PATHS_})
+    string(LENGTH "${WDIR}" WDIR_LEN)
+    string(SUBSTRING "${TMP_PATH}" ${WDIR_LEN} -1 TMP_PATH)
+    unset(TMP_PATH_FOUND_)
+
+    foreach(RELOCATION_PATH ${RPM_USED_PACKAGE_PREFIXES})
+      file(RELATIVE_PATH REL_PATH_ "${RELOCATION_PATH}" "${TMP_PATH}")
+      string(SUBSTRING "${REL_PATH_}" 0 2 PREFIX_)
+
+      if(NOT "${PREFIX_}" STREQUAL "..")
+        set(TPM_PATH_FOUND_ TRUE)
+        break()
+      endif()
+    endforeach()
+
+    if(NOT TPM_PATH_FOUND_)
+      message(AUTHOR_WARNING "CPackRPM:Warning: Path ${TMP_PATH} is not on one of the relocatable paths! Package will be partially relocatable.")
+    endif()
+  endforeach()
+
+  set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}" PARENT_SCOPE)
+endfunction()
+
 if(CMAKE_BINARY_DIR)
   message(FATAL_ERROR "CPackRPM.cmake may only be used by CPack internally.")
 endif()
@@ -636,13 +720,16 @@ if(CPACK_PACKAGE_RELOCATABLE)
   set(CPACK_RPM_PACKAGE_RELOCATABLE TRUE)
 endif()
 if(CPACK_RPM_PACKAGE_RELOCATABLE)
+  unset(TMP_RPM_PREFIXES)
+
   if(CPACK_RPM_PACKAGE_DEBUG)
     message("CPackRPM:Debug: Trying to build a relocatable package")
   endif()
   if(CPACK_SET_DESTDIR AND (NOT CPACK_SET_DESTDIR STREQUAL "I_ON"))
     message("CPackRPM:Warning: CPACK_SET_DESTDIR is set (=${CPACK_SET_DESTDIR}) while requesting a relocatable package (CPACK_RPM_PACKAGE_RELOCATABLE is set): this is not supported, the package won't be relocatable.")
   else()
-    set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX})
+    set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX}) # kept for back compatibility (provided external RPM spec files)
+    cpack_rpm_prepare_relocation_paths()
   endif()
 endif()
 
@@ -856,15 +943,21 @@ if(CPACK_RPM_PACKAGE_RELOCATABLE)
   # get a list of the elements in CPACK_RPM_PACKAGE_PREFIX and remove
   # the final element (so the install-prefix dir itself is not omitted
   # from the RPM's content-list)
-  string(REPLACE "/" ";" _CPACK_RPM_PACKAGE_PREFIX_ELEMS ".${CPACK_RPM_PACKAGE_PREFIX}")
-  list(REMOVE_AT _CPACK_RPM_PACKAGE_PREFIX_ELEMS -1)
-  # Now generate all of the parent dirs of CPACK_RPM_PACKAGE_PREFIX
-  foreach(_ELEM ${_CPACK_RPM_PACKAGE_PREFIX_ELEMS})
-    list(APPEND _TMP_LIST "${_ELEM}")
-    string(REPLACE ";" "/" _OMIT_DIR "${_TMP_LIST}")
-    set(_OMIT_DIR "-o -path ${_OMIT_DIR}")
-    separate_arguments(_OMIT_DIR)
-    list(APPEND _RPM_DIRS_TO_OMIT ${_OMIT_DIR})
+  foreach(CPACK_RPM_PACKAGE_PREFIX ${RPM_PACKAGE_PREFIXES})
+    string(REPLACE "/" ";" _CPACK_RPM_PACKAGE_PREFIX_ELEMS ".${CPACK_RPM_PACKAGE_PREFIX}")
+    list(REMOVE_AT _CPACK_RPM_PACKAGE_PREFIX_ELEMS -1)
+    unset(_TMP_LIST)
+    # Now generate all of the parent dirs of CPACK_RPM_PACKAGE_PREFIX
+    foreach(_ELEM ${_CPACK_RPM_PACKAGE_PREFIX_ELEMS})
+      list(APPEND _TMP_LIST "${_ELEM}")
+      string(REPLACE ";" "/" _OMIT_DIR "${_TMP_LIST}")
+      list(FIND _RPM_DIRS_TO_OMIT "${_OMIT_DIR}" _DUPLICATE_FOUND)
+      if(_DUPLICATE_FOUND EQUAL -1)
+        set(_OMIT_DIR "-o -path ${_OMIT_DIR}")
+        separate_arguments(_OMIT_DIR)
+        list(APPEND _RPM_DIRS_TO_OMIT ${_OMIT_DIR})
+      endif()
+    endforeach()
   endforeach()
 endif()
 
@@ -1101,7 +1194,7 @@ Vendor:         \@CPACK_RPM_PACKAGE_VENDOR\@
 \@TMP_RPM_AUTOREQ\@
 \@TMP_RPM_AUTOREQPROV\@
 \@TMP_RPM_BUILDARCH\@
-\@TMP_RPM_PREFIX\@
+\@TMP_RPM_PREFIXES\@
 
 %define _rpmdir \@CPACK_RPM_DIRECTORY\@
 %define _rpmfilename \@CPACK_RPM_FILE_NAME\@

+ 6 - 0
Tests/CPackComponentsForAll/CMakeLists.txt

@@ -110,6 +110,12 @@ set(CPACK_COMPONENT_LIBRARIES_INSTALL_TYPES Developer Full)
 set(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full)
 set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full)
 
+# set CPACK_RPM_RELOCATION_PATHS here as GNUInstallDirs script
+# can not be used in CPack scripts due to CMAKE_SIZEOF_VOID_P
+# variable not being set
+set(CPACK_RPM_RELOCATION_PATHS "${CMAKE_INSTALL_INCLUDEDIR}"
+  "${CMAKE_INSTALL_LIBDIR}" "${CMAKE_INSTALL_BINDIR}")
+
 # We may use the CPack specific config file in order
 # to tailor CPack behavior on a CPack generator specific way
 # (Behavior would be different for RPM or TGZ or DEB ...)

+ 9 - 7
Tests/CPackComponentsForAll/MyLibCPackConfig-IgnoreGroup.cmake.in

@@ -6,15 +6,17 @@ if(CPACK_GENERATOR MATCHES "ZIP")
 endif()
 
 if(CPACK_GENERATOR MATCHES "RPM")
-   set(CPACK_RPM_COMPONENT_INSTALL "ON")
-   set(CPACK_RPM_applications_PACKAGE_REQUIRES "mylib-libraries")
+  set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
 
-   # test package summary override
-   set(CPACK_RPM_PACKAGE_SUMMARY "default summary")
-   set(CPACK_RPM_libraries_PACKAGE_SUMMARY "libraries summary")
+  set(CPACK_RPM_COMPONENT_INSTALL "ON")
+  set(CPACK_RPM_applications_PACKAGE_REQUIRES "mylib-libraries")
 
-   # test package description override
-   set(CPACK_RPM_libraries_PACKAGE_DESCRIPTION "libraries description")
+  # test package summary override
+  set(CPACK_RPM_PACKAGE_SUMMARY "default summary")
+  set(CPACK_RPM_libraries_PACKAGE_SUMMARY "libraries summary")
+
+  # test package description override
+  set(CPACK_RPM_libraries_PACKAGE_DESCRIPTION "libraries description")
 endif()
 
 if(CPACK_GENERATOR MATCHES "DEB")

+ 28 - 2
Tests/CPackComponentsForAll/RunCPackVerifyResult.cmake

@@ -140,6 +140,12 @@ if(CPackGen MATCHES "RPM")
     "C/C\\+\\+ header files for use with MyLib")
 
   if(${CPackComponentWay} STREQUAL "IgnoreGroup")
+    # set gnu install prefixes to what they are set during rpm creation
+    # CMAKE_SIZEOF_VOID_P is not set here but lib is prefix of lib64 so
+    # relocation path test won't fail on OSes with lib64 library location
+    include(GNUInstallDirs)
+    set(CPACK_PACKAGING_INSTALL_PREFIX "/usr")
+
     foreach(check_file ${expected_file})
       string(REGEX MATCH ".*libraries.*" check_file_libraries_match ${check_file})
       string(REGEX MATCH ".*headers.*" check_file_headers_match ${check_file})
@@ -154,15 +160,23 @@ if(CPackGen MATCHES "RPM")
       if(check_file_libraries_match)
         set(check_file_match_expected_summary ".*${CPACK_RPM_libraries_PACKAGE_SUMMARY}.*")
         set(check_file_match_expected_description ".*${CPACK_RPM_libraries_PACKAGE_DESCRIPTION}.*")
+        set(check_file_match_expected_relocation_path "Relocations : ${CPACK_PACKAGING_INSTALL_PREFIX} ${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
+        set(spec_regex "*libraries*")
       elseif(check_file_headers_match)
         set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
         set(check_file_match_expected_description ".*${CPACK_COMPONENT_HEADERS_DESCRIPTION}.*")
+        set(check_file_match_expected_relocation_path "Relocations : ${CPACK_PACKAGING_INSTALL_PREFIX} ${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}")
+        set(spec_regex "*headers*")
       elseif(check_file_applications_match)
         set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
         set(check_file_match_expected_description ".*${CPACK_COMPONENT_APPLICATIONS_DESCRIPTION}.*")
+        set(check_file_match_expected_relocation_path "Relocations : ${CPACK_PACKAGING_INSTALL_PREFIX} ${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+        set(spec_regex "*applications*")
       elseif(check_file_Unspecified_match)
         set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
         set(check_file_match_expected_description ".*DESCRIPTION.*")
+        set(check_file_match_expected_relocation_path "Relocations : ${CPACK_PACKAGING_INSTALL_PREFIX} ${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
+        set(spec_regex "*Unspecified*")
       else()
         message(FATAL_ERROR "error: unexpected rpm package '${check_file}'")
       endif()
@@ -170,13 +184,25 @@ if(CPackGen MATCHES "RPM")
       string(REGEX MATCH ${check_file_match_expected_summary} check_file_match_summary ${check_file_content})
 
       if(NOT check_file_match_summary)
-          message(FATAL_ERROR "error: '${check_file}' rpm package summary does not match expected value - regex '${check_file_match_expected_summary}'")
+        message(FATAL_ERROR "error: '${check_file}' rpm package summary does not match expected value - regex '${check_file_match_expected_summary}'; RPM output: '${check_file_content}'")
       endif()
 
       string(REGEX MATCH ${check_file_match_expected_description} check_file_match_description ${check_file_content})
 
       if(NOT check_file_match_description)
-          message(FATAL_ERROR "error: '${check_file}' rpm package description does not match expected value - regex '${check_file_match_expected_description}'")
+        message(FATAL_ERROR "error: '${check_file}' rpm package description does not match expected value - regex '${check_file_match_expected_description}'; RPM output: '${check_file_content}'")
+      endif()
+
+      string(REGEX MATCH ${check_file_match_expected_relocation_path} check_file_match_relocation_path ${check_file_content})
+
+      if(NOT check_file_match_relocation_path)
+        file(GLOB_RECURSE spec_file "${CPackComponentsForAll_BINARY_DIR}/${spec_regex}.spec")
+
+        if(spec_file)
+          file(READ ${spec_file} spec_file_content)
+        endif()
+
+        message(FATAL_ERROR "error: '${check_file}' rpm package relocation path does not match expected value - regex '${check_file_match_expected_relocation_path}'; RPM output: '${check_file_content}'; generated spec file: '${spec_file_content}'")
       endif()
     endforeach()
   elseif(${CPackComponentWay} STREQUAL "IgnoreGroup")

+ 4 - 0
Tests/RunCMake/CMakeLists.txt

@@ -173,3 +173,7 @@ add_RunCMake_test(CommandLine)
 add_RunCMake_test(install)
 add_RunCMake_test(CPackInstallProperties)
 add_RunCMake_test(ExternalProject)
+
+if(RPMBUILD)
+  add_RunCMake_test(CPackRPM)
+endif()

+ 7 - 0
Tests/RunCMake/CPackRPM/CMakeLists.txt

@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
+
+set(CPACK_GENERATOR "RPM")
+include(CPack)

+ 1 - 0
Tests/RunCMake/CPackRPM/CPackRPM_PARTIALLY_RELOCATABLE_WARNING-stderr.txt

@@ -0,0 +1 @@
+CPackRPM:Warning: Path /not_relocatable/CMakeLists.txt is not on one of the.*relocatable paths! Package will be partially relocatable.

+ 7 - 0
Tests/RunCMake/CPackRPM/CPackRPM_PARTIALLY_RELOCATABLE_WARNING.cmake

@@ -0,0 +1,7 @@
+install(FILES CMakeLists.txt DESTINATION /not_relocatable COMPONENT static)
+install(FILES CMakeLists.txt DESTINATION relocatable COMPONENT relocatable)
+
+set(CPACK_PACKAGE_RELOCATABLE TRUE)
+set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
+
+set(CPACK_RPM_COMPONENT_INSTALL ON)

+ 17 - 0
Tests/RunCMake/CPackRPM/RunCMakeTest.cmake

@@ -0,0 +1,17 @@
+include(RunCMake)
+
+function(run_cpack_rpm_test TEST_NAME)
+  set(RunCMake_TEST_NO_CLEAN TRUE)
+  set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${TEST_NAME}-build")
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+  execute_process(
+    COMMAND "${CMAKE_COMMAND}" -D RunCMake_TEST=${TEST_NAME} "${RunCMake_SOURCE_DIR}"
+    WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}"
+    OUTPUT_QUIET
+    ERROR_QUIET
+    )
+  run_cmake_command(${TEST_NAME} ${CMAKE_CPACK_COMMAND})
+endfunction()
+
+run_cpack_rpm_test(CPackRPM_PARTIALLY_RELOCATABLE_WARNING)