diff --git a/share/rocmcmakebuildtools/cmake/ROCMPackageConfigHelpers.cmake b/share/rocmcmakebuildtools/cmake/ROCMPackageConfigHelpers.cmake index f15bfb94..631bbf6c 100644 --- a/share/rocmcmakebuildtools/cmake/ROCMPackageConfigHelpers.cmake +++ b/share/rocmcmakebuildtools/cmake/ROCMPackageConfigHelpers.cmake @@ -21,6 +21,16 @@ function(rocm_configure_package_config_file INPUT_FILE OUTPUT_FILE) message(FATAL_ERROR "INSTALL_DESTINATION is required for rocm_configure_package_config_file()") endif() + # CMAKE_INSTALL_MODE with symlinks and PREFIX is not supported because the symlink structure + # created by rocm_install_symlink_subdir() is incompatible with the config file's + # PACKAGE_PREFIX_DIR calculation when symlinks are followed by REALPATH. + # CMAKE_INSTALL_MODE symlink modes: SYMLINK, SYMLINK_OR_COPY, ABS_SYMLINK, ABS_SYMLINK_OR_COPY + if(PARSE_PREFIX AND NOT WIN32 AND "$ENV{CMAKE_INSTALL_MODE}" MATCHES "SYMLINK") + message(FATAL_ERROR + "CMAKE_INSTALL_MODE=$ENV{CMAKE_INSTALL_MODE} cannot be used with PREFIX argument. " + "Use either CMAKE_INSTALL_MODE with symlinks (without PREFIX) or PREFIX (without CMAKE_INSTALL_MODE symlinks).") + endif() + if(IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}") set(INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") else() @@ -70,9 +80,38 @@ endif() # Any changes to this file will be overwritten by the next CMake run #################################################################################### -get_filename_component(_ROCM_CMAKE_CURRENT_LIST_FILE_REAL \"\${CMAKE_CURRENT_LIST_FILE}\" REALPATH) -get_filename_component(_ROCM_CMAKE_CURRENT_LIST_DIR_REAL \"\${_ROCM_CMAKE_CURRENT_LIST_FILE_REAL}\" DIRECTORY) -get_filename_component(PACKAGE_PREFIX_DIR \"\${_ROCM_CMAKE_CURRENT_LIST_DIR_REAL}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE) +# Handle both PREFIX symlinks and CMAKE_INSTALL_MODE=SYMLINK by detecting directory structure. +# PREFIX symlinks (e.g., /opt/rocm -> /opt/rocm-7.2) preserve the install tree structure, +# so the real file and symlink have matching relative layouts (lib/cmake/foo/ in both). +# CMAKE_INSTALL_MODE=SYMLINK creates symlinks from install tree (lib/cmake/foo/) to build +# directory (build/), which has a different structure, breaking relative path assumptions. +get_filename_component( + _ROCM_CMAKE_CURRENT_LIST_FILE_REAL \"\${CMAKE_CURRENT_LIST_FILE}\" REALPATH) +get_filename_component( + _ROCM_CMAKE_CURRENT_LIST_DIR_REAL \"\${_ROCM_CMAKE_CURRENT_LIST_FILE_REAL}\" DIRECTORY) + +# Check if navigating from real dir through install structure returns to real dir. +# If yes, structure is preserved (PREFIX case); if no, structure differs (INSTALL_MODE case). +get_filename_component( + _ROCM_STRUCTURE_CHECK + \"\${_ROCM_CMAKE_CURRENT_LIST_DIR_REAL}/${PACKAGE_RELATIVE_PATH}/${PACKAGE_INSTALL_RELATIVE_DIR}\" + ABSOLUTE) + +if(\"\${_ROCM_STRUCTURE_CHECK}\" STREQUAL \"\${_ROCM_CMAKE_CURRENT_LIST_DIR_REAL}\") + # Structure preserved - use REALPATH (handles PREFIX symlinks like /opt/rocm -> /opt/rocm-7.2) + get_filename_component( + PACKAGE_PREFIX_DIR \"\${_ROCM_CMAKE_CURRENT_LIST_DIR_REAL}/${PACKAGE_RELATIVE_PATH}\" + ABSOLUTE) +else() + # Structure differs - use ABSOLUTE to preserve symlink path (handles CMAKE_INSTALL_MODE=SYMLINK) + get_filename_component( + _ROCM_CMAKE_CURRENT_LIST_FILE_ABS \"\${CMAKE_CURRENT_LIST_FILE}\" ABSOLUTE) + get_filename_component( + _ROCM_CMAKE_CURRENT_LIST_DIR_ABS \"\${_ROCM_CMAKE_CURRENT_LIST_FILE_ABS}\" DIRECTORY) + get_filename_component( + PACKAGE_PREFIX_DIR \"\${_ROCM_CMAKE_CURRENT_LIST_DIR_ABS}/${PACKAGE_RELATIVE_PATH}\" + ABSOLUTE) +endif() ${CHECK_PREFIX} diff --git a/test/fail/simple-prefix-install-mode-symlink.cmake b/test/fail/simple-prefix-install-mode-symlink.cmake new file mode 100644 index 00000000..fbff8b25 --- /dev/null +++ b/test/fail/simple-prefix-install-mode-symlink.cmake @@ -0,0 +1,14 @@ +# ###################################################################################################################### +# Copyright (C) 2017 Advanced Micro Devices, Inc. +# ###################################################################################################################### + +set(ENV{CMAKE_INSTALL_MODE} "SYMLINK") +install_dir( + ${TEST_DIR}/libsimple + CMAKE_ARGS -DROCM_PREFIX=simple + TARGETS package) +test_expect_file(${PREFIX}/include/simple.h) +if(NOT WIN32) + test_expect_file(${PREFIX}/simple/include/simple.h) +endif() +install_dir(${TEST_DIR}/libbasic) diff --git a/test/pass/simple-install-mode-symlink.cmake b/test/pass/simple-install-mode-symlink.cmake new file mode 100644 index 00000000..35836806 --- /dev/null +++ b/test/pass/simple-install-mode-symlink.cmake @@ -0,0 +1,12 @@ +# ###################################################################################################################### +# Copyright (C) 2017 Advanced Micro Devices, Inc. +# ###################################################################################################################### + +set(ENV{CMAKE_INSTALL_MODE} "SYMLINK") +install_dir( + ${TEST_DIR}/libsimple + CMAKE_ARGS + TARGETS package) +test_expect_file(${PREFIX}/include/simple.h) + +install_dir(${TEST_DIR}/libbasic) diff --git a/test/test.cmake b/test/test.cmake index 9b0e2411..5c10818f 100755 --- a/test/test.cmake +++ b/test/test.cmake @@ -149,10 +149,20 @@ function(install_dir DIR) cmake_parse_arguments(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - configure_dir( - ${DIR} - TARGETS all ${PARSE_TARGETS} install - CMAKE_ARGS ${PARSE_CMAKE_ARGS} -DROCM_SYMLINK_LIBS=OFF) + # When CMAKE_INSTALL_MODE is SYMLINK, we need to preserve the build directory + # because installed files are symlinks pointing to it + if("$ENV{CMAKE_INSTALL_MODE}" STREQUAL "SYMLINK") + configure_dir( + ${DIR} + BUILD_DIR_VAR PRESERVED_BUILD_DIR + TARGETS all ${PARSE_TARGETS} install + CMAKE_ARGS ${PARSE_CMAKE_ARGS} -DROCM_SYMLINK_LIBS=OFF) + else() + configure_dir( + ${DIR} + TARGETS all ${PARSE_TARGETS} install + CMAKE_ARGS ${PARSE_CMAKE_ARGS} -DROCM_SYMLINK_LIBS=OFF) + endif() endfunction() function(write_version_cmake DIR VERSION CONTENT)