CPackRPM: Add basic symlink support (#15209)

RPM packages can contain symbolic links to relative paths - including
support for multiple relocation paths through generation of post install
relocation scripts.  Add basic support with limitations described in
documentation.
This commit is contained in:
Domen Vrankar 2015-03-29 20:55:20 +02:00 committed by Brad King
parent c1f8c6cdf9
commit 681f3a2f01
5 changed files with 526 additions and 26 deletions

View File

@ -418,6 +418,41 @@
# #
# May be used to remove CPACK_PACKAGING_INSTALL_PREFIX and CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX # May be used to remove CPACK_PACKAGING_INSTALL_PREFIX and CPACK_RPM_<COMPONENT>_PACKAGE_PREFIX
# from relocatable RPM prefix paths. # from relocatable RPM prefix paths.
#
# Packaging of Symbolic Links
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^
#
# CPackRPM supports packaging of symbolic links::
#
# execute_process(COMMAND ${CMAKE_COMMAND}
# -E create_symlink <relative_path_location> <symlink_name>)
# install(FILES ${CMAKE_CURRENT_BINARY_DIR}/<symlink_name>
# DESTINATION <symlink_location> COMPONENT libraries)
#
# Symbolic links will be optimized (paths will be shortened if possible)
# before being added to the package or if multiple relocation paths are
# detected, a post install symlink relocation script will be generated.
#
# Symbolic links may point to locations that are not packaged by the same
# package (either a different component or even not packaged at all) but
# those locations will be treated as if they were a part of the package
# while determining if symlink should be either created or present in a
# post install script - depending on relocation paths.
#
# Currenty there are a few limitations though:
#
# * Only symbolic links with relative path can be packaged.
#
# * For component based packaging component interdependency is not checked
# when processing symbolic links. Symbolic links pointing to content of
# a different component are treated the same way as if pointing to location
# that will not be packaged.
#
# * Symbolic links pointing to a location through one or more intermediate
# symbolic links will not be handled differently - if the intermediate
# symbolic link(s) is also on a relocatable path, relocating it during
# package installation may cause initial symbolic link to point to an
# invalid location.
#============================================================================= #=============================================================================
# Copyright 2007-2009 Kitware, Inc. # Copyright 2007-2009 Kitware, Inc.
@ -503,6 +538,301 @@ function(cpack_rpm_prepare_relocation_paths)
set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}" PARENT_SCOPE) set(TMP_RPM_PREFIXES "${TMP_RPM_PREFIXES}" PARENT_SCOPE)
endfunction() endfunction()
function(cpack_rpm_symlink_get_relocation_prefixes LOCATION PACKAGE_PREFIXES RETURN_VARIABLE)
foreach(PKG_PREFIX IN LISTS PACKAGE_PREFIXES)
string(REGEX MATCH "^${PKG_PREFIX}/.*" FOUND_ "${LOCATION}")
if(FOUND_)
list(APPEND TMP_PREFIXES "${PKG_PREFIX}")
endif()
endforeach()
set(${RETURN_VARIABLE} "${TMP_PREFIXES}" PARENT_SCOPE)
endfunction()
function(cpack_rpm_symlink_create_relocation_script PACKAGE_PREFIXES)
list(LENGTH PACKAGE_PREFIXES LAST_INDEX)
set(SORTED_PACKAGE_PREFIXES "${PACKAGE_PREFIXES}")
list(SORT SORTED_PACKAGE_PREFIXES)
list(REVERSE SORTED_PACKAGE_PREFIXES)
math(EXPR LAST_INDEX ${LAST_INDEX}-1)
foreach(SYMLINK_INDEX RANGE ${LAST_INDEX})
list(GET SORTED_PACKAGE_PREFIXES ${SYMLINK_INDEX} SRC_PATH)
list(FIND PACKAGE_PREFIXES "${SRC_PATH}" SYMLINK_INDEX) # reverse magic
string(LENGTH "${SRC_PATH}" SRC_PATH_LEN)
set(PARTS_CNT 0)
set(SCRIPT_PART "if [ \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}\" != \"${SRC_PATH}\" ]; then\n")
# both paths relocated
foreach(POINT_INDEX RANGE ${LAST_INDEX})
list(GET SORTED_PACKAGE_PREFIXES ${POINT_INDEX} POINT_PATH)
list(FIND PACKAGE_PREFIXES "${POINT_PATH}" POINT_INDEX) # reverse magic
string(LENGTH "${POINT_PATH}" POINT_PATH_LEN)
if(_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX})
if("${SYMLINK_INDEX}" EQUAL "${POINT_INDEX}")
set(INDENT "")
else()
set(SCRIPT_PART "${SCRIPT_PART} if [ \"$RPM_INSTALL_PREFIX${POINT_INDEX}\" != \"${POINT_PATH}\" ]; then\n")
set(INDENT " ")
endif()
foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX})
math(EXPR PARTS_CNT ${PARTS_CNT}+1)
math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
math(EXPR SRC_PATH_END ${SPLIT_INDEX}-${SRC_PATH_LEN})
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${SRC_PATH_LEN} ${SRC_PATH_END} SYMLINK_)
math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1+${POINT_PATH_LEN})
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
set(SCRIPT_PART "${SCRIPT_PART} ${INDENT}if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
set(SCRIPT_PART "${SCRIPT_PART} ${INDENT}ln -s \"$RPM_INSTALL_PREFIX${POINT_INDEX}${POINT_}\" \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}${SYMLINK_}\"\n")
set(SCRIPT_PART "${SCRIPT_PART} ${INDENT}CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
set(SCRIPT_PART "${SCRIPT_PART} ${INDENT}fi\n")
endforeach()
if(NOT "${SYMLINK_INDEX}" EQUAL "${POINT_INDEX}")
set(SCRIPT_PART "${SCRIPT_PART} fi\n")
endif()
endif()
endforeach()
# source path relocated
if(_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X)
foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X)
math(EXPR PARTS_CNT ${PARTS_CNT}+1)
math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
math(EXPR SRC_PATH_END ${SPLIT_INDEX}-${SRC_PATH_LEN})
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${SRC_PATH_LEN} ${SRC_PATH_END} SYMLINK_)
math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1)
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
set(SCRIPT_PART "${SCRIPT_PART} if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
set(SCRIPT_PART "${SCRIPT_PART} ln -s \"${POINT_}\" \"$RPM_INSTALL_PREFIX${SYMLINK_INDEX}${SYMLINK_}\"\n")
set(SCRIPT_PART "${SCRIPT_PART} CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
set(SCRIPT_PART "${SCRIPT_PART} fi\n")
endforeach()
endif()
if(PARTS_CNT)
set(SCRIPT "${SCRIPT_PART}")
set(SCRIPT "${SCRIPT}fi\n")
endif()
endforeach()
# point path relocated
foreach(POINT_INDEX RANGE ${LAST_INDEX})
list(GET SORTED_PACKAGE_PREFIXES ${POINT_INDEX} POINT_PATH)
list(FIND PACKAGE_PREFIXES "${POINT_PATH}" POINT_INDEX) # reverse magic
string(LENGTH "${POINT_PATH}" POINT_PATH_LEN)
if(_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX})
set(SCRIPT "${SCRIPT}if [ \"$RPM_INSTALL_PREFIX${POINT_INDEX}\" != \"${POINT_PATH}\" ]; then\n")
foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX})
math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} 0 ${SPLIT_INDEX} SYMLINK_)
math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1+${POINT_PATH_LEN})
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
set(SCRIPT "${SCRIPT} if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
set(SCRIPT "${SCRIPT} ln -s \"$RPM_INSTALL_PREFIX${POINT_INDEX}${POINT_}\" \"${SYMLINK_}\"\n")
set(SCRIPT "${SCRIPT} CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}=true\n")
set(SCRIPT "${SCRIPT} fi\n")
endforeach()
set(SCRIPT "${SCRIPT}fi\n")
endif()
endforeach()
# no path relocated
if(_RPM_RELOCATION_SCRIPT_X_X)
foreach(RELOCATION_NO IN LISTS _RPM_RELOCATION_SCRIPT_X_X)
math(EXPR RELOCATION_INDEX ${RELOCATION_NO}-1)
list(GET _RPM_RELOCATION_SCRIPT_PAIRS ${RELOCATION_INDEX} RELOCATION_SCRIPT_PAIR)
string(FIND "${RELOCATION_SCRIPT_PAIR}" ":" SPLIT_INDEX)
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} 0 ${SPLIT_INDEX} SYMLINK_)
math(EXPR POINT_PATH_START ${SPLIT_INDEX}+1)
string(SUBSTRING ${RELOCATION_SCRIPT_PAIR} ${POINT_PATH_START} -1 POINT_)
set(SCRIPT "${SCRIPT}if [ -z \"$CPACK_RPM_RELOCATED_SYMLINK_${RELOCATION_INDEX}\" ]; then\n")
set(SCRIPT "${SCRIPT} ln -s \"${POINT_}\" \"${SYMLINK_}\"\n")
set(SCRIPT "${SCRIPT}fi\n")
endforeach()
endif()
set(RPM_SYMLINK_POSTINSTALL "${SCRIPT}" PARENT_SCOPE)
endfunction()
function(cpack_rpm_symlink_add_for_relocation_script PACKAGE_PREFIXES SYMLINK SYMLINK_RELOCATION_PATHS POINT POINT_RELOCATION_PATHS)
list(LENGTH SYMLINK_RELOCATION_PATHS SYMLINK_PATHS_COUTN)
list(LENGTH POINT_RELOCATION_PATHS POINT_PATHS_COUNT)
list(APPEND _RPM_RELOCATION_SCRIPT_PAIRS "${SYMLINK}:${POINT}")
list(LENGTH _RPM_RELOCATION_SCRIPT_PAIRS PAIR_NO)
if(SYMLINK_PATHS_COUTN)
foreach(SYMLINK_RELOC_PATH IN LISTS SYMLINK_RELOCATION_PATHS)
list(FIND PACKAGE_PREFIXES "${SYMLINK_RELOC_PATH}" SYMLINK_INDEX)
# source path relocated
list(APPEND _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X "${PAIR_NO}")
list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_X")
foreach(POINT_RELOC_PATH IN LISTS POINT_RELOCATION_PATHS)
list(FIND PACKAGE_PREFIXES "${POINT_RELOC_PATH}" POINT_INDEX)
# both paths relocated
list(APPEND _RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX} "${PAIR_NO}")
list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_${SYMLINK_INDEX}_${POINT_INDEX}")
# point path relocated
list(APPEND _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX} "${PAIR_NO}")
list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX}")
endforeach()
endforeach()
elseif(POINT_PATHS_COUNT)
foreach(POINT_RELOC_PATH IN LISTS POINT_RELOCATION_PATHS)
list(FIND PACKAGE_PREFIXES "${POINT_RELOC_PATH}" POINT_INDEX)
# point path relocated
list(APPEND _RPM_RELOCATION_SCRIPT_X_${POINT_INDEX} "${PAIR_NO}")
list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_${POINT_INDEX}")
endforeach()
endif()
# no path relocated
list(APPEND _RPM_RELOCATION_SCRIPT_X_X "${PAIR_NO}")
list(APPEND RELOCATION_VARS "_RPM_RELOCATION_SCRIPT_X_X")
# place variables into parent scope
foreach(VAR IN LISTS RELOCATION_VARS)
set(${VAR} "${${VAR}}" PARENT_SCOPE)
endforeach()
set(_RPM_RELOCATION_SCRIPT_PAIRS "${_RPM_RELOCATION_SCRIPT_PAIRS}" PARENT_SCOPE)
set(REQUIRES_SYMLINK_RELOCATION_SCRIPT "true" PARENT_SCOPE)
set(DIRECTIVE "%ghost " PARENT_SCOPE)
endfunction()
function(cpack_rpm_prepare_install_files 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 does
# 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}")
string(LENGTH "${WDIR}" WDR_LEN_)
list(SORT INSTALL_FILES_LIST) # make file order consistent on all platforms
foreach(F IN LISTS INSTALL_FILES_LIST)
unset(DIRECTIVE)
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_
OUTPUT_STRIP_TRAILING_WHITESPACE)
string(FIND "${SYMLINK_POINT_}" "->" SYMLINK_POINT_INDEX_ REVERSE)
math(EXPR SYMLINK_POINT_INDEX_ ${SYMLINK_POINT_INDEX_}+3)
string(LENGTH "${SYMLINK_POINT_}" SYMLINK_POINT_LENGTH_)
# get destination path
string(SUBSTRING "${SYMLINK_POINT_}" ${SYMLINK_POINT_INDEX_} ${SYMLINK_POINT_LENGTH_} SYMLINK_POINT_)
# check if path is relative or absolute
string(SUBSTRING "${SYMLINK_POINT_}" 0 1 SYMLINK_IS_ABSOLUTE_)
if(${SYMLINK_IS_ABSOLUTE_} STREQUAL "/")
# prevent absolute paths from having /../ or /./ section inside of them
get_filename_component(SYMLINK_POINT_ "${SYMLINK_POINT_}" ABSOLUTE)
else()
# handle relative path
get_filename_component(SYMLINK_POINT_ "${SYMLINK_LOCATION_}/${SYMLINK_POINT_}" ABSOLUTE)
endif()
string(SUBSTRING "${SYMLINK_POINT_}" ${WDR_LEN_} -1 SYMLINK_POINT_WD_)
cpack_rpm_symlink_get_relocation_prefixes("${F}" "${PACKAGE_PREFIXES}" "SYMLINK_RELOCATIONS")
cpack_rpm_symlink_get_relocation_prefixes("${SYMLINK_POINT_WD_}" "${PACKAGE_PREFIXES}" "POINT_RELOCATIONS")
list(LENGTH SYMLINK_RELOCATIONS SYMLINK_RELOCATIONS_COUNT)
list(LENGTH POINT_RELOCATIONS POINT_RELOCATIONS_COUNT)
if(SYMLINK_RELOCATIONS_COUNT AND POINT_RELOCATIONS_COUNT)
# find matching
foreach(SYMLINK_RELOCATION_PREFIX IN LISTS SYMLINK_RELOCATIONS)
list(FIND POINT_RELOCATIONS "${SYMLINK_RELOCATION_PREFIX}" FOUND_INDEX)
if(NOT ${FOUND_INDEX} EQUAL -1)
break()
endif()
endforeach()
if(NOT ${FOUND_INDEX} EQUAL -1)
# symlinks have the same subpath
if(${SYMLINK_RELOCATIONS_COUNT} EQUAL 1 AND ${POINT_RELOCATIONS_COUNT} EQUAL 1)
# permanent symlink
get_filename_component(SYMLINK_LOCATION_ "${F}" DIRECTORY)
file(RELATIVE_PATH FINAL_PATH_ ${SYMLINK_LOCATION_} ${SYMLINK_POINT_WD_})
execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${FINAL_PATH_}" "${WDIR}/${F}")
else()
# relocation subpaths
cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
"${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
endif()
else()
# not on the same relocation path
cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
"${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
endif()
elseif(POINT_RELOCATIONS_COUNT)
# point is relocatable
cpack_rpm_symlink_add_for_relocation_script("${PACKAGE_PREFIXES}" "${F}" "${SYMLINK_RELOCATIONS}"
"${SYMLINK_POINT_WD_}" "${POINT_RELOCATIONS}")
else()
# is not relocatable or points to non relocatable path - permanent symlink
execute_process(COMMAND "${CMAKE_COMMAND}" -E create_symlink "${SYMLINK_POINT_WD_}" "${WDIR}/${F}")
endif()
endif()
elseif(IS_DIRECTORY "${WDIR}/${F}")
set(DIRECTIVE "%dir ")
endif()
set(INSTALL_FILES "${INSTALL_FILES}${DIRECTIVE}\"${F}\"\n")
endforeach()
if(REQUIRES_SYMLINK_RELOCATION_SCRIPT)
cpack_rpm_symlink_create_relocation_script("${PACKAGE_PREFIXES}")
endif()
set(RPM_SYMLINK_POSTINSTALL "${RPM_SYMLINK_POSTINSTALL}" PARENT_SCOPE)
set(CPACK_RPM_INSTALL_FILES "${INSTALL_FILES}" PARENT_SCOPE)
endfunction()
if(CMAKE_BINARY_DIR) if(CMAKE_BINARY_DIR)
message(FATAL_ERROR "CPackRPM.cmake may only be used by CPack internally.") message(FATAL_ERROR "CPackRPM.cmake may only be used by CPack internally.")
endif() endif()
@ -963,9 +1293,10 @@ function(cpack_rpm_generate_package)
# destinct parent paths of other relocation paths and remove the # destinct parent paths of other relocation paths and remove the
# final element (so the install-prefix dir itself is not omitted # final element (so the install-prefix dir itself is not omitted
# from the RPM's content-list) # from the RPM's content-list)
list(SORT RPM_USED_PACKAGE_PREFIXES) set(SORTED_RPM_USED_PACKAGE_PREFIXES "${RPM_USED_PACKAGE_PREFIXES}")
list(SORT SORTED_RPM_USED_PACKAGE_PREFIXES)
set(_DISTINCT_PATH "NOT_SET") set(_DISTINCT_PATH "NOT_SET")
foreach(_RPM_RELOCATION_PREFIX ${RPM_USED_PACKAGE_PREFIXES}) foreach(_RPM_RELOCATION_PREFIX ${SORTED_RPM_USED_PACKAGE_PREFIXES})
if(NOT "${_RPM_RELOCATION_PREFIX}" MATCHES "${_DISTINCT_PATH}/.*") if(NOT "${_RPM_RELOCATION_PREFIX}" MATCHES "${_DISTINCT_PATH}/.*")
set(_DISTINCT_PATH "${_RPM_RELOCATION_PREFIX}") set(_DISTINCT_PATH "${_RPM_RELOCATION_PREFIX}")
@ -1142,25 +1473,13 @@ function(cpack_rpm_generate_package)
set(CPACK_RPM_ABSOLUTE_INSTALL_FILES "") set(CPACK_RPM_ABSOLUTE_INSTALL_FILES "")
endif() endif()
# Prepare install files
# Prepend directories in ${CPACK_RPM_INSTALL_FILES} with %dir cpack_rpm_prepare_install_files(
# This is necessary to avoid duplicate files since rpmbuild do "${CPACK_RPM_INSTALL_FILES}"
# recursion on its own when encountering a pathname which is a directory "${WDIR}"
# which is not flagged as %dir "${RPM_USED_PACKAGE_PREFIXES}"
string(STRIP "${CPACK_RPM_INSTALL_FILES}" CPACK_RPM_INSTALL_FILES_LIST) "${CPACK_RPM_PACKAGE_RELOCATABLE}"
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 "")
# The name of the final spec file to be used by rpmbuild # 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") set(CPACK_RPM_BINARY_SPECFILE "${CPACK_RPM_ROOTDIR}/SPECS/${CPACK_RPM_PACKAGE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_NAME}.spec")
@ -1246,6 +1565,7 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT
%clean %clean
%post %post
\@RPM_SYMLINK_POSTINSTALL\@
\@CPACK_RPM_SPEC_POSTINSTALL\@ \@CPACK_RPM_SPEC_POSTINSTALL\@
%postun %postun

View File

@ -991,6 +991,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
${build_generator_args} ${build_generator_args}
--build-project CPackComponentsForAll --build-project CPackComponentsForAll
--build-options ${build_options} --build-options ${build_options}
-DCPACK_GENERATOR:STRING=${CPackGen}
-DCPACK_BINARY_${CPackGen}:BOOL=ON -DCPACK_BINARY_${CPackGen}:BOOL=ON
${CPackRun_CPackComponentWay} ${CPackRun_CPackComponentWay}
${CPackComponentsForAll_BUILD_OPTIONS} ${CPackComponentsForAll_BUILD_OPTIONS}

View File

@ -49,6 +49,44 @@ install(FILES mylib.h
DESTINATION include DESTINATION include
COMPONENT headers) COMPONENT headers)
if("${CPACK_GENERATOR}" MATCHES "RPM")
# Package symbolic links
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two/depth_three COMPONENT libraries)
install(DIRECTORY DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two/different_relocatable/bar COMPONENT libraries)
install(DIRECTORY DESTINATION other_relocatable/depth_two COMPONENT libraries)
install(DIRECTORY DESTINATION non_relocatable/depth_two COMPONENT libraries)
# test symbolic links to same dir
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink depth_three symlink_samedir_path)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_samedir_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
# test symbolic links to same dir with current dir ./ prefix
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ./depth_three symlink_samedir_path_current_dir)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_samedir_path_current_dir DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
# test symbolic links to same dir with longer relative path
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../../../${CMAKE_INSTALL_LIBDIR}/.././${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/./depth_two/depth_three symlink_samedir_path_longer)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_samedir_path_longer DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
# test symbolic links to sub dir
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../../${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two/depth_three symlink_subdir_path)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_subdir_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one COMPONENT libraries)
# test symbolic links to parent dir
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././../../../${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/./depth_two symlink_parentdir_path)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_parentdir_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two/depth_three COMPONENT libraries)
# test symbolic link to another relocatable path
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././.././../other_relocatable/./depth_two symlink_other_relocatable_path)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_other_relocatable_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two COMPONENT libraries)
# test symbolic link to non relocatable path
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././../../non_relocatable/./depth_two symlink_to_non_relocatable_path)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_to_non_relocatable_path DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two COMPONENT libraries)
# test symbolic link from non relocatable path
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink .././../${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two symlink_from_non_relocatable_path)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_from_non_relocatable_path DESTINATION non_relocatable/depth_two COMPONENT libraries)
# test symbolic link relocatable path to its relocatable subpath
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ../../inside_relocatable_two/depth_two/different_relocatable/bar symlink_relocatable_subpath)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_relocatable_subpath DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
# test symbolic link to location outside package
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ./outside_package symlink_outside_package)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/symlink_outside_package DESTINATION ${CMAKE_INSTALL_LIBDIR}/inside_relocatable_one/depth_two COMPONENT libraries)
endif()
# CPack boilerplate for this project # CPack boilerplate for this project
set(CPACK_PACKAGE_NAME "MyLib") set(CPACK_PACKAGE_NAME "MyLib")
set(CPACK_PACKAGE_CONTACT "None") set(CPACK_PACKAGE_CONTACT "None")
@ -114,7 +152,8 @@ set(CPACK_COMPONENT_APPLICATIONS_INSTALL_TYPES Full)
# can not be used in CPack scripts due to CMAKE_SIZEOF_VOID_P # can not be used in CPack scripts due to CMAKE_SIZEOF_VOID_P
# variable not being set # variable not being set
set(CPACK_RPM_RELOCATION_PATHS "${CMAKE_INSTALL_INCLUDEDIR}" set(CPACK_RPM_RELOCATION_PATHS "${CMAKE_INSTALL_INCLUDEDIR}"
"${CMAKE_INSTALL_LIBDIR}" "${CMAKE_INSTALL_BINDIR}") "${CMAKE_INSTALL_LIBDIR}" "${CMAKE_INSTALL_BINDIR}" "other_relocatable"
"${CMAKE_INSTALL_LIBDIR}/inside_relocatable_two/depth_two/different_relocatable")
# We may use the CPack specific config file in order # We may use the CPack specific config file in order
# to tailor CPack behavior on a CPack generator specific way # to tailor CPack behavior on a CPack generator specific way

View File

@ -1,3 +1,7 @@
# prevent older policies from interfearing with this script
cmake_policy(PUSH)
cmake_policy(VERSION ${CMAKE_VERSION})
message(STATUS "=============================================================================") message(STATUS "=============================================================================")
message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
message(STATUS "") message(STATUS "")
@ -138,6 +142,7 @@ if(CPackGen MATCHES "RPM")
"An extremely useful application that makes use of MyLib") "An extremely useful application that makes use of MyLib")
set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION set(CPACK_COMPONENT_LIBRARIES_DESCRIPTION
"Static libraries used to build programs with MyLib") "Static libraries used to build programs with MyLib")
set(LIB_SUFFIX "6?4?")
# test package info # test package info
if(${CPackComponentWay} STREQUAL "IgnoreGroup") if(${CPackComponentWay} STREQUAL "IgnoreGroup")
@ -174,10 +179,32 @@ if(CPackGen MATCHES "RPM")
if(check_file_libraries_match) if(check_file_libraries_match)
set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*") set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
set(check_file_match_expected_description ".*${CPACK_COMPONENT_LIBRARIES_DESCRIPTION}.*") set(check_file_match_expected_description ".*${CPACK_COMPONENT_LIBRARIES_DESCRIPTION}.*")
set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${LIB_SUFFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/other_relocatable${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}${LIB_SUFFIX}/inside_relocatable_two/depth_two/different_relocatable")
set(check_file_match_expected_architecture "") # we don't explicitly set this value so it is different on each platform - ignore it set(check_file_match_expected_architecture "") # we don't explicitly set this value so it is different on each platform - ignore it
set(spec_regex "*libraries*") set(spec_regex "*libraries*")
set(check_content_list "^/usr/foo/bar/lib.*\n/usr/foo/bar/lib.*/libmylib.a$") set(check_content_list "^/usr/foo/bar/lib${LIB_SUFFIX}
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/depth_three
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/depth_three/symlink_parentdir_path
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_outside_package
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_relocatable_subpath
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_samedir_path
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_samedir_path_current_dir
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/depth_two/symlink_samedir_path_longer
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_one/symlink_subdir_path
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/different_relocatable
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/different_relocatable/bar
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/symlink_other_relocatable_path
/usr/foo/bar/lib${LIB_SUFFIX}/inside_relocatable_two/depth_two/symlink_to_non_relocatable_path
/usr/foo/bar/lib${LIB_SUFFIX}/libmylib.a
/usr/foo/bar/non_relocatable
/usr/foo/bar/non_relocatable/depth_two
/usr/foo/bar/non_relocatable/depth_two/symlink_from_non_relocatable_path
/usr/foo/bar/other_relocatable
/usr/foo/bar/other_relocatable/depth_two$")
elseif(check_file_headers_match) elseif(check_file_headers_match)
set(check_file_match_expected_summary ".*${CPACK_RPM_headers_PACKAGE_SUMMARY}.*") set(check_file_match_expected_summary ".*${CPACK_RPM_headers_PACKAGE_SUMMARY}.*")
set(check_file_match_expected_description ".*${CPACK_RPM_headers_PACKAGE_DESCRIPTION}.*") set(check_file_match_expected_description ".*${CPACK_RPM_headers_PACKAGE_DESCRIPTION}.*")
@ -188,10 +215,12 @@ if(CPackGen MATCHES "RPM")
elseif(check_file_applications_match) elseif(check_file_applications_match)
set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*") 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_description ".*${CPACK_COMPONENT_APPLICATIONS_DESCRIPTION}.*")
set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}.*") set(check_file_match_expected_relocation_path "Relocations${whitespaces}:${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR}")
set(check_file_match_expected_architecture "armv7hf") set(check_file_match_expected_architecture "armv7hf")
set(spec_regex "*applications*") set(spec_regex "*applications*")
set(check_content_list "^/usr/foo/bar\n/usr/foo/bar/bin\n/usr/foo/bar/bin/mylibapp$") set(check_content_list "^/usr/foo/bar
/usr/foo/bar/bin
/usr/foo/bar/bin/mylibapp$")
elseif(check_file_Unspecified_match) elseif(check_file_Unspecified_match)
set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*") set(check_file_match_expected_summary ".*${CPACK_RPM_PACKAGE_SUMMARY}.*")
set(check_file_match_expected_description ".*DESCRIPTION.*") set(check_file_match_expected_description ".*DESCRIPTION.*")
@ -269,5 +298,59 @@ if(CPackGen MATCHES "RPM")
message(FATAL_ERROR "error: '${check_file}' rpm package content does not match expected value - regex '${check_content_list}'; RPM output: '${check_package_content}'; generated spec file: '${spec_file_content}'") message(FATAL_ERROR "error: '${check_file}' rpm package content does not match expected value - regex '${check_content_list}'; RPM output: '${check_package_content}'; generated spec file: '${spec_file_content}'")
endif() endif()
endforeach() endforeach()
#######################
# verify generated symbolic links
#######################
file(GLOB_RECURSE symlink_files RELATIVE "${CPackComponentsForAll_BINARY_DIR}" "${CPackComponentsForAll_BINARY_DIR}/*/symlink_*")
foreach(check_symlink IN LISTS symlink_files)
get_filename_component(symlink_name "${check_symlink}" NAME)
execute_process(COMMAND ls -la "${check_symlink}"
WORKING_DIRECTORY "${CPackComponentsForAll_BINARY_DIR}"
OUTPUT_VARIABLE SYMLINK_POINT_
OUTPUT_STRIP_TRAILING_WHITESPACE)
if("${symlink_name}" STREQUAL "symlink_samedir_path"
OR "${symlink_name}" STREQUAL "symlink_samedir_path_current_dir"
OR "${symlink_name}" STREQUAL "symlink_samedir_path_longer")
string(REGEX MATCH "^.*${whitespaces}->${whitespaces}depth_three$" check_symlink "${SYMLINK_POINT_}")
elseif("${symlink_name}" STREQUAL "symlink_subdir_path")
string(REGEX MATCH "^.*${whitespaces}->${whitespaces}depth_two/depth_three$" check_symlink "${SYMLINK_POINT_}")
elseif("${symlink_name}" STREQUAL "symlink_parentdir_path")
string(REGEX MATCH "^.*${whitespaces}->${whitespaces}../$" check_symlink "${SYMLINK_POINT_}")
elseif("${symlink_name}" STREQUAL "symlink_to_non_relocatable_path")
string(REGEX MATCH "^.*${whitespaces}->${whitespaces}${CPACK_PACKAGING_INSTALL_PREFIX}/non_relocatable/depth_two$" check_symlink "${SYMLINK_POINT_}")
elseif("${symlink_name}" STREQUAL "symlink_outside_package")
string(REGEX MATCH "^.*${whitespaces}->${whitespaces}outside_package$" check_symlink "${SYMLINK_POINT_}")
elseif("${symlink_name}" STREQUAL "symlink_other_relocatable_path"
OR "${symlink_name}" STREQUAL "symlink_from_non_relocatable_path"
OR "${symlink_name}" STREQUAL "symlink_relocatable_subpath")
# these links were not canged - post install script only - ignore them
else()
message(FATAL_ERROR "error: unexpected rpm symbolic link '${check_symlink}'")
endif()
if(NOT check_symlink)
message(FATAL_ERROR "symlink points to unexpected location '${SYMLINK_POINT_}'")
endif()
endforeach()
# verify post install symlink relocation script
file(GLOB_RECURSE spec_file "${CPackComponentsForAll_BINARY_DIR}/*libraries*.spec")
file(READ ${spec_file} spec_file_content)
file(READ "${CMAKE_CURRENT_LIST_DIR}/symlink_postinstall_expected.txt" symlink_postinstall_expected)
# prepare regex
string(STRIP "${symlink_postinstall_expected}" symlink_postinstall_expected)
string(REPLACE "[" "\\[" symlink_postinstall_expected "${symlink_postinstall_expected}")
string(REPLACE "$" "\\$" symlink_postinstall_expected "${symlink_postinstall_expected}")
string(REPLACE "lib" "lib${LIB_SUFFIX}" symlink_postinstall_expected "${symlink_postinstall_expected}")
# compare
string(REGEX MATCH ".*${symlink_postinstall_expected}.*" symlink_postinstall_expected_matches "${spec_file_content}")
if(NOT symlink_postinstall_expected_matches)
message(FATAL_ERROR "error: unexpected rpm symbolic link postinstall script! generated spec file: '${spec_file_content}'")
endif()
endif() endif()
endif() endif()
cmake_policy(POP)

View File

@ -0,0 +1,57 @@
if [ "$RPM_INSTALL_PREFIX0" != "/usr/foo/bar/lib" ]; then
if [ "$RPM_INSTALL_PREFIX1" != "/usr/foo/bar/other_relocatable" ]; then
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
ln -s "$RPM_INSTALL_PREFIX1/depth_two" "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
CPACK_RPM_RELOCATED_SYMLINK_1=true
fi
fi
if [ "$RPM_INSTALL_PREFIX2" != "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable" ]; then
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
ln -s "$RPM_INSTALL_PREFIX2/bar" "$RPM_INSTALL_PREFIX0/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
CPACK_RPM_RELOCATED_SYMLINK_0=true
fi
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
ln -s "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/different_relocatable/bar" "$RPM_INSTALL_PREFIX0/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
CPACK_RPM_RELOCATED_SYMLINK_0=true
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
ln -s "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable/bar" "$RPM_INSTALL_PREFIX0/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
CPACK_RPM_RELOCATED_SYMLINK_0=true
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
ln -s "/usr/foo/bar/other_relocatable/depth_two" "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
CPACK_RPM_RELOCATED_SYMLINK_1=true
fi
fi
if [ "$RPM_INSTALL_PREFIX1" != "/usr/foo/bar/other_relocatable" ]; then
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
ln -s "$RPM_INSTALL_PREFIX1/depth_two" "/usr/foo/bar/lib/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
CPACK_RPM_RELOCATED_SYMLINK_1=true
fi
fi
if [ "$RPM_INSTALL_PREFIX2" != "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable" ]; then
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
ln -s "$RPM_INSTALL_PREFIX2/bar" "/usr/foo/bar/lib/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
CPACK_RPM_RELOCATED_SYMLINK_0=true
fi
fi
if [ "$RPM_INSTALL_PREFIX0" != "/usr/foo/bar/lib" ]; then
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
ln -s "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two/different_relocatable/bar" "/usr/foo/bar/lib/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
CPACK_RPM_RELOCATED_SYMLINK_0=true
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_2" ]; then
ln -s "$RPM_INSTALL_PREFIX0/inside_relocatable_two/depth_two" "/usr/foo/bar/non_relocatable/depth_two/symlink_from_non_relocatable_path"
CPACK_RPM_RELOCATED_SYMLINK_2=true
fi
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_0" ]; then
ln -s "/usr/foo/bar/lib/inside_relocatable_two/depth_two/different_relocatable/bar" "/usr/foo/bar/lib/inside_relocatable_one/depth_two/symlink_relocatable_subpath"
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_1" ]; then
ln -s "/usr/foo/bar/other_relocatable/depth_two" "/usr/foo/bar/lib/inside_relocatable_two/depth_two/symlink_other_relocatable_path"
fi
if [ -z "$CPACK_RPM_RELOCATED_SYMLINK_2" ]; then
ln -s "/usr/foo/bar/lib/inside_relocatable_two/depth_two" "/usr/foo/bar/non_relocatable/depth_two/symlink_from_non_relocatable_path"
fi