View Issue Details [ Jump to Notes ] | [ Print ] |
ID | Project | Category | View Status | Date Submitted | Last Update |
0015209 | CMake | CPack | public | 2014-10-16 09:10 | 2016-01-04 11:51 |
|
Reporter | Luc J. Bourhis | |
Assigned To | Domen Vrankar | |
Priority | normal | Severity | minor | Reproducibility | always |
Status | closed | Resolution | fixed | |
Platform | | OS | | OS Version | |
Product Version | CMake 2.8.12.2 | |
Target Version | CMake 3.3 | Fixed in Version | CMake 3.3 | |
|
Summary | 0015209: RPM generation chokes on directory symlinks with latest rpmbuild |
Description | As stated here (https://bugzilla.redhat.com/show_bug.cgi?id=1005529 [^]), the following specs file is no more legal as of rpmbuild 4.11
%files
%dir xxx
yyy/
when xxx or yyy are directory symlinks instead of proper directories. Unfortunately CPack has not been taught that and it generates %dir xxx for a directory symlink xxx. |
Steps To Reproduce | Using the CMakeLists.txt attached to this bug report, issue "make package", on a Linux machine with rpmbuild 4.11 (I tested with Fedora 20). You should get the following error message:
error: Not a directory: /home/luc/Developer/sandbox/build/_CPack_Packages/Linux/RPM/it-will-fail-0.1.1-Linux/usr/usr/share/test/project/subdir
Not a directory: /home/luc/Developer/sandbox/build/_CPack_Packages/Linux/RPM/it-will-fail-0.1.1-Linux/usr/usr/share/test/project/subdir
|
Tags | No tags attached. |
|
Attached Files | CMakeLists.txt [^] (487 bytes) 2014-10-16 09:10 [Show Content] [Hide Content]cmake_minimum_required(VERSION 2.8)
project(CPack-issue-with-directory-symlink-and-RPM)
add_custom_command(
OUTPUT subdir-1/foo.txt
COMMAND mkdir -p project/subdir-1 && cd project && cmake -E touch subdir-1/foo.txt && ln -sf subdir-1 subdir
)
add_custom_target(foo ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/subdir-1/foo.txt)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/project DESTINATION share/test)
set(CPACK_PACKAGE_NAME it-will-fail)
set(CPACK_GENERATOR "RPM")
include(CPack)
CPackRPM.cmake.patch [^] (564 bytes) 2014-10-17 08:22 [Show Content] [Hide Content]--- /usr/share/cmake/Modules/CPackRPM.cmake 2014-09-11 15:24:00.000000000 +0200
+++ CPackRPM.cmake 2014-10-17 10:58:08.015296852 +0200
@@ -935,7 +935,7 @@
"${CPACK_RPM_INSTALL_FILES_LIST}")
set(CPACK_RPM_INSTALL_FILES "")
foreach(F IN LISTS CPACK_RPM_INSTALL_FILES_LIST)
- if(IS_DIRECTORY "${WDIR}/${F}")
+ if(IS_DIRECTORY "${WDIR}/${F}" AND NOT IS_SYMLINK "${WDIR}/${F}" )
set(CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}%dir \"${F}\"\n")
else()
set(CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}\"${F}\"\n")
0001-CPackRPM-handling-of-symbolic-links.patch [^] (12,666 bytes) 2014-11-08 16:03 [Show Content] [Hide Content]From 0a3098dbeb79c90ac3882b13afa77e6e8ff98d62 Mon Sep 17 00:00:00 2001
From: Domen Vrankar <domen.vrankar@gmail.com>
Date: Sat, 8 Nov 2014 22:01:19 +0100
Subject: [PATCH] CPackRPM handling of symbolic links
Try to make symbolic links as relocatable as possible for relocatable
rpm packages and to prevent directory symlinks from being added with
dir prefix to generated spec files
---
Modules/CPackRPM.cmake | 217 +++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 199 insertions(+), 18 deletions(-)
diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake
index 56d9b66..5e19d7c 100644
--- a/Modules/CPackRPM.cmake
+++ b/Modules/CPackRPM.cmake
@@ -395,6 +395,203 @@
# Author: Eric Noulard with the help of Alexander Neundorf.
+function(CPackRPM_PrepareInstallFiles INSTALL_FILES_LIST WDIR PACKAGE_PREFIXES IS_RELOCATABLE)
+ # Prepend directories in ${CPACK_RPM_INSTALL_FILES} with %dir
+ # This is necessary to avoid duplicate files since rpmbuild do
+ # recursion on its own when encountering a pathname which is a directory
+ # which is not flagged as %dir
+ string(STRIP "${INSTALL_FILES_LIST}" INSTALL_FILES_LIST)
+ string(REPLACE "\n" ";" INSTALL_FILES_LIST
+ "${INSTALL_FILES_LIST}")
+ string(REPLACE "\"" "" INSTALL_FILES_LIST
+ "${INSTALL_FILES_LIST}")
+
+ foreach(F IN LISTS INSTALL_FILES_LIST)
+ if(IS_SYMLINK "${WDIR}/${F}")
+ if(IS_RELOCATABLE)
+ # check that symlink has relocatable format
+ get_filename_component(SYMLINK_LOCATION_ "${WDIR}/${F}" DIRECTORY)
+ execute_process(COMMAND ls -la "${WDIR}/${F}"
+ WORKING_DIRECTORY "${WDIR}"
+ OUTPUT_VARIABLE SYMLINK_POINT_)
+
+ string(FIND ${SYMLINK_POINT_} "->" SYMLINK_POINT_INDEX_ REVERSE)
+ math(EXPR SYMLINK_POINT_INDEX_ ${SYMLINK_POINT_INDEX_}+3)
+ string(LENGTH ${SYMLINK_POINT_} SYMLINK_POINT_LENGTH_)
+ # substract additional -1 to remove new line
+ math(EXPR SYMLINK_POINT_LENGTH_ ${SYMLINK_POINT_LENGTH_}-${SYMLINK_POINT_INDEX_}-1)
+ # get destination path
+ string(SUBSTRING ${SYMLINK_POINT_} ${SYMLINK_POINT_INDEX_} ${SYMLINK_POINT_LENGTH_} SYMLINK_POINT_)
+ set(SYMLINK_POINT_RAW_ ${SYMLINK_POINT_})
+ # check if path is relative or absolute
+ if(${SYMLINK_POINT_LENGTH_} GREATER 1)
+ string(SUBSTRING ${SYMLINK_POINT_} 0 2 SYMLINK_IS_ABSOLUTE_)
+
+ if(${SYMLINK_IS_ABSOLUTE_} STREQUAL "./")
+ # handle relative path
+ get_filename_component(SYMLINK_POINT_ "${SYMLINK_LOCATION_}/${SYMLINK_POINT_}" ABSOLUTE)
+ elseif(${SYMLINK_POINT_LENGTH_} GREATER 2)
+ string(SUBSTRING ${SYMLINK_POINT_} 0 3 SYMLINK_IS_ABSOLUTE_)
+
+ if(${SYMLINK_IS_ABSOLUTE_} STREQUAL "../")
+ # handle relative path
+ get_filename_component(SYMLINK_POINT_ "${SYMLINK_LOCATION_}/${SYMLINK_POINT_}" ABSOLUTE)
+ endif()
+ endif()
+ endif()
+
+ # prevent absolute paths from having /../ or /./ section inside of them
+ get_filename_component(SYMLINK_POINT_ "${SYMLINK_POINT_}" ABSOLUTE)
+
+ # check if path is local directory
+ string(SUBSTRING ${SYMLINK_POINT_} 0 1 SYMLINK_IS_ABSOLUTE_)
+ if(${SYMLINK_IS_ABSOLUTE_} STREQUAL "/")
+ string(LENGTH ${WDIR} WDR_LEN_)
+ string(LENGTH ${SYMLINK_POINT_} POINT_LEN_)
+ unset(SKIP_SYMLINK_)
+ if(${WDR_LEN_} GREATER ${POINT_LEN_})
+ if(EXISTS "${WDIR}/${SYMLINK_POINT_}")
+ # file is part of this rpm so we can convert it
+ get_filename_component(SYMLINK_POINT_ "${WDIR}/${SYMLINK_POINT_}" ABSOLUTE)
+ else()
+ message(WARNING "Symlink '${F}' points to location that is not part of the package!")
+ set(SKIP_SYMLINK_ TRUE)
+ set(INSTALL_FILES "${INSTALL_FILES}\"${F}\"\n")
+ endif()
+ endif()
+
+ if(NOT SKIP_SYMLINK_)
+ string(LENGTH ${SYMLINK_POINT_} SYMLINK_POINT_LEN)
+ string(LENGTH ${SYMLINK_LOCATION_} SYMLINK_LOCATION_LEN)
+
+ # make sure that both paths are at least long enough that substrings can be created
+ if(${SYMLINK_POINT_LEN} GREATER ${WDR_LEN_} AND ${SYMLINK_LOCATION_LEN} GREATER ${WDR_LEN_})
+ string(SUBSTRING ${SYMLINK_POINT_} 0 ${WDR_LEN_} SYMLINK_POINT_WD_)
+ string(SUBSTRING ${SYMLINK_LOCATION_} 0 ${WDR_LEN_} SYMLINK_LOCATION_WD_)
+ else()
+ set(SKIP_SYMLINK_ TRUE)
+ endif()
+
+ if(SKIP_SYMLINK_ OR NOT ${SYMLINK_POINT_WD_} STREQUAL ${SYMLINK_LOCATION_WD_})
+ message(WARNING "Symlink '${F}' points to location that is not part of the package!")
+ set(INSTALL_FILES "${INSTALL_FILES}\"${F}\"\n")
+ else()
+ # check if symlink and point location are in the same relocation path
+ unset(IDENTICAL_RELOCATION_PATH)
+ foreach(PKG_PREFIX ${PACKAGE_PREFIXES})
+ unset(SKIP_SYMLINK_)
+ get_filename_component(RELOCATION_PATH_ "${WDIR}/${PKG_PREFIX}" ABSOLUTE)
+ string(LENGTH ${RELOCATION_PATH_} RELOCATION_PATH_LENGTH_)
+ math(EXPR RELOCATION_PATH_LENGTH_ ${RELOCATION_PATH_LENGTH_}+1) # add +1 to length so that we check that location ends with /
+
+ # make sure that both paths are at least long enough that substrings can be created
+ if(${SYMLINK_POINT_LEN} GREATER ${RELOCATION_PATH_LENGTH_} AND ${SYMLINK_LOCATION_LEN} GREATER ${RELOCATION_PATH_LENGTH_})
+ string(SUBSTRING ${SYMLINK_POINT_} 0 ${RELOCATION_PATH_LENGTH_} SYMLINK_POINT_RELOCATIONPATH_)
+ string(SUBSTRING ${SYMLINK_LOCATION_} 0 ${RELOCATION_PATH_LENGTH_} SYMLINK_LOCATION_RELOCATIONPATH_)
+ else()
+ set(SKIP_SYMLINK_ TRUE)
+ endif()
+
+ if(NOT SKIP_SYMLINK_ AND ${SYMLINK_POINT_RELOCATIONPATH_} STREQUAL ${SYMLINK_LOCATION_RELOCATIONPATH_})
+ set(IDENTICAL_RELOCATION_PATH TRUE)
+ break()
+ endif()
+ endforeach()
+
+ if(IDENTICAL_RELOCATION_PATH)
+ # construct relative path
+ string(LENGTH ${SYMLINK_POINT_} POINT_LEN)
+ math(EXPR POINT_LEN ${POINT_LEN}-1)
+ string(SUBSTRING ${SYMLINK_POINT_} 1 ${POINT_LEN} SYMLINK_POINT_)
+ string(LENGTH ${SYMLINK_LOCATION_} LOCATION_LEN)
+ math(EXPR LOCATION_LEN ${LOCATION_LEN}-1)
+ string(SUBSTRING ${SYMLINK_LOCATION_} 1 ${LOCATION_LEN} SYMLINK_LOCATION_)
+ string(REPLACE "/" ";" SYMLINK_POINT_SPLIT_ ${SYMLINK_POINT_})
+ string(REPLACE "/" ";" SYMLINK_LOCATION_SPLIT_ ${SYMLINK_LOCATION_})
+
+ set(SYMLINK_POINT_PART_ "")
+ set(SYMLINK_LOCATION_PART_ "")
+ list(LENGTH SYMLINK_POINT_SPLIT_ SYMLINK_POINT_PART_LEN_)
+ list(LENGTH SYMLINK_LOCATION_SPLIT_ SYMLINK_LOCATION_PART_LEN_)
+
+ while("${SYMLINK_POINT_PART_}" STREQUAL "${SYMLINK_LOCATION_PART_}"
+ AND ${SYMLINK_POINT_PART_LEN_} AND ${SYMLINK_LOCATION_PART_LEN_})
+ list(GET SYMLINK_POINT_SPLIT_ 0 SYMLINK_POINT_PART_)
+ list(GET SYMLINK_LOCATION_SPLIT_ 0 SYMLINK_LOCATION_PART_)
+ list(REMOVE_AT SYMLINK_POINT_SPLIT_ 0)
+ list(REMOVE_AT SYMLINK_LOCATION_SPLIT_ 0)
+ list(LENGTH SYMLINK_POINT_SPLIT_ SYMLINK_POINT_PART_LEN_)
+ list(LENGTH SYMLINK_LOCATION_SPLIT_ SYMLINK_LOCATION_PART_LEN_)
+ endwhile()
+
+ list(LENGTH SYMLINK_LOCATION_SPLIT_ LIST_LEN)
+ if(NOT "${SYMLINK_POINT_PART_}" STREQUAL "${SYMLINK_LOCATION_PART_}")
+ list(INSERT SYMLINK_POINT_SPLIT_ 0 ".." "${SYMLINK_POINT_PART_}")
+ endif()
+
+ while(${LIST_LEN} GREATER 0)
+ list(INSERT SYMLINK_POINT_SPLIT_ 0 "..")
+ math(EXPR LIST_LEN ${LIST_LEN}-1)
+ endwhile()
+
+ string(REPLACE ";" "/" FINAL "${SYMLINK_POINT_SPLIT_}")
+
+ # override symlink with new relative path if original point location is not equal to generated point location
+ if(NOT ${SYMLINK_POINT_RAW_} STREQUAL ${FINAL})
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${FINAL}" "${WDIR}/${F}" RESULT_VARIABLE res)
+ endif()
+ else()
+ # handle case when symlink and point don't have same relocation path
+ unset(HAS_RELOCATION_PATH)
+ foreach(PKG_PREFIX ${PACKAGE_PREFIXES})
+ unset(SKIP_SYMLINK_)
+ get_filename_component(RELOCATION_PATH_ "${WDIR}/${PKG_PREFIX}" ABSOLUTE)
+ string(LENGTH ${RELOCATION_PATH_} RELOCATION_PATH_LENGTH_)
+ math(EXPR RELOCATION_PATH_LENGTH_ ${RELOCATION_PATH_LENGTH_}+1) # add +1 to length so that we check that location ends with /
+
+ # make sure that path is at least long enough that substring can be created
+ if(${SYMLINK_POINT_LEN} GREATER ${RELOCATION_PATH_LENGTH_})
+ string(SUBSTRING ${SYMLINK_POINT_} 0 ${RELOCATION_PATH_LENGTH_} SYMLINK_POINT_RELOCATION_PATH_)
+ else()
+ set(SKIP_SYMLINK_ TRUE)
+ endif()
+
+ if(NOT SKIP_SYMLINK_ AND ${RELOCATION_PATH_} STREQUAL ${SYMLINK_POINT_RELOCATION_PATH_})
+ set(HAS_RELOCATION_PATH ${RELOCATION_PATH_}) # TODO output index as we need to create a script variable (call function twice)
+ break()
+ endif()
+ endforeach()
+
+ if(HAS_RELOCATION_PATH)
+ # TODO prepare post install and pre uninstall symlink scripts
+ message(WARNING "Multiple relocation paths are currently not supported for symlinks in CPackRPM so symlink '${F}' will not be changed.")
+ else()
+ # symlink should have absolute path
+ string(SUBSTRING ${SYMLINK_POINT_} ${WDR_LEN_} -1 FINAL)
+ execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${FINAL}" "${WDIR}/${F}" RESULT_VARIABLE res)
+ endif()
+ endif()
+
+ set(INSTALL_FILES "${INSTALL_FILES}\"${F}\"\n")
+ endif()
+ endif()
+ else()
+ # no need to convert the symlink
+ set(INSTALL_FILES "${INSTALL_FILES}\"${F}\"\n")
+ endif()
+ else()
+ set(INSTALL_FILES "${INSTALL_FILES}\"${F}\"\n")
+ endif()
+ elseif(IS_DIRECTORY "${WDIR}/${F}")
+ set(INSTALL_FILES "${INSTALL_FILES}%dir \"${F}\"\n")
+ else()
+ set(INSTALL_FILES "${INSTALL_FILES}\"${F}\"\n")
+ endif()
+ endforeach()
+
+ set(CPACK_RPM_INSTALL_FILES "${INSTALL_FILES}" PARENT_SCOPE)
+endfunction()
+
if(CMAKE_BINARY_DIR)
message(FATAL_ERROR "CPackRPM.cmake may only be used by CPack internally.")
endif()
@@ -1025,24 +1222,8 @@ else()
set(CPACK_RPM_ABSOLUTE_INSTALL_FILES "")
endif()
-# Prepend directories in ${CPACK_RPM_INSTALL_FILES} with %dir
-# This is necessary to avoid duplicate files since rpmbuild do
-# recursion on its own when encountering a pathname which is a directory
-# which is not flagged as %dir
-string(STRIP "${CPACK_RPM_INSTALL_FILES}" CPACK_RPM_INSTALL_FILES_LIST)
-string(REPLACE "\n" ";" CPACK_RPM_INSTALL_FILES_LIST
- "${CPACK_RPM_INSTALL_FILES_LIST}")
-string(REPLACE "\"" "" CPACK_RPM_INSTALL_FILES_LIST
- "${CPACK_RPM_INSTALL_FILES_LIST}")
-set(CPACK_RPM_INSTALL_FILES "")
-foreach(F IN LISTS CPACK_RPM_INSTALL_FILES_LIST)
- if(IS_DIRECTORY "${WDIR}/${F}")
- set(CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}%dir \"${F}\"\n")
- else()
- set(CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}\"${F}\"\n")
- endif()
-endforeach()
-set(CPACK_RPM_INSTALL_FILES_LIST "")
+# Prepare install files
+CPackRPM_PrepareInstallFiles("${CPACK_RPM_INSTALL_FILES}" "${WDIR}" "${CPACK_RPM_PACKAGE_PREFIX}" "${CPACK_RPM_PACKAGE_PREFIX}" ${CPACK_RPM_PACKAGE_RELOCATABLE})
# The name of the final spec file to be used by rpmbuild
set(CPACK_RPM_BINARY_SPECFILE "${CPACK_RPM_ROOTDIR}/SPECS/${CPACK_RPM_PACKAGE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_NAME}.spec")
--
2.1.0
|
|