Automate installation of DXVK, D9VK + Wine/Wine Staging & update GPU drivers + PlayonLinux wineprefixes (Debian/Ubuntu/Mint/Arch Linux/Manjaro)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1101 lines
31 KiB

6 years ago
6 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. #!/bin/env bash
  2. # Compile DXVK git on Debian/Ubuntu/Mint and variants
  3. # Copyright (C) 2019, 2022 Pekka Helenius
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation, either version 3 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. ########################################################
  18. # DO NOT RUN INDIVIDUALLY, ONLY VIA ../../updatewine.sh PARENT SCRIPT!
  19. ########################################################
  20. # Root directory of this script file
  21. WINE_ADDONS_ROOT="${PWD}"
  22. # datedir variable supplied by ../updatewine_debian.sh script file
  23. datedir="${1}"
  24. ########################################################
  25. # Divide input args into array indexes
  26. i=0
  27. for p in ${@:2}; do
  28. params[$i]=${p}
  29. let i++
  30. done
  31. ########################################################
  32. # Parse input git override hashes
  33. # This order is mandatory!
  34. # If you change the order or contents of 'githash_overrides'
  35. # array in ../updatewine.sh, make sure to update these
  36. # variables!
  37. #
  38. git_commithash_dxvknvapi=${params[0]}
  39. git_commithash_vkd3dproton=${params[1]}
  40. git_commithash_dxvk=${params[2]}
  41. git_commithash_glslang=${params[3]}
  42. git_commithash_meson=${params[4]}
  43. git_branch_dxvknvapi=${params[6]}
  44. git_branch_vkd3dproton=${params[7]}
  45. git_branch_dxvk=${params[8]}
  46. git_branch_glslang=${params[9]}
  47. git_branch_meson=${params[10]}
  48. git_source_dxvknvapi_debian=${params[19]}
  49. git_source_vkd3dproton_debian=${params[20]}
  50. git_source_dxvk_debian=${params[21]}
  51. git_source_glslang_debian=${params[15]}
  52. git_source_meson_debian=${params[16]}
  53. ########################################################
  54. # Parse input arguments, filter user parameters
  55. # The range is defined in ../updatewine.sh
  56. # All input arguments are:
  57. # <datedir> 4*<githash_override> 4*<gitbranch_override> <args>
  58. # 0 1 2 3 4 5 6 7 8 9...
  59. # Filter all but <args>, i.e. the first 0-8 arguments
  60. i=0
  61. for arg in ${params[@]:24}; do
  62. args[$i]="${arg}"
  63. let i++
  64. done
  65. for check in ${args[@]}; do
  66. case ${check} in
  67. --no-install)
  68. NO_INSTALL=
  69. ;;
  70. --updateoverride)
  71. UPDATE_OVERRIDE=
  72. ;;
  73. --buildpkg-rm)
  74. BUILDPKG_RM=
  75. ;;
  76. --no-dxvk)
  77. NO_DXVK=
  78. ;;
  79. --no-nvapi)
  80. NO_NVAPI=
  81. ;;
  82. --no-vkd3d)
  83. NO_VKD3D=
  84. ;;
  85. esac
  86. done
  87. ########################################################
  88. # Check presence of Wine. Some version of Wine should
  89. # be found in the system in order to install DXVK/DXVK NVAPI/VKD3D Proton.
  90. known_wines=(
  91. 'wine'
  92. 'wine-stable'
  93. 'wine32'
  94. 'wine64'
  95. 'libwine:amd64'
  96. 'libwine:i386'
  97. 'wine-git'
  98. 'wine-staging-git'
  99. )
  100. # Alternative remote dependency packages for Debian distributions which offer too old packages for Wine addons
  101. #
  102. # Left side: <package name in repositories>,<version_number>
  103. # Right side: package alternative source URL
  104. #
  105. # NOTE: Determine these packages in corresponding debdata files as runtime or buildtime dependencies
  106. #
  107. # As this seems to be a dependency for binutils-mingw packages
  108. if [[ $(dpkg -s "binutils-common" &>/dev/null)$? -ne 0 ]]; then
  109. sudo apt -y install "binutils-common"
  110. fi
  111. binutils_ver=$(dpkg -s "binutils-common" | sed -rn 's/^Version: ([0-9\.]+).*$/\1/p')
  112. remote_package_repositories=(
  113. "https://mirrors.edge.kernel.org/ubuntu/pool/universe/d/directx-headers"
  114. "https://mirrors.edge.kernel.org/ubuntu/pool/main/i/isl"
  115. "https://mirrors.edge.kernel.org/ubuntu/pool/universe/b/binutils-mingw-w64"
  116. "https://mirrors.edge.kernel.org/ubuntu/pool/universe/g/gcc-mingw-w64"
  117. "https://mirrors.edge.kernel.org/ubuntu/pool/universe/m/mingw-w64"
  118. )
  119. remote_packages_pool=(
  120. "directx-headers-dev"
  121. "libisl22"
  122. "gcc-mingw-w64-base"
  123. "mingw-w64-common"
  124. "binutils-mingw-w64-x86-64"
  125. "binutils-mingw-w64-i686"
  126. "mingw-w64-x86-64-dev"
  127. "gcc-mingw-w64-x86-64"
  128. "g++-mingw-w64-x86-64"
  129. "mingw-w64-i686-dev"
  130. "gcc-mingw-w64-i686"
  131. "g++-mingw-w64-i686"
  132. )
  133. # NOTE: Package versions defined here *must* exist in some of the repositories!
  134. typeset -A remote_packages_version_locks
  135. remote_packages_version_locks=(
  136. [directx-headers-dev]="1.606.4"
  137. )
  138. pkg_multi_data_binutils=()
  139. typeset -A rpp_alternatives
  140. typeset -A remote_packages_selected
  141. typeset -A remote_packages_alt_available
  142. for rpp in "${remote_packages_pool[@]}"; do
  143. version_len=100
  144. new_rpp_url=
  145. new_rpp_token=
  146. version_lock=
  147. version_lock_set=0
  148. rpp_alternative_time=-1
  149. alt_remote_epoch_time=-1
  150. alt_remote_flat_version=-1
  151. rpp_alternatives=()
  152. remote_packages_alt_available=()
  153. for package_version_lock in ${!remote_packages_version_locks[@]}; do
  154. if [[ ${rpp} == ${package_version_lock} ]]; then
  155. version_lock=${remote_packages_version_locks[${package_version_lock}]}
  156. version_lock_set=1
  157. break 1
  158. fi
  159. done
  160. for source_url in "${remote_package_repositories[@]}"; do
  161. # Fetch exact package name and associated date.
  162. # rpp_rx is just for regex escaping purposes.
  163. rpp_rx=$(echo ${rpp} | sed 's/\+/\\\+/g')
  164. pkg_multi_data=(
  165. $(curl -s "${source_url}/" | \
  166. sed -rn 's/.*href="(.*(amd64|all)\.deb)">.*([0-9]{2}\-[A-Za-z]{3}\-[0-9]{4}).*/\1|\3/p' | \
  167. sed 's/%2B/+/g' | grep -E "${rpp_rx}_[0-9]" | xargs echo
  168. )
  169. )
  170. [[ ${#pkg_multi_data[@]} -eq 0 ]] && continue
  171. # binutils packages depend on system binutils-common.
  172. # Versions must match, even if the newest package is not available.
  173. if [[ ${rpp} =~ binutils ]] && [[ ${binutils_ver} != "" ]]; then
  174. for b in "${pkg_multi_data[@]}"; do
  175. if [[ ${b} =~ ${binutils_ver} ]]; then
  176. pkg_multi_data_binutils+=("${b}")
  177. fi
  178. done
  179. pkg_multi_data=( ${pkg_multi_data_binutils[@]} )
  180. unset pkg_multi_data_binutils
  181. fi
  182. # TODO: Remove duplicate functionality
  183. # Check relevant version parts while collecting
  184. # different versions of a package.
  185. # version_len is count of relevant parts.
  186. #
  187. # For instance
  188. # - In a case of versions 2.23.1, 2.28 and 2.34.6.1
  189. # count of relevant parts is 2 as determined by
  190. # version 2.28.
  191. # In this fair comparison, we therefore consider
  192. # normalized version 2.23, 2.28 and 2.34
  193. #
  194. for pkg_data in "${pkg_multi_data[@]}"; do
  195. rpp_pkg=$(printf '%s' "${pkg_data}" | awk -F '|' '{print $1}')
  196. rpp_version_raw=$(printf '%s' $(echo "${rpp_pkg}" | sed -r 's/.*_(.*[0-9]+)\-.*_(all|amd64).*/\1/g;'))
  197. version_parts=( $(echo ${rpp_version_raw} | sed 's/\./ /g') )
  198. new_version_len=$(printf '%d' ${#version_parts[@]})
  199. if [[ ${new_version_len} -lt ${version_len} ]]; then
  200. version_len=${new_version_len}
  201. fi
  202. done
  203. # Add each version of a package into associated array remote_packages_alt_available
  204. # We collect the next information here for each entry:
  205. # - package normalized version number
  206. # - package release date in epoch format
  207. # - package source root url and .deb name
  208. #
  209. # This information is collected so that we can determine which
  210. # package version to use, and which URL is associated to it.
  211. #
  212. for pkg_data in "${pkg_multi_data[@]}"; do
  213. rpp_pkg=$(printf '%s' "${pkg_data}" | awk -F '|' '{print $1}')
  214. rpp_epoch_time=$(date --date=$(printf '%s' "${ps}" | awk -F '|' '{print $2}') +%s)
  215. rpp_version_raw=$(printf '%s' $(echo "${rpp_pkg}" | sed -r 's/.*_(.*[0-9]+)\-.*_(all|amd64).*/\1/g;'))
  216. version_parts=( $(echo ${rpp_version_raw} | sed 's/\./ /g') )
  217. relevant_version_parts=( ${version_parts[@]:0:${version_len}} )
  218. rpp_flat_version=$(printf '%d' $(echo ${relevant_version_parts[@]} | sed 's/ //g'))
  219. rpp_dot_version=$(echo ${relevant_version_parts[@]} | sed 's/ /./g')
  220. rpp_token=$(printf '%s,%d,%d,%s' "${rpp}" "${rpp_epoch_time}" "${rpp_flat_version}" "${rpp_dot_version}")
  221. rpp_url=$(printf '%s/%s' "${source_url}" "${rpp_pkg}")
  222. remote_packages_alt_available+=(["${rpp_token}"]="${rpp_url}")
  223. done
  224. done
  225. # For collected package versions, get the highest available
  226. #
  227. for alt_remote_package in "${!remote_packages_alt_available[@]}"; do
  228. new_alt_remote_epoch_time=$(echo ${alt_remote_package} | awk -F ',' '{print $2}')
  229. new_alt_remote_flat_version=$(echo ${alt_remote_package} | awk -F ',' '{print $3}')
  230. new_alt_remote_dot_version=$(echo ${alt_remote_package} | awk -F ',' '{print $4}')
  231. # TODO: Remove duplicate functionality
  232. if [[ ${version_lock} =~ ${new_alt_remote_dot_version} ]]; then
  233. alt_remote_epoch_time=${new_alt_remote_epoch_time}
  234. alt_remote_flat_version=${new_alt_remote_flat_version}
  235. alt_remote_dot_version=${new_alt_remote_dot_version}
  236. new_rpp_token=${alt_remote_package}
  237. new_rpp_url=${remote_packages_alt_available[${alt_remote_package}]}
  238. rpp_alternatives+=(["${new_rpp_token}"]="${new_rpp_url}|${alt_remote_epoch_time}|${alt_remote_flat_version}")
  239. fi
  240. if [[ ${new_alt_remote_flat_version} -ge ${alt_remote_flat_version} ]] && [[ ${version_lock_set} -eq 0 ]]; then
  241. alt_remote_epoch_time=${new_alt_remote_epoch_time}
  242. alt_remote_flat_version=${new_alt_remote_flat_version}
  243. alt_remote_dot_version=${new_alt_remote_dot_version}
  244. new_rpp_token=${alt_remote_package}
  245. new_rpp_url=${remote_packages_alt_available[${alt_remote_package}]}
  246. rpp_alternatives+=(["${new_rpp_token}"]="${new_rpp_url}|${alt_remote_epoch_time}|${alt_remote_flat_version}")
  247. fi
  248. done
  249. # Do epoch time comparison for collected package versions
  250. #
  251. for rpp_alternative in ${!rpp_alternatives[@]}; do
  252. new_rpp_alternative=${rpp_alternative}
  253. new_rpp_alternative_time=$(printf '%d' $(echo ${rpp_alternative} | awk -F '|' '{print $2}') )
  254. if [[ ${new_rpp_alternative_time} -gt ${rpp_alternative_time} ]]; then
  255. rpp_alternative_time=${new_rpp_alternative_time}
  256. fi
  257. rpp_alternative=${new_rpp_alternative}
  258. done
  259. remote_packages_selected+=( ["${rpp}"]=$(echo "${rpp_alternatives[$rpp_alternative]}|${version_lock_set}") )
  260. done
  261. # Posix-compliant MingW alternative executables
  262. #
  263. typeset -A alternatives
  264. alternatives=(
  265. [x86_64-w64-mingw32-gcc]="x86_64-w64-mingw32-gcc-posix"
  266. [x86_64-w64-mingw32-g++]="x86_64-w64-mingw32-g++-posix"
  267. [i686-w64-mingw32-gcc]="i686-w64-mingw32-gcc-posix"
  268. [i686-w64-mingw32-g++]="i686-w64-mingw32-g++-posix"
  269. )
  270. # Temporary symbolic links for DXVK compilation
  271. #
  272. typeset -A tempLinks
  273. tempLinks=(
  274. ['/usr/bin/i686-w64-mingw32-gcc']='/usr/bin/i686-w64-mingw32-gcc-posix'
  275. ['/usr/bin/i686-w64-mingw32-g++']='/usr/bin/i686-w64-mingw32-g++-posix'
  276. ['/usr/bin/x86_64-w64-mingw32-gcc']='x86_64-w64-mingw32-gcc-posix'
  277. ['/usr/bin/x86_64-w64-mingw32-g++']='x86_64-w64-mingw32-g++-posix'
  278. )
  279. ########################################################
  280. function runtime_check() {
  281. local pkgreq_name
  282. local known_pkgs
  283. local pkglist
  284. # Friendly name for this package
  285. pkgreq_name=${1}
  286. # Known package names to check on Debian
  287. known_pkgs=${2}
  288. # Check if any of these Wine packages are present on the system
  289. i=0
  290. for pkg in ${known_pkgs[@]}; do
  291. if [[ $(echo $(dpkg -s ${pkg} &>/dev/null)$?) -eq 0 ]]; then
  292. pkglist[$i]=${pkg}
  293. let i++
  294. fi
  295. done
  296. if [[ -z ${pkglist[*]} ]]; then
  297. echo -e "\e[1mWARNING:\e[0m Not compiling Wine addons because \e[1m${pkgreq_name}\e[0m is missing on your system.\n\
  298. ${pkgreq_name} should be installed in order to use DXVK, DXVK NVAPI and VKD3D Proton.\n"
  299. exit 1
  300. fi
  301. }
  302. ########################################################
  303. # If the script is interrupted (Ctrl+C/SIGINT), do the following
  304. function wine_addons_int_cleanup() {
  305. rm -rf ${WINE_ADDONS_ROOT}/{dxvk-git,meson,glslang,*.deb}
  306. rm -rf ${WINE_ADDONS_ROOT}/../compiled_deb/"${datedir}"
  307. exit 0
  308. }
  309. # Allow interruption of the script at any time (Ctrl + C)
  310. trap "wine_addons_int_cleanup" INT
  311. ########################################################
  312. # http://wiki.bash-hackers.org/snipplets/print_horizontal_line#a_line_across_the_entire_width_of_the_terminal
  313. function INFO_SEP() { printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - ; }
  314. ########################################################
  315. # Update all packages if UPDATE_OVERRIDE given
  316. if [[ -v UPDATE_OVERRIDE ]]; then
  317. echo -en "Updating all packages" && \
  318. if [[ $(printf $(sudo -n uptime &>/dev/null)$?) -ne 0 ]]; then printf " Please provide your sudo password.\n"; else printf "\n\n"; fi
  319. sudo apt update && sudo apt upgrade -y
  320. fi
  321. ########################################################
  322. # Check do we need to compile the package
  323. # given as input for this function
  324. function pkg_compile_check() {
  325. local install_function
  326. local pkg
  327. local pkg_data
  328. install_function=${1}
  329. pkg=${2}
  330. pkg_data=${3}
  331. if [[ $(echo $(dpkg -s ${pkg} &>/dev/null)$?) -ne 0 ]] || [[ -v UPDATE_OVERRIDE ]]; then
  332. ${install_function} ${pkg_data}
  333. fi
  334. }
  335. ########################################################
  336. # ADDON CUSTOM INSTALLATION HOOKS
  337. # These are custom installation instructions for addon
  338. # They are not used independently.
  339. function addon_install_custom() {
  340. local PATCHDIR
  341. PATCHDIR="${1}"
  342. # Use posix alternates for MinGW binaries
  343. function addon_posixpkgs() {
  344. for alt in ${!alternatives[@]}; do
  345. echo "Linking MingW executable ${alt} to ${alternatives[$alt]}"
  346. sudo rm -rf /etc/alternatives/"${alt}" 2>/dev/null
  347. sudo ln -sf /usr/bin/"${alternatives[$alt]}" /etc/alternatives/"${alt}"
  348. if [[ $? -ne 0 ]]; then
  349. echo -e "\e[1mERROR:\e[0m Error occured while linking executable ${alt} to ${alternatives[$alt]}. Aborting\n"
  350. exit 1
  351. fi
  352. done
  353. for link in ${!tempLinks[@]}; do
  354. if [[ ! -f ${link} ]]; then
  355. echo "Creating temporary links for MingW executable ${link}"
  356. sudo ln -sf ${tempLinks["${link}"]} "${link}"
  357. if [[ $? -ne 0 ]]; then
  358. echo -e "\e[1mERROR:\e[0m Error occured while linking executable ${link}. Aborting\n"
  359. exit 1
  360. fi
  361. fi
  362. done
  363. }
  364. ############################
  365. # ADDON - CUSTOM PATCHES
  366. # Add and apply custom addon patches
  367. function addon_custom_patches() {
  368. local CURDIR
  369. local dxvk_builddir_name
  370. local dxvk_builddir_path
  371. # Get our current directory, since we will change it during patching process below
  372. # We want to go back here after having applied the patches
  373. CURDIR="${PWD}"
  374. # Check if the following folder exists, and proceed.
  375. if [[ -d "${WINE_ADDONS_ROOT}/../../${PATCHDIR}" ]]; then
  376. cp -r "${WINE_ADDONS_ROOT}/../../${PATCHDIR}/"*.{patch,diff} "${WINE_ADDONS_ROOT}/${pkg_name}/" 2>/dev/null
  377. dxvk_builddir_name=$(ls -l "${WINE_ADDONS_ROOT}/${pkg_name}" | grep ^d | awk '{print $NF}')
  378. # TODO Expecting just one folder here. This method doesn't work with multiple dirs present
  379. if [[ $(echo ${dxvk_builddir_name} | wc -l) -gt 1 ]]; then
  380. echo -e "\e[1mERROR:\e[0m Multiple entries in addon build directory detected. Can't decide which one to use. Aborting\n"
  381. exit 1
  382. fi
  383. dxvk_builddir_path="${WINE_ADDONS_ROOT}/${pkg_name}/${dxvk_builddir_name}"
  384. cd "${dxvk_builddir_path}"
  385. for pfile in ../*.{patch,diff}; do
  386. if [[ -f ${pfile} ]]; then
  387. echo -e "Applying addon's patch: ${pfile}\n"
  388. patch -Np1 < ${pfile}
  389. fi
  390. if [[ $? -ne 0 ]]; then
  391. echo -e "\e[1mERROR:\e[0m Error occured while applying addon's patch '${pfile}'. Aborting\n"
  392. cd ${CURDIR}
  393. exit 1
  394. fi
  395. done
  396. cd "${CURDIR}"
  397. fi
  398. }
  399. ############################
  400. # ADDON - CUSTOM HOOKS EXECUTION
  401. addon_custom_patches && \
  402. addon_posixpkgs
  403. }
  404. ###########################################################
  405. # Fetch extra package files
  406. function fetch_extra_pkg_files() {
  407. local pkgname
  408. local pkgdir
  409. local extra_files_dir
  410. pkgname=${1}
  411. pkgdir=${2}
  412. extra_files_dir=${3}
  413. find ${extra_files_dir} -mindepth 1 -type f -exec cp -f {} ${pkgdir}/ \;
  414. }
  415. ########################################################
  416. # COMMON - COMPILE AND INSTALL DEB PACKAGE
  417. # Instructions to compile and install a deb package
  418. # on Debian system
  419. # Global variable to track buildtime dependencies
  420. z=0
  421. function compile_and_install_deb() {
  422. ############################
  423. # Set local variables
  424. local _pkg_name="${1}"
  425. local _pkg_license="${2}"
  426. local _pkg_giturl="${3}"
  427. local _pkg_gitbranch="${4}"
  428. local _git_commithash="${5}"
  429. local _pkg_gitver="${6}"
  430. local _pkg_debinstall="${7}"
  431. local _pkg_debcontrol="${8}"
  432. local _pkg_debrules="${9}"
  433. local _pkg_installfile="${10}"
  434. local _pkg_controlfile="${11}"
  435. local _pkg_rulesfile="${12}"
  436. local _pkg_deps_build="${13}"
  437. local _pkg_deps_runtime="${14}"
  438. local _pkg_debbuilder="${15}"
  439. local _pkg_debcompat="${16}"
  440. local _pkg_compatfile="${17}"
  441. local extra_files_dir=$(find "../../extra_files/" -type d -iname "${_pkg_name%-git}")
  442. if [[ -d ${extra_files_dir} ]]; then
  443. [[ ! -d "debian/source" ]] && mkdir -p "debian/source"
  444. fetch_extra_pkg_files ${_pkg_name} "debian/source" ${extra_files_dir}
  445. fi
  446. ############################
  447. # COMMON - ARRAY PARAMETER FIX
  448. # Separate array indexes correctly
  449. # We have streamed all array indexes, separated
  450. # by | symbol. We reconstruct the arrays here.
  451. function arrayparser_reverse() {
  452. local arrays
  453. local s
  454. local IFS
  455. local y
  456. arrays=(
  457. '_pkg_deps_build'
  458. '_pkg_deps_runtime'
  459. )
  460. for w in ${arrays[@]}; do
  461. s=\${${w}}
  462. IFS='|'
  463. y=0
  464. for t in $(eval printf '%s\|' ${s}); do
  465. eval ${w}[$y]=\"${t}\"
  466. let y++
  467. done
  468. unset IFS
  469. done
  470. }
  471. arrayparser_reverse
  472. ############################
  473. function pkg_installcheck() {
  474. local full_pkg_name_found
  475. full_pkg_name_found_return_code=$(echo $(dpkg -s "${1}" &>/dev/null)$?)
  476. # Bad and error-prone fallback
  477. if [[ ${full_pkg_name_found_return_code} -ne 0 ]]; then
  478. full_pkg_name_matches=$(dpkg --get-selections | awk '{print $1}' | grep ^${1} | wc -l)
  479. if [[ ${full_pkg_name_matches} -ne 0 ]]; then
  480. full_pkg_name_found_return_code=0
  481. fi
  482. fi
  483. return ${full_pkg_name_found_return_code}
  484. }
  485. ############################
  486. echo -e "Starting compilation$(if [[ ! -v NO_INSTALL ]] || [[ ${_pkg_name} =~ ^meson|glslang$ ]]; then printf " & installation"; fi) of ${_pkg_name}\n"
  487. ############################
  488. function get_locked_packages() {
  489. local _lock_pkgs
  490. # Generate a list of version-locked-dependencies
  491. if [[ ${#remote_packages_selected[@]} -gt 0 ]]; then
  492. for alt_remote_pkg in ${!remote_packages_selected[@]}; do
  493. alt_remote_version_lock_set=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $4}')
  494. if [[ ${alt_remote_version_lock_set} -eq 1 ]]; then
  495. _lock_pkgs+=(${alt_remote_pkg})
  496. fi
  497. done
  498. fi
  499. echo "${_lock_pkgs[*]}"
  500. }
  501. ############################
  502. # COMMON - PACKAGE DEPENDENCIES CHECK
  503. # Check and install package related dependencies if they are missing
  504. function pkg_dependencies() {
  505. local _pkg_list
  506. local _pkg_type
  507. local _pkg_type_str
  508. local a
  509. local b
  510. local _validlist
  511. local _lock_pkgs
  512. local is_locked
  513. local IFS
  514. _pkg_list=("${1}")
  515. _pkg_type="${2}"
  516. _lock_pkgs=($(get_locked_packages))
  517. IFS=$'\n'
  518. _pkg_list=$(echo "${_pkg_list}" | sed 's/([^)]*)//g')
  519. unset IFS
  520. case ${_pkg_type} in
  521. buildtime)
  522. _pkg_type_str="build time"
  523. ;;
  524. runtime)
  525. _pkg_type_str="runtime"
  526. ;;
  527. esac
  528. if [[ ${_pkg_list[0]} == "empty" ]]; then
  529. return 0
  530. fi
  531. a=0
  532. # Generate a list of missing dependencies
  533. for p in ${_pkg_list[@]}; do
  534. is_locked=0
  535. for lock_pkg in "${_lock_pkgs[@]}"; do
  536. if [[ ${p%% *} == ${lock_pkg} ]]; then
  537. is_locked=1
  538. break 1
  539. fi
  540. done
  541. if [[ $(pkg_installcheck ${p%% *})$? -ne 0 ]] || [[ ${is_locked} -eq 1 ]]; then
  542. _validlist[$a]=${p%% *}
  543. let a++
  544. # Global array to track installed build dependencies
  545. if [[ ${_pkg_type} == "buildtime" ]]; then
  546. _buildpkglist[$z]=${p%% *}
  547. let z++
  548. fi
  549. fi
  550. done
  551. function pkg_remoteinstall() {
  552. sudo apt install -y ${1} &> /dev/null
  553. }
  554. function pkg_localinstall() {
  555. wget ${1} -O ${WINE_ADDONS_ROOT}/"${2}".deb
  556. sudo dpkg -i --force-all ${WINE_ADDONS_ROOT}/"${2}".deb
  557. }
  558. function pkg_configure() {
  559. if [[ $(sudo dpkg-reconfigure ${1} | grep "is broken or not fully installed") ]]; then
  560. if [[ -v ${2} ]]; then
  561. pkg_localinstall ${2} ${1}
  562. else
  563. pkg_remoteinstall ${1}
  564. fi
  565. fi
  566. }
  567. # Install missing dependencies, be informative
  568. b=0
  569. for _pkg_dep in ${_validlist[@]}; do
  570. echo -e "$(( $b + 1 ))/$(( ${#_validlist[*]} )) - Installing ${_pkg_name} ${_pkg_type_str} dependency ${_pkg_dep}"
  571. if [[ ${#remote_packages_selected[@]} -gt 0 ]]; then
  572. for alt_remote_pkg in ${!remote_packages_selected[@]}; do
  573. if [[ "${_pkg_dep}" == "${alt_remote_pkg}" ]]; then
  574. alt_remote_url=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $1}')
  575. alt_remote_version=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $3}')
  576. alt_remote_version_lock_set=$(echo ${remote_packages_selected[${alt_remote_pkg}]} | awk -F '|' '{print $4}')
  577. # If remote pkg is not installed
  578. if [[ $(pkg_installcheck ${alt_remote_pkg})$? -ne 0 ]]; then
  579. # TODO remove duplicate functionality
  580. repository_version=$(apt-cache show "${alt_remote_pkg}" 2>/dev/null | grep -m1 -oP "(?<=^Version: )[0-9|\.]*" | sed 's/\.//g')
  581. [[ ! -z ${repository_version} ]] && repository_version=0
  582. if [[ ${repository_version} -eq ${alt_remote_version} ]]; then
  583. echo -e "Already updated. Skipping"
  584. continue 1
  585. fi
  586. if [[ ${repository_version} -lt ${alt_remote_version} ]] || [[ ${alt_remote_version_lock_set} -eq 1 ]]; then
  587. pkg_localinstall "${alt_remote_url}" "${alt_remote_pkg}"
  588. pkg_configure "${alt_remote_pkg}" "${alt_remote_url}"
  589. else
  590. pkg_remoteinstall "${alt_remote_pkg}"
  591. pkg_configure "${alt_remote_pkg}"
  592. fi
  593. # If remote pkg is installed
  594. else
  595. local_version=$(dpkg -s "${alt_remote_pkg}" | grep -m1 -oP "(?<=^Version: )[0-9|\.]*" | sed 's/\.//g')
  596. [[ ! -z ${local_version} ]] && local_version=0
  597. if [[ ${local_version} -eq ${alt_remote_version} ]]; then
  598. echo -e "Already updated. Skipping"
  599. continue 1
  600. fi
  601. if [[ ${local_version} -lt ${alt_remote_version} ]] || [[ ${alt_remote_version_lock_set} -eq 1 ]]; then
  602. pkg_localinstall "${alt_remote_url}" "${alt_remote_pkg}"
  603. pkg_configure "${alt_remote_pkg}" "${alt_remote_url}"
  604. else
  605. pkg_remoteinstall "${alt_remote_pkg}"
  606. pkg_configure "${alt_remote_pkg}"
  607. fi
  608. fi
  609. fi
  610. done
  611. fi
  612. if [[ $(pkg_installcheck ${_pkg_dep})$? -ne 0 ]]; then
  613. pkg_remoteinstall "${_pkg_dep}"
  614. pkg_configure "${_pkg_dep}"
  615. fi
  616. if [[ $? -eq 0 ]]; then
  617. let b++
  618. else
  619. echo -e "\n\e[1mERROR:\e[0m Error occured while installing ${_pkg_dep}. Aborting.\n"
  620. exit 1
  621. fi
  622. done
  623. if [[ -n ${_validlist[*]} ]]; then
  624. # Add empty newline
  625. echo ""
  626. fi
  627. }
  628. ############################
  629. # COMMON - RETRIEVE PACKAGE
  630. # GIT VERSION TAG
  631. # Get git-based version in order to rename the package main folder
  632. # This is required by deb builder. It retrieves the version number
  633. # from that folder name
  634. function pkg_gitversion() {
  635. if [[ -n "${_pkg_gitver}" ]] && [[ "${_pkg_gitver}" =~ ^git ]]; then
  636. cd ${_pkg_name}
  637. git checkout ${_pkg_gitbranch}
  638. git reset --hard ${_git_commithash}
  639. if [[ $? -ne 0 ]]; then
  640. echo -e "\e[1mERROR:\e[0m Couldn't find commit ${_git_commithash} for ${_pkg_name}. Aborting\n"
  641. exit 1
  642. fi
  643. _pkg_gitver=$(eval "${_pkg_gitver}")
  644. cd ..
  645. fi
  646. }
  647. ############################
  648. # COMMON - OVERWRITE
  649. # DEBIAN BUILD ENV FILES
  650. # Overwrite a file which is given as user input
  651. # The contents are supplied as input, too.
  652. function pkg_override_debianfile() {
  653. local contents
  654. local targetfile
  655. contents=${1}
  656. targetfile=${2}
  657. if [[ ${contents} != "empty" ]]; then
  658. echo "${contents}" > "${targetfile}"
  659. if [[ $? -ne 0 ]]; then
  660. echo -e "\e[1mERROR:\e[0m Couldn't create Debian file '${targetfile}' for ${_pkg_name}. Aborting\n"
  661. exit 1
  662. fi
  663. fi
  664. }
  665. ############################
  666. # COMMON - GET SOURCE AND
  667. # PREPARE SOURCE FOLDER
  668. function pkg_folderprepare() {
  669. # Remove old build directory, if present
  670. rm -rf ${_pkg_name}
  671. # Create a new build directory, access it and download git sources there
  672. mkdir ${_pkg_name}
  673. cd ${_pkg_name}
  674. echo -e "Retrieving source code of ${_pkg_name} from $(printf ${_pkg_giturl} | sed 's/^.*\/\///; s/\/.*//')\n"
  675. git clone ${_pkg_giturl} ${_pkg_name}
  676. # If sources could be downloaded, rename the folder properly for deb builder
  677. # Access the folder after which package specific debianbuild function will be run
  678. # That function is defined inside package specific install_main function below
  679. if [[ $? -eq 0 ]]; then
  680. pkg_gitversion && \
  681. mv ${_pkg_name} ${_pkg_name}-${_pkg_gitver}
  682. cd ${_pkg_name}-${_pkg_gitver}
  683. # Get all required submodules
  684. git submodule update --init --recursive
  685. dh_make --createorig -s -y -c ${_pkg_license} && \
  686. pkg_override_debianfile "${_pkg_debinstall}" "${_pkg_installfile}"
  687. pkg_override_debianfile "${_pkg_debcontrol}" "${_pkg_controlfile}"
  688. pkg_override_debianfile "${_pkg_debrules}" "${_pkg_rulesfile}"
  689. pkg_override_debianfile "${_pkg_debcompat}" "${_pkg_compatfile}"
  690. else
  691. echo -e "\e[1mERROR:\e[0m Error while downloading source of ${_pkg_name} package. Aborting\n"
  692. exit 1
  693. fi
  694. }
  695. ############################
  696. # COMMON - COMPILE, INSTALL
  697. # AND STORE DEB PACKAGE
  698. function pkg_debianbuild() {
  699. # Start deb builder
  700. bash -c "${_pkg_debbuilder}"
  701. # Once our deb package is compiled, install and store it
  702. # We do not make installation optional for deps because they may be required by the addon
  703. if [[ $? -eq 0 ]]; then
  704. rm -rf ../*.{changes,buildinfo,tar.xz}
  705. if [[ ! -v NO_INSTALL ]]; then
  706. sudo dpkg -i ../${_pkg_name}*.deb
  707. fi
  708. mv ../${_pkg_name}*.deb ../../../compiled_deb/"${datedir}" && \
  709. echo -e "Compiled ${_pkg_name} is stored at '$(readlink -f ../../../compiled_deb/"${datedir}")/'\n"
  710. cd ../..
  711. rm -rf {${_pkg_name},*.deb}
  712. else
  713. buildpkg_removal
  714. exit 1
  715. fi
  716. }
  717. ############################
  718. # COMMON - EXECUTION HOOKS
  719. pkg_dependencies "${_pkg_deps_build[*]}" buildtime
  720. if [[ ${_pkg_deps_runtime[0]} != "empty" ]] && [[ ! -v NO_INSTALL ]]; then
  721. pkg_dependencies "${_pkg_deps_runtime[*]}" runtime
  722. fi
  723. pkg_folderprepare
  724. # TODO use package name or separate override switch here?
  725. if [[ "${_pkg_name%-git}" == "dxvk" ]]; then
  726. addon_install_custom "dxvk_custom_patches"
  727. elif [[ "${_pkg_name%-git}" == "dxvk-nvapi" ]]; then
  728. addon_install_custom "dxvk-nvapi_custom_patches"
  729. elif [[ "${_pkg_name%-git}" == "vkd3d-proton" ]]; then
  730. addon_install_custom "vkd3d-proton_custom_patches"
  731. fi
  732. pkg_debianbuild
  733. unset _pkg_gitver
  734. }
  735. ########################################################
  736. # BUILD DEPENDENCIES REMOVAL
  737. function buildpkg_removal() {
  738. _buildpkglist=($(echo ${_buildpkglist[@]} | tr ' ' '\n' |sort -u | tr '\n' ' '))
  739. for link in ${!tempLinks[@]}; do
  740. if [[ $(file ${link}) == *"symbolic link"* ]]; then
  741. sudo rm -f "${link}"
  742. fi
  743. done
  744. # Build time dependencies which were installed but no longer needed
  745. if [[ -v _buildpkglist ]]; then
  746. if [[ -v BUILDPKG_RM ]]; then
  747. sudo apt purge --remove -y ${_buildpkglist[*]}
  748. # In some cases, glslang or meson may still be present on the system. Remove them
  749. for _extrapkg in glslang meson; do
  750. if [[ $(echo $(dpkg -s ${_extrapkg} &>/dev/null)$?) -eq 0 ]]; then
  751. sudo dpkg --remove --force-remove-reinstreq ${_extrapkg}
  752. fi
  753. done
  754. # Manually obtained deb packages are expected to break system configuration, thus we need to fix it.
  755. sudo apt --fix-broken -y install
  756. else
  757. echo -e "The following build time dependencies were installed and no longer needed:\n\n$(for l in ${_buildpkglist[*]}; do echo -e ${l}; done)\n"
  758. fi
  759. fi
  760. }
  761. ########################################################
  762. # Package installation instructions
  763. function pkg_install_main() {
  764. local pkg_datafile
  765. # Read necessary variables from debdata file
  766. pkg_datafile=${1}
  767. if [[ -f ${pkg_datafile} ]]; then
  768. source ${pkg_datafile}
  769. else
  770. echo -e "\e[1mERROR:\e[0m Couldn't read datafile '${pkg_datafile}'. Check the file path and try again.\n"
  771. exit 1
  772. fi
  773. ############################
  774. # Prepare these arrays for 'compile_and_install_deb' input
  775. # Separate each array index with | in these arrays
  776. function pkg_arrayparser() {
  777. local pkg_arrays
  778. local IFS
  779. local s
  780. local t
  781. pkg_arrays=(
  782. 'pkg_deps_build'
  783. 'pkg_deps_runtime'
  784. )
  785. local IFS=$'\n'
  786. for w in ${pkg_arrays[@]}; do
  787. s=\${${w}[@]}
  788. t=$(eval printf '%s\|' ${s})
  789. unset ${w}
  790. eval ${w}=\"${t}\"
  791. done
  792. }
  793. ############################
  794. # Execute package installation procedure
  795. pkg_arrayparser && \
  796. compile_and_install_deb \
  797. "${pkg_name}" \
  798. "${pkg_license}" \
  799. "${pkg_giturl}" \
  800. "${pkg_gitbranch}" \
  801. "${git_commithash}" \
  802. "${pkg_gitver}" \
  803. "${pkg_debinstall}" \
  804. "${pkg_debcontrol}" \
  805. "${pkg_debrules}" \
  806. "${pkg_installfile}" \
  807. "${pkg_controlfile}" \
  808. "${pkg_rulesfile}" \
  809. "${pkg_deps_build}" \
  810. "${pkg_deps_runtime}" \
  811. "${pkg_debbuilder}" \
  812. "${pkg_debcompat}" \
  813. "${pkg_compatfile}"
  814. }
  815. ########################################################
  816. # Check existence of known Wine packages
  817. runtime_check Wine "${known_wines[*]}"
  818. # Meson - compile (& install)
  819. pkg_compile_check pkg_install_main meson "${WINE_ADDONS_ROOT}/../debdata/meson.debdata"
  820. # Glslang - compile (& install)
  821. pkg_compile_check pkg_install_main glslang "${WINE_ADDONS_ROOT}/../debdata/glslang.debdata"
  822. if [[ ! -v NO_DXVK ]]; then
  823. # DXVK - compile (& install)
  824. pkg_install_main "${WINE_ADDONS_ROOT}/../debdata/dxvk.debdata"
  825. fi
  826. if [[ ! -v NO_NVAPI ]]; then
  827. # DXVK NVAPI - compile (& install)
  828. pkg_install_main "${WINE_ADDONS_ROOT}/../debdata/dxvk_nvapi.debdata"
  829. fi
  830. if [[ ! -v NO_VKD3D ]]; then
  831. # VKD3D Proton - compile (& install)
  832. pkg_install_main "${WINE_ADDONS_ROOT}/../debdata/vkd3d_proton.debdata"
  833. fi
  834. # Clean buildtime dependencies
  835. buildpkg_removal