mirror of
https://github.com/microsoft/vcpkg.git
synced 2024-12-24 04:47:51 +08:00
233f096536
Cherry-picked from https://github.com/microsoft/vcpkg/pull/38847: Fix processing of `INTERFACE_LINK_LIBS` when it contain `)` inside `"`, e.g. for `C:/Program Files (x86)/Windows Kits/10/Lib/10.0.22621.0/um/x64/User32.Lib` created by `pkg_check_modules` from `-luser32` as found in icu pc files. Without the fix, the property is not processed at all, pulling release libs into debug builds.
279 lines
14 KiB
CMake
279 lines
14 KiB
CMake
include_guard(GLOBAL)
|
|
|
|
function(vcpkg_cmake_config_fixup)
|
|
cmake_parse_arguments(PARSE_ARGV 0 "arg" "DO_NOT_DELETE_PARENT_CONFIG_PATH;NO_PREFIX_CORRECTION" "PACKAGE_NAME;CONFIG_PATH;TOOLS_PATH" "")
|
|
|
|
if(DEFINED arg_UNPARSED_ARGUMENTS)
|
|
message(FATAL_ERROR "vcpkg_cmake_config_fixup was passed extra arguments: ${arg_UNPARSED_ARGUMENTS}")
|
|
endif()
|
|
if(NOT arg_PACKAGE_NAME)
|
|
set(arg_PACKAGE_NAME "${PORT}")
|
|
endif()
|
|
if(NOT arg_CONFIG_PATH)
|
|
set(arg_CONFIG_PATH "share/${arg_PACKAGE_NAME}")
|
|
endif()
|
|
if(NOT arg_TOOLS_PATH)
|
|
set(arg_TOOLS_PATH "tools/${PORT}")
|
|
endif()
|
|
set(target_path "share/${arg_PACKAGE_NAME}")
|
|
|
|
string(REPLACE "." "\\." EXECUTABLE_SUFFIX "${VCPKG_TARGET_EXECUTABLE_SUFFIX}")
|
|
|
|
set(debug_share "${CURRENT_PACKAGES_DIR}/debug/${target_path}")
|
|
set(release_share "${CURRENT_PACKAGES_DIR}/${target_path}")
|
|
|
|
if(NOT arg_CONFIG_PATH STREQUAL "share/${arg_PACKAGE_NAME}")
|
|
if(arg_CONFIG_PATH STREQUAL "share")
|
|
set(arg_CONFIG_PATH z_vcpkg_share)
|
|
file(RENAME "${CURRENT_PACKAGES_DIR}/debug/share" "${CURRENT_PACKAGES_DIR}/debug/${arg_CONFIG_PATH}")
|
|
file(RENAME "${CURRENT_PACKAGES_DIR}/share" "${CURRENT_PACKAGES_DIR}/${arg_CONFIG_PATH}")
|
|
endif()
|
|
|
|
set(debug_config "${CURRENT_PACKAGES_DIR}/debug/${arg_CONFIG_PATH}")
|
|
set(release_config "${CURRENT_PACKAGES_DIR}/${arg_CONFIG_PATH}")
|
|
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
|
|
if(NOT EXISTS "${debug_config}")
|
|
message(FATAL_ERROR "'${debug_config}' does not exist.")
|
|
endif()
|
|
|
|
# This roundabout handling enables CONFIG_PATH = share
|
|
file(MAKE_DIRECTORY "${debug_share}")
|
|
file(GLOB files "${debug_config}/*")
|
|
file(COPY ${files} DESTINATION "${debug_share}")
|
|
file(REMOVE_RECURSE "${debug_config}")
|
|
endif()
|
|
|
|
file(GLOB files "${release_config}/*")
|
|
file(COPY ${files} DESTINATION "${release_share}")
|
|
file(REMOVE_RECURSE "${release_config}")
|
|
|
|
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
|
|
get_filename_component(debug_config_dir_name "${debug_config}" NAME)
|
|
string(TOLOWER "${debug_config_dir_name}" debug_config_dir_name)
|
|
if(debug_config_dir_name STREQUAL "cmake" AND NOT arg_DO_NOT_DELETE_PARENT_CONFIG_PATH)
|
|
file(REMOVE_RECURSE "${debug_config}")
|
|
else()
|
|
get_filename_component(debug_config_parent_dir "${debug_config}" DIRECTORY)
|
|
get_filename_component(debug_config_dir_name "${debug_config_parent_dir}" NAME)
|
|
string(TOLOWER "${debug_config_dir_name}" debug_config_dir_name)
|
|
if(debug_config_dir_name STREQUAL "cmake" AND NOT arg_DO_NOT_DELETE_PARENT_CONFIG_PATH)
|
|
file(REMOVE_RECURSE "${debug_config_parent_dir}")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
get_filename_component(release_config_dir_name "${release_config}" NAME)
|
|
string(TOLOWER "${release_config_dir_name}" release_config_dir_name)
|
|
if(release_config_dir_name STREQUAL "cmake" AND NOT arg_DO_NOT_DELETE_PARENT_CONFIG_PATH)
|
|
file(REMOVE_RECURSE "${release_config}")
|
|
else()
|
|
get_filename_component(release_config_parent_dir "${release_config}" DIRECTORY)
|
|
get_filename_component(release_config_dir_name "${release_config_parent_dir}" NAME)
|
|
string(TOLOWER "${release_config_dir_name}" release_config_dir_name)
|
|
if(release_config_dir_name STREQUAL "cmake" AND NOT arg_DO_NOT_DELETE_PARENT_CONFIG_PATH)
|
|
file(REMOVE_RECURSE "${release_config_parent_dir}")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
|
|
if(NOT EXISTS "${debug_share}")
|
|
message(FATAL_ERROR "'${debug_share}' does not exist.")
|
|
endif()
|
|
endif()
|
|
|
|
file(GLOB_RECURSE release_targets
|
|
"${release_share}/*-release.cmake"
|
|
)
|
|
foreach(release_target IN LISTS release_targets)
|
|
file(READ "${release_target}" contents)
|
|
string(REPLACE "${CURRENT_INSTALLED_DIR}" "\${_IMPORT_PREFIX}" contents "${contents}")
|
|
string(REGEX REPLACE "\\\${_IMPORT_PREFIX}/bin/([^ \"]+${EXECUTABLE_SUFFIX})" "\${_IMPORT_PREFIX}/${arg_TOOLS_PATH}/\\1" contents "${contents}")
|
|
file(WRITE "${release_target}" "${contents}")
|
|
endforeach()
|
|
|
|
if(NOT DEFINED VCPKG_BUILD_TYPE OR VCPKG_BUILD_TYPE STREQUAL "debug")
|
|
file(GLOB_RECURSE debug_targets
|
|
"${debug_share}/*-debug.cmake"
|
|
)
|
|
foreach(debug_target IN LISTS debug_targets)
|
|
file(RELATIVE_PATH debug_target_rel "${debug_share}" "${debug_target}")
|
|
|
|
file(READ "${debug_target}" contents)
|
|
string(REPLACE "${CURRENT_INSTALLED_DIR}" "\${_IMPORT_PREFIX}" contents "${contents}")
|
|
string(REGEX REPLACE "\\\${_IMPORT_PREFIX}/bin/([^ \";]+${EXECUTABLE_SUFFIX})" "\${_IMPORT_PREFIX}/${arg_TOOLS_PATH}/\\1" contents "${contents}")
|
|
string(REPLACE "\${_IMPORT_PREFIX}/lib" "\${_IMPORT_PREFIX}/debug/lib" contents "${contents}")
|
|
string(REPLACE "\${_IMPORT_PREFIX}/bin" "\${_IMPORT_PREFIX}/debug/bin" contents "${contents}")
|
|
file(WRITE "${release_share}/${debug_target_rel}" "${contents}")
|
|
|
|
file(REMOVE "${debug_target}")
|
|
endforeach()
|
|
endif()
|
|
|
|
#Fix ${_IMPORT_PREFIX} and absolute paths in cmake generated targets and configs;
|
|
#Since those can be renamed we have to check in every *.cmake, but only once.
|
|
file(GLOB_RECURSE main_cmakes "${release_share}/*.cmake")
|
|
if(NOT DEFINED Z_VCPKG_CMAKE_CONFIG_ALREADY_FIXED_UP)
|
|
vcpkg_list(SET Z_VCPKG_CMAKE_CONFIG_ALREADY_FIXED_UP)
|
|
endif()
|
|
foreach(already_fixed_up IN LISTS Z_VCPKG_CMAKE_CONFIG_ALREADY_FIXED_UP)
|
|
vcpkg_list(REMOVE_ITEM main_cmakes "${already_fixed_up}")
|
|
endforeach()
|
|
vcpkg_list(APPEND Z_VCPKG_CMAKE_CONFIG_ALREADY_FIXED_UP ${main_cmakes})
|
|
set(Z_VCPKG_CMAKE_CONFIG_ALREADY_FIXED_UP "${Z_VCPKG_CMAKE_CONFIG_ALREADY_FIXED_UP}" CACHE INTERNAL "")
|
|
|
|
foreach(main_cmake IN LISTS main_cmakes)
|
|
file(READ "${main_cmake}" contents)
|
|
# Note: I think the following comment is no longer true, since we now require the path to be `share/blah`
|
|
# however, I don't know it for sure.
|
|
# - nimazzuc
|
|
|
|
#This correction is not correct for all cases. To make it correct for all cases it needs to consider
|
|
#original folder deepness to CURRENT_PACKAGES_DIR in comparison to the moved to folder deepness which
|
|
#is always at least (>=) 2, e.g. share/${PORT}. Currently the code assumes it is always 2 although
|
|
#this requirement is only true for the *Config.cmake. The targets are not required to be in the same
|
|
#folder as the *Config.cmake!
|
|
if(NOT arg_NO_PREFIX_CORRECTION)
|
|
string(REGEX REPLACE
|
|
[[get_filename_component\(_IMPORT_PREFIX "\${CMAKE_CURRENT_LIST_FILE}" PATH\)(
|
|
get_filename_component\(_IMPORT_PREFIX "\${_IMPORT_PREFIX}" PATH\))*]]
|
|
[[get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
|
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
|
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)]]
|
|
contents "${contents}") # see #1044 for details why this replacement is necessary. See #4782 why it must be a regex.
|
|
string(REGEX REPLACE
|
|
[[get_filename_component\(PACKAGE_PREFIX_DIR "\${CMAKE_CURRENT_LIST_DIR}/\.\./(\.\./)*" ABSOLUTE\)]]
|
|
[[get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE)]]
|
|
contents "${contents}")
|
|
string(REGEX REPLACE
|
|
[[get_filename_component\(PACKAGE_PREFIX_DIR "\${CMAKE_CURRENT_LIST_DIR}/\.\.((\\|/)\.\.)*" ABSOLUTE\)]]
|
|
[[get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE)]]
|
|
contents "${contents}") # This is a meson-related workaround, see https://github.com/mesonbuild/meson/issues/6955
|
|
endif()
|
|
|
|
# Merge release and debug configurations of target property INTERFACE_LINK_LIBRARIES.
|
|
string(REPLACE "${release_share}/" "${debug_share}/" debug_cmake "${main_cmake}")
|
|
if(DEFINED VCPKG_BUILD_TYPE)
|
|
# Skip. Warning: A release-only port in a dual-config installation
|
|
# may pull release dependencies into the debug configuration.
|
|
elseif(NOT contents MATCHES "INTERFACE_LINK_LIBRARIES")
|
|
# Skip. No relevant properties.
|
|
elseif(NOT contents MATCHES "# Generated CMake target import file\\.")
|
|
# Skip. No safe assumptions about a matching debug import file.
|
|
elseif(NOT EXISTS "${debug_cmake}")
|
|
message(SEND_ERROR "Did not find a debug import file matching '${main_cmake}'")
|
|
else()
|
|
file(READ "${debug_cmake}" debug_contents)
|
|
set(remainder "${contents}")
|
|
while(remainder)
|
|
z_vcpkg_cmake_config_fixup_match_command("${remainder}" "set_target_properties(" matched_command remainder)
|
|
if(NOT matched_command MATCHES "set_target_properties[(]([^ \$]*) PROPERTIES.* INTERFACE_LINK_LIBRARIES \"([^\"]*)\"")
|
|
continue()
|
|
endif()
|
|
set(target "${CMAKE_MATCH_1}")
|
|
set(release_libs "${CMAKE_MATCH_2}")
|
|
z_vcpkg_cmake_config_fixup_match_command("${debug_contents}" "set_target_properties(${target} " debug_command unused)
|
|
if(NOT debug_command MATCHES " INTERFACE_LINK_LIBRARIES \"([^\"]*)\"")
|
|
message(SEND_ERROR "Did not find a debug configuration for target '${target}'.")
|
|
continue()
|
|
endif()
|
|
set(debug_libs "${CMAKE_MATCH_1}")
|
|
z_vcpkg_cmake_config_fixup_merge(merged_libs release_libs debug_libs)
|
|
string(REPLACE " INTERFACE_LINK_LIBRARIES \"${release_libs}\"" " INTERFACE_LINK_LIBRARIES \"${merged_libs}\"" updated_command "${matched_command}")
|
|
string(REPLACE "${matched_command}" "${updated_command}" contents "${contents}")
|
|
endwhile()
|
|
endif()
|
|
|
|
#Fix absolute paths to installed dir with ones relative to ${CMAKE_CURRENT_LIST_DIR}
|
|
#This happens if vcpkg built libraries are directly linked to a target instead of using
|
|
#an imported target.
|
|
string(REPLACE "${CURRENT_INSTALLED_DIR}" [[${VCPKG_IMPORT_PREFIX}]] contents "${contents}")
|
|
file(TO_CMAKE_PATH "${CURRENT_PACKAGES_DIR}" cmake_current_packages_dir)
|
|
string(REPLACE "${cmake_current_packages_dir}" [[${VCPKG_IMPORT_PREFIX}]] contents "${contents}")
|
|
# If ${VCPKG_IMPORT_PREFIX} was actually used, inject a definition of it:
|
|
string(FIND "${contents}" [[${VCPKG_IMPORT_PREFIX}]] index)
|
|
if (NOT index STREQUAL "-1")
|
|
get_filename_component(main_cmake_dir "${main_cmake}" DIRECTORY)
|
|
# Calculate relative to be a sequence of "../"
|
|
file(RELATIVE_PATH relative "${main_cmake_dir}" "${cmake_current_packages_dir}")
|
|
string(PREPEND contents "get_filename_component(VCPKG_IMPORT_PREFIX \"\${CMAKE_CURRENT_LIST_DIR}\/${relative}\" ABSOLUTE)\n")
|
|
endif()
|
|
|
|
file(WRITE "${main_cmake}" "${contents}")
|
|
endforeach()
|
|
|
|
file(GLOB_RECURSE unused_files
|
|
"${debug_share}/*[Tt]argets.cmake"
|
|
"${debug_share}/*[Cc]onfig.cmake"
|
|
"${debug_share}/*[Cc]onfigVersion.cmake"
|
|
"${debug_share}/*[Cc]onfig-version.cmake"
|
|
)
|
|
foreach(unused_file IN LISTS unused_files)
|
|
file(REMOVE "${unused_file}")
|
|
endforeach()
|
|
|
|
# Remove /debug/<target_path>/ if it's empty.
|
|
file(GLOB_RECURSE remaining_files "${debug_share}/*")
|
|
if(remaining_files STREQUAL "")
|
|
file(REMOVE_RECURSE "${debug_share}")
|
|
endif()
|
|
|
|
# Remove /debug/share/ if it's empty.
|
|
file(GLOB_RECURSE remaining_files "${CURRENT_PACKAGES_DIR}/debug/share/*")
|
|
if(remaining_files STREQUAL "")
|
|
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")
|
|
endif()
|
|
endfunction()
|
|
|
|
# Match a command from "<needle>" to ")\n". On match, returns the command and
|
|
# the remainder from haystack. Otherwise, returns empty values.
|
|
function(z_vcpkg_cmake_config_fixup_match_command haystack needle out_match out_remainder)
|
|
set(match "")
|
|
set(remainder "")
|
|
string(FIND "${haystack}" "${needle}" first)
|
|
if(NOT first EQUAL "-1")
|
|
string(SUBSTRING "${haystack}" ${first} -1 tmp)
|
|
string(FIND "${tmp}" ")\n" bound)
|
|
if(NOT bound EQUAL "-1")
|
|
math(EXPR bound "${bound} + 2")
|
|
string(SUBSTRING "${tmp}" 0 ${bound} match)
|
|
string(SUBSTRING "${tmp}" "${bound}" -1 remainder)
|
|
endif()
|
|
endif()
|
|
set("${out_match}" "${match}" PARENT_SCOPE)
|
|
set("${out_remainder}" "${remainder}" PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
# Merges link interface library lists for release and debug
|
|
# into a single expression which use generator expression as necessary.
|
|
function(z_vcpkg_cmake_config_fixup_merge out_var release_var debug_var)
|
|
set(release_libs "VCPKG;${${release_var}}")
|
|
string(REGEX REPLACE ";optimized;([^;]*)" ";\\1" release_libs "${release_libs}")
|
|
string(REGEX REPLACE ";debug;([^;]*)" ";" release_libs "${release_libs}")
|
|
list(REMOVE_AT release_libs 0)
|
|
list(FILTER release_libs EXCLUDE REGEX [[^\\[$]<\\[$]<CONFIG:DEBUG>:]])
|
|
list(TRANSFORM release_libs REPLACE [[^\\[$]<\\[$]<NOT:\\[$]<CONFIG:DEBUG>>:(.*)>$]] "\\1")
|
|
|
|
set(debug_libs "VCPKG;${${debug_var}}")
|
|
string(REGEX REPLACE ";optimized;([^;]*)" ";" debug_libs "${debug_libs}")
|
|
string(REGEX REPLACE ";debug;([^;]*)" ";\\1" debug_libs "${debug_libs}")
|
|
list(REMOVE_AT debug_libs 0)
|
|
list(FILTER debug_libs EXCLUDE REGEX [[^\\[$]<\\[$]<NOT:\\[$]<CONFIG:DEBUG>>:]])
|
|
list(TRANSFORM debug_libs REPLACE [[^\\[$]<\\[$]<CONFIG:DEBUG>:(.*)>$]] "\\1")
|
|
|
|
set(merged_libs "")
|
|
foreach(release_lib debug_lib IN ZIP_LISTS release_libs debug_libs)
|
|
if(release_lib STREQUAL debug_lib)
|
|
list(APPEND merged_libs "${release_lib}")
|
|
else()
|
|
if(release_lib)
|
|
list(APPEND merged_libs "\\\$<\\\$<NOT:\\\$<CONFIG:DEBUG>>:${release_lib}>")
|
|
endif()
|
|
if(debug_lib)
|
|
list(APPEND merged_libs "\\\$<\\\$<CONFIG:DEBUG>:${debug_lib}>")
|
|
endif()
|
|
endif()
|
|
endforeach()
|
|
set("${out_var}" "${merged_libs}" PARENT_SCOPE)
|
|
endfunction()
|