Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vcpkg_fixup_pkgconfig] HOTFIX -- revert #19469 (#19607) #713

Merged
merged 1 commit into from
Aug 17, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
213 changes: 94 additions & 119 deletions scripts/cmake/vcpkg_fixup_pkgconfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -45,174 +45,149 @@ Still work in progress. If there are more cases which can be handled here feel f
* [brotli](https://github.com/Microsoft/vcpkg/blob/master/ports/brotli/portfile.cmake)
#]===]

function(z_vcpkg_fixup_pkgconfig_check_files file config)
set(path_suffix_debug /debug)
set(path_suffix_release "")
function(vcpkg_fixup_pkgconfig_check_files pkg_cfg_cmd _file _config)
set(PATH_SUFFIX_DEBUG /debug)
set(PATH_SUFFIX_RELEASE)
set(PKGCONFIG_INSTALLED_DIR "${CURRENT_INSTALLED_DIR}${PATH_SUFFIX_${_config}}/lib/pkgconfig")
set(PKGCONFIG_INSTALLED_SHARE_DIR "${CURRENT_INSTALLED_DIR}/share/pkgconfig")
set(PKGCONFIG_PACKAGES_DIR "${CURRENT_PACKAGES_DIR}${PATH_SUFFIX_${_config}}/lib/pkgconfig")
set(PKGCONFIG_PACKAGES_SHARE_DIR "${CURRENT_PACKAGES_DIR}/share/pkgconfig")

if(DEFINED ENV{PKG_CONFIG_PATH})
set(backup_env_pkg_config_path "$ENV{PKG_CONFIG_PATH}")
set(BACKUP_ENV_PKG_CONFIG_PATH "$ENV{PKG_CONFIG_PATH}")
else()
unset(backup_env_pkg_config_path)
unset(BACKUP_ENV_PKG_CONFIG_PATH)
endif()

vcpkg_list(SET pkg_config_path
"${CURRENT_INSTALLED_DIR}${PATH_SUFFIX_${_config}}/lib/pkgconfig"
"${CURRENT_INSTALLED_DIR}/share/pkgconfig"
"${CURRENT_PACKAGES_DIR}${PATH_SUFFIX_${_config}}/lib/pkgconfig"
"${CURRENT_PACKAGES_DIR}/share/pkgconfig"
)
if(DEFINED ENV{PKG_CONFIG_PATH} AND NOT ENV{PKG_CONFIG_PATH} STREQUAL "")
vcpkg_list(APPEND pkg_config_path "$ENV{PKG_CONFIG_PATH}")
set(ENV{PKG_CONFIG_PATH} "${PKGCONFIG_INSTALLED_DIR}${VCPKG_HOST_PATH_SEPARATOR}${PKGCONFIG_INSTALLED_SHARE_DIR}${VCPKG_HOST_PATH_SEPARATOR}${PKGCONFIG_PACKAGES_DIR}${VCPKG_HOST_PATH_SEPARATOR}${PKGCONFIG_PACKAGES_SHARE_DIR}${VCPKG_HOST_PATH_SEPARATOR}$ENV{PKG_CONFIG_PATH}")
else()
set(ENV{PKG_CONFIG_PATH} "${PKGCONFIG_INSTALLED_DIR}${VCPKG_HOST_PATH_SEPARATOR}${PKGCONFIG_INSTALLED_SHARE_DIR}${VCPKG_HOST_PATH_SEPARATOR}${PKGCONFIG_PACKAGES_DIR}${VCPKG_HOST_PATH_SEPARATOR}${PKGCONFIG_PACKAGES_SHARE_DIR}")
endif()
vcpkg_list(JOIN pkg_config_path "${VCPKG_PATH_SEPARATOR}" pkg_config_path)
set(ENV{PKG_CONFIG_PATH} "${pkg_config_path}")

# First make sure everything is ok with the package and its deps
cmake_path(GET file STEM package_name)
debug_message("Checking package (${config}): ${package_name}")
execute_process(
COMMAND "${PKGCONFIG}" --print-errors --exists "${package_name}"
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}"
RESULT_VARIABLE error_var
OUTPUT_VARIABLE output
ERROR_VARIABLE output
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE
)
if(NOT "${error_var}" EQUAL "0")
message(FATAL_ERROR "${PKGCONFIG} --exists ${package_name} failed with error code: ${error_var}
ENV{PKG_CONFIG_PATH}: \"$ENV{PKG_CONFIG_PATH}\"
output: ${output}"
)
get_filename_component(_package_name "${_file}" NAME_WLE)
debug_message("Checking package (${_config}): ${_package_name}")
execute_process(COMMAND "${pkg_cfg_cmd}" --print-errors --exists ${_package_name}
WORKING_DIRECTORY "${CURRENT_BUILDTREES_DIR}"
RESULT_VARIABLE _pkg_error_var
OUTPUT_VARIABLE _pkg_output
ERROR_VARIABLE _pkg_error_out
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_STRIP_TRAILING_WHITESPACE
)
if(NOT _pkg_error_var EQUAL 0)
message(STATUS "pkg_cfg_cmd call with:${pkg_cfg_cmd} --exists ${_package_name} failed")
message(STATUS "ENV{PKG_CONFIG_PATH}:$ENV{PKG_CONFIG_PATH}")
message(STATUS "pkg-config call failed with error code:${_pkg_error_var}")
message(STATUS "pkg-config output:${_pkg_output}")
message(FATAL_ERROR "pkg-config error output:${_pkg_error_out}")
else()
debug_message("pkg-config --exists ${package_name} output: ${output}")
debug_message("pkg-config returned:${_pkg_error_var}")
debug_message("pkg-config output:${_pkg_output}")
debug_message("pkg-config error output:${_pkg_error_out}")
endif()
if(DEFINED backup_env_pkg_config_path)
set(ENV{PKG_CONFIG_PATH} "${backup_env_pkg_config_path}")
if(DEFINED BACKUP_ENV_PKG_CONFIG_PATH)
set(ENV{PKG_CONFIG_PATH} "${BACKUP_ENV_PKG_CONFIG_PATH}")
else()
unset(ENV{PKG_CONFIG_PATH})
endif()
endfunction()

function(vcpkg_fixup_pkgconfig)
cmake_parse_arguments(PARSE_ARGV 0 arg
"SKIP_CHECK"
""
"RELEASE_FILES;DEBUG_FILES;SYSTEM_LIBRARIES;SYSTEM_PACKAGES;IGNORE_FLAGS"
)

if(DEFINED arg_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "${CMAKE_CURRENT_FUNCTION} was passed extra arguments: ${arg_UNPARSED_ARGUMENTS}")
endif()
# parse parameters such that semicolons in options arguments to COMMAND don't get erased
cmake_parse_arguments(PARSE_ARGV 0 _vfpkg "SKIP_CHECK" "" "RELEASE_FILES;DEBUG_FILES;SYSTEM_LIBRARIES;SYSTEM_PACKAGES;IGNORE_FLAGS")

if(DEFINED arg_RELEASE_FILES AND NOT DEFINED arg_DEBUG_FILES)
message(FATAL_ERROR "DEBUG_FILES must be specified if RELEASE_FILES was specified.")
if(_vfpkg_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "vcpkg_fixup_pkgconfig() was passed extra arguments: ${_vfct_UNPARSED_ARGUMENTS}")
endif()
if(NOT DEFINED arg_RELEASE_FILES AND DEFINED arg_DEBUG_FILES)
message(FATAL_ERROR "RELEASE_FILES must be specified if DEBUG_FILES was specified.")

if((DEFINED _vfpkg_RELEASE_FILES AND NOT DEFINED _vfpkg_DEBUG_FILES) OR (NOT DEFINED _vfpkg_RELEASE_FILES AND DEFINED _vfpkg_DEBUG_FILES))
message(FATAL_ERROR "vcpkg_fixup_pkgconfig() requires both or neither of DEBUG_FILES and RELEASE_FILES")
endif()

if(NOT DEFINED arg_RELEASE_FILES)
file(GLOB_RECURSE arg_RELEASE_FILES "${CURRENT_PACKAGES_DIR}/**/*.pc")
file(GLOB_RECURSE arg_DEBUG_FILES "${CURRENT_PACKAGES_DIR}/debug/**/*.pc")
foreach(debug_file IN LISTS arg_DEBUG_FILES)
vcpkg_list(REMOVE_ITEM arg_RELEASE_FILES "${debug_file}")
endforeach()
if(NOT DEFINED _vfpkg_RELEASE_FILES)
file(GLOB_RECURSE _vfpkg_RELEASE_FILES "${CURRENT_PACKAGES_DIR}/**/*.pc")
file(GLOB_RECURSE _vfpkg_DEBUG_FILES "${CURRENT_PACKAGES_DIR}/debug/**/*.pc")
if(_vfpkg_DEBUG_FILES)
list(REMOVE_ITEM _vfpkg_RELEASE_FILES ${_vfpkg_DEBUG_FILES})
endif()
endif()

vcpkg_find_acquire_program(PKGCONFIG)
debug_message("Using pkg-config from: ${PKGCONFIG}")

string(REGEX REPLACE "^([a-zA-Z]):/" [[/\1/]] unix_packages_dir "${CURRENT_PACKAGES_DIR}")
string(REGEX REPLACE "^([a-zA-Z]):/" [[/\1/]] unix_installed_dir "${CURRENT_INSTALLED_DIR}")
#Absolute Unix like paths
string(REGEX REPLACE "([a-zA-Z]):/" "/\\1/" _VCPKG_PACKAGES_DIR "${CURRENT_PACKAGES_DIR}")
string(REGEX REPLACE "([a-zA-Z]):/" "/\\1/" _VCPKG_INSTALLED_DIR "${CURRENT_INSTALLED_DIR}")

foreach(config IN ITEMS RELEASE DEBUG)
debug_message("${config} Files: ${arg_${config}_FILES}")
if("${VCPKG_BUILD_TYPE}" STREQUAL "debug" AND "${config}" STREQUAL "RELEASE")
foreach(CONFIG RELEASE DEBUG)
debug_message("${CONFIG} Files: ${_vfpkg_${CONFIG}_FILES}")
if(VCPKG_BUILD_TYPE STREQUAL "debug" AND CONFIG STREQUAL "RELEASE")
continue()
endif()
if("${VCPKG_BUILD_TYPE}" STREQUAL "release" AND "${config}" STREQUAL "DEBUG")
if(VCPKG_BUILD_TYPE STREQUAL "release" AND CONFIG STREQUAL "DEBUG")
continue()
endif()
foreach(file IN LISTS "arg_${config}_FILES")
message(STATUS "Fixing pkgconfig file: ${file}")
cmake_path(GET file PARENT_PATH pkg_lib_search_path)
if("${config}" STREQUAL "DEBUG")
set(relative_pc_path "${CURRENT_PACKAGES_DIR}/debug")
cmake_path(RELATIVE_PATH relative_pc_path BASE_DIRECTORY "${pkg_lib_search_path}")
foreach(_file ${_vfpkg_${CONFIG}_FILES})
message(STATUS "Fixing pkgconfig file: ${_file}")
get_filename_component(PKG_LIB_SEARCH_PATH "${_file}" DIRECTORY)
if(CONFIG STREQUAL "DEBUG")
file(RELATIVE_PATH RELATIVE_PC_PATH "${PKG_LIB_SEARCH_PATH}" "${CURRENT_PACKAGES_DIR}/debug/")
else()
set(relative_pc_path "${CURRENT_PACKAGES_DIR}")
cmake_path(RELATIVE_PATH relative_pc_path BASE_DIRECTORY "${pkg_lib_search_path}")
file(RELATIVE_PATH RELATIVE_PC_PATH "${PKG_LIB_SEARCH_PATH}" "${CURRENT_PACKAGES_DIR}")
endif()
# strip trailing slash
string(REGEX REPLACE "/$" "" RELATIVE_PC_PATH "${RELATIVE_PC_PATH}")
#Correct *.pc file
file(READ "${file}" contents)

string(REPLACE "${CURRENT_PACKAGES_DIR}" [[${prefix}]] contents "${contents}")
string(REPLACE "${CURRENT_INSTALLED_DIR}" [[${prefix}]] contents "${contents}")
string(REPLACE "${unix_packages_dir}" [[${prefix}]] contents "${contents}")
string(REPLACE "${unix_installed_dir}" [[${prefix}]] contents "${contents}")

string(REGEX REPLACE "(^|\n)prefix[\t ]*=[^\n]*" "" contents "${contents}")
if("${config}" STREQUAL "DEBUG")
# prefix points at the debug subfolder
string(REPLACE [[${prefix}/debug]] [[${prefix}]] contents "${contents}")
string(REPLACE [[${prefix}/include]] [[${prefix}/../include]] contents "${contents}")
string(REPLACE [[${prefix}/share]] [[${prefix}/../share]] contents "${contents}")
file(READ "${_file}" _contents)
string(REPLACE "${CURRENT_PACKAGES_DIR}" "\${prefix}" _contents "${_contents}")
string(REPLACE "${CURRENT_INSTALLED_DIR}" "\${prefix}" _contents "${_contents}")
string(REPLACE "${_VCPKG_PACKAGES_DIR}" "\${prefix}" _contents "${_contents}")
string(REPLACE "${_VCPKG_INSTALLED_DIR}" "\${prefix}" _contents "${_contents}")
string(REGEX REPLACE "(^|\n)prefix[\t ]*=[^\n]*" "" _contents "${_contents}")
if(CONFIG STREQUAL "DEBUG")
string(REPLACE "}/debug" "}" _contents "${_contents}")
# Prefix points at the debug subfolder
string(REPLACE "\${prefix}/include" "\${prefix}/../include" _contents "${_contents}")
string(REPLACE "\${prefix}/share" "\${prefix}/../share" _contents "${_contents}")
endif()
# quote -L, -I, and -l paths starting with `${blah}`
string(REGEX REPLACE " -([LIl])(\\\${[^}]*}[^ \n\t]*)" [[ -\1"\2"]] contents "${contents}")
string(REGEX REPLACE " -L(\\\${[^}]*}[^ \n\t]*)" " -L\"\\1\"" _contents "${_contents}")
string(REGEX REPLACE " -I(\\\${[^}]*}[^ \n\t]*)" " -I\"\\1\"" _contents "${_contents}")
string(REGEX REPLACE " -l(\\\${[^}]*}[^ \n\t]*)" " -l\"\\1\"" _contents "${_contents}")
# This section fuses XYZ.private and XYZ according to VCPKG_LIBRARY_LINKAGE
#
# Pkgconfig searches Requires.private transitively for Cflags in the dynamic case,
# which prevents us from removing it.
#
# Once this transformation is complete, users of vcpkg should never need to pass
# --static.
if("${VCPKG_LIBRARY_LINKAGE}" STREQUAL "static")
# how this works:
# we want to transform:
# Libs: $1
# Libs.private: $2
# into
# Libs: $1 $2
# and the same thing for Requires and Requires.private

set(libs_line "")
set(requires_line "")
if("${contents}" MATCHES "Libs: *([^\n]*)")
string(APPEND libs_line " ${CMAKE_MATCH_1}")
endif()
if("${contents}" MATCHES "Libs.private: *([^\n]*)")
string(APPEND libs_line " ${CMAKE_MATCH_1}")
endif()
if("${contents}" MATCHES "Requires: *([^\n]*)")
string(APPEND requires_line " ${CMAKE_MATCH_1}")
endif()
if("${contents}" MATCHES "Requires.private: *([^\n]*)")
string(APPEND requires_line " ${CMAKE_MATCH_1}")
endif()

string(REGEX REPLACE "(^|\n)(Requires|Libs)(\\.private)?:[^\n]*\n" [[\1]] contents "${contents}")

if(NOT "${libs_line}" STREQUAL "")
string(APPEND contents "Libs:${libs_line}\n")
endif()
if(NOT "${requires_line}" STREQUAL "")
string(APPEND contents "Requires:${requires_line}\n")
endif()
if(VCPKG_LIBRARY_LINKAGE STREQUAL "static")
# Libs comes before Libs.private
string(REGEX REPLACE "(^|\n)(Libs: *[^\n]*)(.*)\nLibs.private:( *[^\n]*)" "\\1\\2\\4\\3" _contents "${_contents}")
# Libs.private comes before Libs
string(REGEX REPLACE "(^|\n)Libs.private:( *[^\n]*)(.*\nLibs: *[^\n]*)" "\\3\\2" _contents "${_contents}")
# Only Libs.private
string(REGEX REPLACE "(^|\n)Libs.private: *" "\\1Libs: " _contents "${_contents}")
# Requires comes before Requires.private
string(REGEX REPLACE "(^|\n)(Requires: *[^\n]*)(.*)\nRequires.private:( *[^\n]*)" "\\1\\2\\4\\3" _contents "${_contents}")
# Requires.private comes before Requires
string(REGEX REPLACE "(^|\n)Requires.private:( *[^\n]*)(.*\nRequires: *[^\n]*)" "\\3\\2" _contents "${_contents}")
# Only Requires.private
string(REGEX REPLACE "(^|\n)Requires.private: *" "\\1Requires: " _contents "${_contents}")
endif()
file(WRITE "${file}" "prefix=\${pcfiledir}/${relative_pc_path}\n${contents}")
file(WRITE "${_file}" "prefix=\${pcfiledir}/${RELATIVE_PC_PATH}\n${_contents}")
unset(PKG_LIB_SEARCH_PATH)
endforeach()

if(NOT arg_SKIP_CHECK) # The check can only run after all files have been corrected!
foreach(file IN LISTS "arg_${config}_FILES")
z_vcpkg_fixup_pkgconfig_check_files("${PKGCONFIG}" "${file}" "${config}")
if(NOT _vfpkg_SKIP_CHECK) # The check can only run after all files have been corrected!
foreach(_file ${_vfpkg_${CONFIG}_FILES})
vcpkg_fixup_pkgconfig_check_files("${PKGCONFIG}" "${_file}" "${CONFIG}")
endforeach()
endif()
endforeach()
debug_message("Fixing pkgconfig --- finished")

set(Z_VCPKG_FIXUP_PKGCONFIG_CALLED TRUE CACHE INTERNAL "See below" FORCE)
set(VCPKG_FIXUP_PKGCONFIG_CALLED TRUE CACHE INTERNAL "See below" FORCE)
# Variable to check if this function has been called!
# Theoreotically vcpkg could look for *.pc files and automatically call this function
# or check if this function has been called if *.pc files are detected.
Expand Down