diff --git a/debian/wine_addons_root/wine_addons_build.sh b/debian/wine_addons_root/wine_addons_build.sh index 2985ef1..5a2ad41 100755 --- a/debian/wine_addons_root/wine_addons_build.sh +++ b/debian/wine_addons_root/wine_addons_build.sh @@ -1,7 +1,7 @@ #!/bin/env bash # Compile DXVK git on Debian/Ubuntu/Mint and variants -# Copyright (C) 2019 Pekka Helenius +# Copyright (C) 2019, 2022 Pekka Helenius # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -57,9 +57,9 @@ git_branch_dxvk=${params[8]} git_branch_glslang=${params[9]} git_branch_meson=${params[10]} -git_source_dxvknvapi=${params[12]} -git_source_vkd3dproton=${params[13]} -git_source_dxvk=${params[14]} +git_source_dxvknvapi_debian=${params[19]} +git_source_vkd3dproton_debian=${params[20]} +git_source_dxvk_debian=${params[21]} git_source_glslang_debian=${params[15]} git_source_meson_debian=${params[16]} @@ -119,7 +119,7 @@ known_wines=( 'wine-staging-git' ) -# Alternative remote dependency packages for Debian distributions which offer too old packages for DXVK +# Alternative remote dependency packages for Debian distributions which offer too old packages for Wine addons # # Left side: , # Right side: package alternative source URL @@ -127,27 +127,24 @@ known_wines=( # NOTE: Determine these packages in corresponding debdata files as runtime or buildtime dependencies # # As this seems to be a dependency for binutils-mingw packages -function binutils_common_ver() { - if [[ $(dpkg -s binutils-common &>/dev/null)$? -ne 0 ]]; then - sudo apt -y install binutils-common - fi - - if [[ $? -eq 0 ]]; then - binutils_ver=$(dpkg -s binutils-common | sed -rn 's/^Version: ([0-9\.]+).*$/\1/p') - fi - -} +if [[ $(dpkg -s "binutils-common" &>/dev/null)$? -ne 0 ]]; then + sudo apt -y install "binutils-common" +fi -binutils_common_ver +binutils_ver=$(dpkg -s "binutils-common" | sed -rn 's/^Version: ([0-9\.]+).*$/\1/p') -remotePackagesUrls=( - "http://mirrors.edge.kernel.org/ubuntu/pool/universe/b/binutils-mingw-w64" - "http://mirrors.edge.kernel.org/ubuntu/pool/universe/g/gcc-mingw-w64" - "http://mirrors.edge.kernel.org/ubuntu/pool/universe/m/mingw-w64" +remote_package_repositories=( + "https://mirrors.edge.kernel.org/ubuntu/pool/universe/d/directx-headers" + "https://mirrors.edge.kernel.org/ubuntu/pool/main/i/isl" + "https://mirrors.edge.kernel.org/ubuntu/pool/universe/b/binutils-mingw-w64" + "https://mirrors.edge.kernel.org/ubuntu/pool/universe/g/gcc-mingw-w64" + "https://mirrors.edge.kernel.org/ubuntu/pool/universe/m/mingw-w64" ) -remotePackagesPool=( +remote_packages_pool=( + "directx-headers-dev" + "libisl22" "gcc-mingw-w64-base" "mingw-w64-common" "binutils-mingw-w64-x86-64" @@ -160,60 +157,178 @@ remotePackagesPool=( "g++-mingw-w64-i686" ) -typeset -A remotePackagesAlt -for rpp in ${remotePackagesPool[@]}; do +# NOTE: Package versions defined here *must* exist in some of the repositories! +typeset -A remote_packages_version_locks +remote_packages_version_locks=( + [directx-headers-dev]="1.606.4" +) + +pkg_multi_data_binutils=() + +typeset -A rpp_alternatives +typeset -A remote_packages_selected +typeset -A remote_packages_alt_available - for URL in "${remotePackagesUrls[@]}"; do +for rpp in "${remote_packages_pool[@]}"; do - # Fetch exact package name and associated date - pkg_data=$(curl -s "${URL}/" | sed -rn 's/.*href="(.*(amd64|all)\.deb)">.*([0-9]{2}\-[A-Za-z]{3}\-[0-9]{4}).*/\1 \3/p' | sed 's/%2B/+/g' | grep "${rpp}") + version_len=100 + new_rpp_url= + new_rpp_token= + version_lock= + version_lock_set=0 + rpp_alternative_time=-1 + alt_remote_epoch_time=-1 + alt_remote_flat_version=-1 - if [[ ${pkg_data} = "" ]]; then - continue + rpp_alternatives=() + remote_packages_alt_available=() + + for package_version_lock in ${!remote_packages_version_locks[@]}; do + + if [[ ${rpp} == ${package_version_lock} ]]; then + version_lock=${remote_packages_version_locks[${package_version_lock}]} + version_lock_set=1 + break 1 fi - # Associate Unix-formatted date with the exact package name - IFS=$'\n' - for ps in ${pkg_data[@]}; do - ps_pkg=$(printf "%s" "${ps}" | awk '{print $1}') - ps_date=$(date --date=$(printf "%s" "${ps}" | awk '{print $NF}') +%s) - remotePackagesAltDate+=("${ps_date}|${ps_pkg}") - done - IFS=" " + done + + for source_url in "${remote_package_repositories[@]}"; do + + # Fetch exact package name and associated date. + # rpp_rx is just for regex escaping purposes. + rpp_rx=$(echo ${rpp} | sed 's/\+/\\\+/g') + pkg_multi_data=( + $(curl -s "${source_url}/" | \ + sed -rn 's/.*href="(.*(amd64|all)\.deb)">.*([0-9]{2}\-[A-Za-z]{3}\-[0-9]{4}).*/\1|\3/p' | \ + sed 's/%2B/+/g' | grep -E "${rpp_rx}_[0-9]" | xargs echo + ) + ) - # Sort exact package names by date - remotePackagesAltDateSorted=($(sort <<<"${remotePackagesAltDate[*]}")) + [[ ${#pkg_multi_data[@]} -eq 0 ]] && continue - # binutils packages depend on system binutils-common. Versions must match, even if not the newest package available. - if [[ ${ps_pkg} =~ binutils ]] && [[ ${binutils_ver} != "" ]]; then - for b in ${remotePackagesAltDateSorted[@]}; do + # binutils packages depend on system binutils-common. + # Versions must match, even if the newest package is not available. + if [[ ${rpp} =~ binutils ]] && [[ ${binutils_ver} != "" ]]; then + for b in "${pkg_multi_data[@]}"; do if [[ ${b} =~ ${binutils_ver} ]]; then - remotePackagesAltBinUtils+=(${b}) + pkg_multi_data_binutils+=("${b}") fi done - unset remotePackagesAltDateSorted - remotePackagesAltDateSorted=(${remotePackagesAltBinUtils[@]}) - unset remotePackagesAltBinUtils + pkg_multi_data=( ${pkg_multi_data_binutils[@]} ) + unset pkg_multi_data_binutils fi - # Get the newest exact package name - pkg=$(printf "%s" ${remotePackagesAltDateSorted[-1]} | sed -r 's/^[0-9]+\|(.*)/\1/') - unset remotePackagesAltDate - unset remotePackagesAltDateSorted + # TODO: Remove duplicate functionality + # Check relevant version parts while collecting + # different versions of a package. + # version_len is count of relevant parts. + # + # For instance + # - In a case of versions 2.23.1, 2.28 and 2.34.6.1 + # count of relevant parts is 2 as determined by + # version 2.28. + # In this fair comparison, we therefore consider + # normalized version 2.23, 2.28 and 2.34 + # + for pkg_data in "${pkg_multi_data[@]}"; do + + rpp_pkg=$(printf '%s' "${pkg_data}" | awk -F '|' '{print $1}') + rpp_version_raw=$(printf '%s' $(echo "${rpp_pkg}" | sed -r 's/.*_(.*[0-9]+)\-.*_(all|amd64).*/\1/g;')) + + version_parts=( $(echo ${rpp_version_raw} | sed 's/\./ /g') ) + + new_version_len=$(printf '%d' ${#version_parts[@]}) + + if [[ ${new_version_len} -lt ${version_len} ]]; then + version_len=${new_version_len} + fi - # Prepare and set a well-formatted value into remotePackagesAlt associative array - if [ ! "${pkg}" == "" ]; then - rpp_url=$(printf "%s/%s" "${URL}" "${pkg}") - rpp_shortver=$(printf "%s" "${pkg}" | sed -r 's/.*_(.*[0-9]+)\-.*_(all|amd64).*/\1/g; s/[^0-9]//g') + done - rpp_token=$(printf "%s,%d" "${rpp}" "${rpp_shortver}") - remotePackagesAlt+=(["${rpp_token}"]="${rpp_url}") + # Add each version of a package into associated array remote_packages_alt_available + # We collect the next information here for each entry: + # - package normalized version number + # - package release date in epoch format + # - package source root url and .deb name + # + # This information is collected so that we can determine which + # package version to use, and which URL is associated to it. + # + for pkg_data in "${pkg_multi_data[@]}"; do + + rpp_pkg=$(printf '%s' "${pkg_data}" | awk -F '|' '{print $1}') + rpp_epoch_time=$(date --date=$(printf '%s' "${ps}" | awk -F '|' '{print $2}') +%s) + rpp_version_raw=$(printf '%s' $(echo "${rpp_pkg}" | sed -r 's/.*_(.*[0-9]+)\-.*_(all|amd64).*/\1/g;')) + + version_parts=( $(echo ${rpp_version_raw} | sed 's/\./ /g') ) + relevant_version_parts=( ${version_parts[@]:0:${version_len}} ) + + rpp_flat_version=$(printf '%d' $(echo ${relevant_version_parts[@]} | sed 's/ //g')) + rpp_dot_version=$(echo ${relevant_version_parts[@]} | sed 's/ /./g') + + rpp_token=$(printf '%s,%d,%d,%s' "${rpp}" "${rpp_epoch_time}" "${rpp_flat_version}" "${rpp_dot_version}") + rpp_url=$(printf '%s/%s' "${source_url}" "${rpp_pkg}") + + remote_packages_alt_available+=(["${rpp_token}"]="${rpp_url}") + + done + + done + + # For collected package versions, get the highest available + # + for alt_remote_package in "${!remote_packages_alt_available[@]}"; do + + new_alt_remote_epoch_time=$(echo ${alt_remote_package} | awk -F ',' '{print $2}') + new_alt_remote_flat_version=$(echo ${alt_remote_package} | awk -F ',' '{print $3}') + new_alt_remote_dot_version=$(echo ${alt_remote_package} | awk -F ',' '{print $4}') + + # TODO: Remove duplicate functionality + if [[ ${version_lock} =~ ${new_alt_remote_dot_version} ]]; then + + alt_remote_epoch_time=${new_alt_remote_epoch_time} + alt_remote_flat_version=${new_alt_remote_flat_version} + alt_remote_dot_version=${new_alt_remote_dot_version} + + new_rpp_token=${alt_remote_package} + new_rpp_url=${remote_packages_alt_available[${alt_remote_package}]} + + rpp_alternatives+=(["${new_rpp_token}"]="${new_rpp_url}|${alt_remote_epoch_time}|${alt_remote_flat_version}") - break 1 fi + + if [[ ${new_alt_remote_flat_version} -ge ${alt_remote_flat_version} ]] && [[ ${version_lock_set} -eq 0 ]]; then + alt_remote_epoch_time=${new_alt_remote_epoch_time} + alt_remote_flat_version=${new_alt_remote_flat_version} + alt_remote_dot_version=${new_alt_remote_dot_version} + + new_rpp_token=${alt_remote_package} + new_rpp_url=${remote_packages_alt_available[${alt_remote_package}]} + + rpp_alternatives+=(["${new_rpp_token}"]="${new_rpp_url}|${alt_remote_epoch_time}|${alt_remote_flat_version}") + fi + done + # Do epoch time comparison for collected package versions + # + for rpp_alternative in ${!rpp_alternatives[@]}; do + + new_rpp_alternative=${rpp_alternative} + new_rpp_alternative_time=$(printf '%d' $(echo ${rpp_alternative} | awk -F '|' '{print $2}') ) + + if [[ ${new_rpp_alternative_time} -gt ${rpp_alternative_time} ]]; then + rpp_alternative_time=${new_rpp_alternative_time} + fi + + rpp_alternative=${new_rpp_alternative} + + done + + remote_packages_selected+=( ["${rpp}"]=$(echo "${rpp_alternatives[$rpp_alternative]}|${version_lock_set}") ) + done # Posix-compliant MingW alternative executables @@ -238,7 +353,7 @@ tempLinks=( ######################################################## -function runtimeCheck() { +function runtime_check() { local pkgreq_name local known_pkgs @@ -272,14 +387,14 @@ ${pkgreq_name} should be installed in order to use DXVK, DXVK NVAPI and VKD3D Pr # If the script is interrupted (Ctrl+C/SIGINT), do the following -function wineAddonsIntCleanup() { +function wine_addons_int_cleanup() { rm -rf ${WINE_ADDONS_ROOT}/{dxvk-git,meson,glslang,*.deb} rm -rf ${WINE_ADDONS_ROOT}/../compiled_deb/"${datedir}" exit 0 } # Allow interruption of the script at any time (Ctrl + C) -trap "wineAddonsIntCleanup" INT +trap "wine_addons_int_cleanup" INT ######################################################## @@ -301,7 +416,7 @@ fi # Check do we need to compile the package # given as input for this function -function pkgcompilecheck() { +function pkg_compile_check() { local install_function local pkg @@ -360,12 +475,12 @@ function addon_install_custom() { # ADDON - CUSTOM PATCHES # Add and apply custom addon patches - function addon_custompatches() { + function addon_custom_patches() { local CURDIR local dxvk_builddir_name local dxvk_builddir_path - + # Get our current directory, since we will change it during patching process below # We want to go back here after having applied the patches CURDIR="${PWD}" @@ -378,7 +493,7 @@ function addon_install_custom() { # TODO Expecting just one folder here. This method doesn't work with multiple dirs present if [[ $(echo ${dxvk_builddir_name} | wc -l) -gt 1 ]]; then - echo -e "\e[1mERROR:\e[0m Multiple entries in dxvk build directory detected. Can't decide which one to use. Aborting\n" + echo -e "\e[1mERROR:\e[0m Multiple entries in addon build directory detected. Can't decide which one to use. Aborting\n" exit 1 fi @@ -387,12 +502,12 @@ function addon_install_custom() { cd "${dxvk_builddir_path}" for pfile in ../*.{patch,diff}; do if [[ -f ${pfile} ]]; then - echo -e "Applying DXVK patch: ${pfile}\n" + echo -e "Applying addon's patch: ${pfile}\n" patch -Np1 < ${pfile} fi if [[ $? -ne 0 ]]; then - echo -e "\e[1mERROR:\e[0m Error occured while applying DXVK patch '${pfile}'. Aborting\n" + echo -e "\e[1mERROR:\e[0m Error occured while applying addon's patch '${pfile}'. Aborting\n" cd ${CURDIR} exit 1 fi @@ -408,7 +523,7 @@ function addon_install_custom() { ############################ # ADDON - CUSTOM HOOKS EXECUTION - addon_custompatches && \ + addon_custom_patches && \ addon_posixpkgs } @@ -421,12 +536,12 @@ function fetch_extra_pkg_files() { local pkgname local pkgdir local extra_files_dir - + pkgname=${1} pkgdir=${2} extra_files_dir=${3} - cp -r ${extra_files_dir}/ ${pkgdir}/ + find ${extra_files_dir} -mindepth 1 -type f -exec cp -f {} ${pkgdir}/ \; } @@ -461,10 +576,11 @@ function compile_and_install_deb() { local _pkg_debbuilder="${15}" local _pkg_debcompat="${16}" local _pkg_compatfile="${17}" - + local extra_files_dir=$(find "../../extra_files/" -type d -iname "${_pkg_name%-git}") if [[ -d ${extra_files_dir} ]]; then + [[ ! -d "debian/source" ]] && mkdir -p "debian/source" fetch_extra_pkg_files ${_pkg_name} "debian/source" ${extra_files_dir} fi @@ -481,7 +597,7 @@ function compile_and_install_deb() { local s local IFS local y - + arrays=( '_pkg_deps_build' '_pkg_deps_runtime' @@ -507,13 +623,47 @@ function compile_and_install_deb() { ############################ function pkg_installcheck() { - return $(echo $(dpkg -s "${1}" &>/dev/null)$?) + + local full_pkg_name_found + + full_pkg_name_found_return_code=$(echo $(dpkg -s "${1}" &>/dev/null)$?) + + # Bad and error-prone fallback + if [[ ${full_pkg_name_found_return_code} -ne 0 ]]; then + full_pkg_name_matches=$(dpkg --get-selections | awk '{print $1}' | grep ^${1} | wc -l) + if [[ ${full_pkg_name_matches} -ne 0 ]]; then + full_pkg_name_found_return_code=0 + fi + fi + return ${full_pkg_name_found_return_code} } ############################ echo -e "Starting compilation$(if [[ ! -v NO_INSTALL ]] || [[ ${_pkg_name} =~ ^meson|glslang$ ]]; then printf " & installation"; fi) of ${_pkg_name}\n" +############################ + +function get_locked_packages() { + + local _lock_pkgs + + # Generate a list of version-locked-dependencies + if [[ ${#remote_packages_selected[@]} -gt 0 ]]; then + + for alt_remote_pkg in ${!remote_packages_selected[@]}; do + alt_remote_version_lock_set=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $4}') + + if [[ ${alt_remote_version_lock_set} -eq 1 ]]; then + _lock_pkgs+=(${alt_remote_pkg}) + fi + + done + fi + + echo "${_lock_pkgs[*]}" +} + ############################ # COMMON - PACKAGE DEPENDENCIES CHECK @@ -527,11 +677,15 @@ function compile_and_install_deb() { local a local b local _validlist + local _lock_pkgs + local is_locked local IFS _pkg_list=("${1}") _pkg_type="${2}" + _lock_pkgs=($(get_locked_packages)) + IFS=$'\n' _pkg_list=$(echo "${_pkg_list}" | sed 's/([^)]*)//g') unset IFS @@ -549,10 +703,20 @@ function compile_and_install_deb() { return 0 fi - # Generate a list of missing dependencies a=0 + # Generate a list of missing dependencies for p in ${_pkg_list[@]}; do - if [[ $(pkg_installcheck ${p%% *})$? -ne 0 ]]; then + + is_locked=0 + + for lock_pkg in "${_lock_pkgs[@]}"; do + if [[ ${p%% *} == ${lock_pkg} ]]; then + is_locked=1 + break 1 + fi + done + + if [[ $(pkg_installcheck ${p%% *})$? -ne 0 ]] || [[ ${is_locked} -eq 1 ]]; then _validlist[$a]=${p%% *} let a++ @@ -588,30 +752,53 @@ function compile_and_install_deb() { for _pkg_dep in ${_validlist[@]}; do echo -e "$(( $b + 1 ))/$(( ${#_validlist[*]} )) - Installing ${_pkg_name} ${_pkg_type_str} dependency ${_pkg_dep}" - if [[ ${#remotePackagesAlt[@]} -gt 0 ]]; then - for altRemote in ${!remotePackagesAlt[@]}; do - altRemotepkg=$(echo ${altRemote} | awk -F ',' '{print $1}') - altRemotever=$(echo ${altRemote} | awk -F ',' '{print $2}') - if [[ "${_pkg_dep}" == "${altRemotepkg}" ]]; then - if [[ $(pkg_installcheck ${altRemotepkg})$? -ne 0 ]]; then + if [[ ${#remote_packages_selected[@]} -gt 0 ]]; then + + for alt_remote_pkg in ${!remote_packages_selected[@]}; do + + if [[ "${_pkg_dep}" == "${alt_remote_pkg}" ]]; then + + alt_remote_url=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $1}') + alt_remote_version=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $3}') + alt_remote_version_lock_set=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $4}') + + # If remote pkg is not installed + if [[ $(pkg_installcheck ${alt_remote_pkg})$? -ne 0 ]]; then # TODO remove duplicate functionality - if [[ $(apt-cache show "${altRemotepkg}" | grep -m1 -oP "(?<=^Version: )[0-9|\.]*" | sed 's/\.//g') < ${altRemotever} ]]; then - pkg_localinstall ${remotePackagesAlt["${altRemote}"]} "${altRemotepkg}" - pkg_configure "${altRemotepkg}" ${remotePackagesAlt["${altRemote}"]} + repository_version=$(apt-cache show "${alt_remote_pkg}" 2>/dev/null | grep -m1 -oP "(?<=^Version: )[0-9|\.]*" | sed 's/\.//g') + [[ ! -z ${repository_version} ]] && repository_version=0 + + if [[ ${repository_version} -eq ${alt_remote_version} ]]; then + echo -e "Already updated. Skipping" + continue 1 + fi + + if [[ ${repository_version} -lt ${alt_remote_version} ]] || [[ ${alt_remote_version_lock_set} -eq 1 ]]; then + pkg_localinstall "${alt_remote_url}" "${alt_remote_pkg}" + pkg_configure "${alt_remote_pkg}" "${alt_remote_url}" else - pkg_remoteinstall "${altRemotepkg}" - pkg_configure "${altRemotepkg}" + pkg_remoteinstall "${alt_remote_pkg}" + pkg_configure "${alt_remote_pkg}" fi + + # If remote pkg is installed else - if [[ $(dpkg -s "${altRemotepkg}" | grep -m1 -oP "(?<=^Version: )[0-9|\.]*" | sed 's/\.//g') < ${altRemotever} ]]; then - pkg_localinstall ${remotePackagesAlt["${altRemote}"]} "${altRemotepkg}" - pkg_configure "${altRemotepkg}" ${remotePackagesAlt["${altRemote}"]} - else - pkg_remoteinstall "${altRemotepkg}" - pkg_configure "${altRemotepkg}" + local_version=$(dpkg -s "${alt_remote_pkg}" | grep -m1 -oP "(?<=^Version: )[0-9|\.]*" | sed 's/\.//g') + [[ ! -z ${local_version} ]] && local_version=0 + + if [[ ${local_version} -eq ${alt_remote_version} ]]; then + echo -e "Already updated. Skipping" + continue 1 fi + if [[ ${local_version} -lt ${alt_remote_version} ]] || [[ ${alt_remote_version_lock_set} -eq 1 ]]; then + pkg_localinstall "${alt_remote_url}" "${alt_remote_pkg}" + pkg_configure "${alt_remote_pkg}" "${alt_remote_url}" + else + pkg_remoteinstall "${alt_remote_pkg}" + pkg_configure "${alt_remote_pkg}" + fi fi fi done @@ -702,10 +889,14 @@ function compile_and_install_deb() { # Access the folder after which package specific debianbuild function will be run # That function is defined inside package specific install_main function below if [[ $? -eq 0 ]]; then + pkg_gitversion && \ mv ${_pkg_name} ${_pkg_name}-${_pkg_gitver} cd ${_pkg_name}-${_pkg_gitver} + # Get all required submodules + git submodule update --init --recursive + dh_make --createorig -s -y -c ${_pkg_license} && \ pkg_override_debianfile "${_pkg_debinstall}" "${_pkg_installfile}" pkg_override_debianfile "${_pkg_debcontrol}" "${_pkg_controlfile}" @@ -883,13 +1074,13 @@ function pkg_install_main() { ######################################################## # Check existence of known Wine packages -runtimeCheck Wine "${known_wines[*]}" +runtime_check Wine "${known_wines[*]}" # Meson - compile (& install) -pkgcompilecheck pkg_install_main meson "${WINE_ADDONS_ROOT}/../debdata/meson.debdata" +pkg_compile_check pkg_install_main meson "${WINE_ADDONS_ROOT}/../debdata/meson.debdata" # Glslang - compile (& install) -pkgcompilecheck pkg_install_main glslang "${WINE_ADDONS_ROOT}/../debdata/glslang.debdata" +pkg_compile_check pkg_install_main glslang "${WINE_ADDONS_ROOT}/../debdata/glslang.debdata" if [[ ! -v NO_DXVK ]]; then # DXVK - compile (& install)