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.

549 lines
16 KiB

5 years ago
  1. #!/bin/env bash
  2. # Set up Wine Staging + DXVK on Arch Linux & Variants
  3. # Copyright (C) 2018 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. ARCH_BUILDROOT="${PWD}"
  22. # datedir variable supplied by ../updatewine.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_dxvk=${params[0]}
  39. git_commithash_wine=${params[3]}
  40. ########################################################
  41. # Parse input arguments, filter user parameters
  42. # The range is defined in ../updatewine.sh
  43. # All input arguments are:
  44. # <datedir> 4*<githash_override> <args>
  45. # 0 1 2 3 4 5 ...
  46. # Filter all but <args>, i.e. the first 0-4 arguments
  47. i=0
  48. for arg in ${params[@]:4}; do
  49. args[$i]="${arg}"
  50. let i++
  51. done
  52. for check in ${args[@]}; do
  53. case ${check} in
  54. --no-staging)
  55. NO_STAGING=
  56. ;;
  57. --no-install)
  58. NO_INSTALL=
  59. # Do not check for PlayOnLinux wine prefixes
  60. NO_POL=
  61. ;;
  62. --no-wine)
  63. NO_WINE=
  64. ;;
  65. --no-dxvk)
  66. NO_DXVK=
  67. ;;
  68. --no-pol)
  69. NO_POL=
  70. ;;
  71. esac
  72. done
  73. ########################################################
  74. # http://wiki.bash-hackers.org/snipplets/print_horizontal_line#a_line_across_the_entire_width_of_the_terminal
  75. function INFO_SEP() { printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' - ; }
  76. ###########################################################
  77. # If the script is interrupted (Ctrl+C/SIGINT), do the following
  78. function Arch_intCleanup() {
  79. rm -rf ${ARCH_BUILDROOT}/{0-wine-staging-git/{wine-patches,*.tar.xz},0-dxvk-git/{dxvk-git,*.tar.xz}}
  80. exit 0
  81. }
  82. # Allow interruption of the script at any time (Ctrl + C)
  83. trap "Arch_intCleanup" INT
  84. ###########################################################
  85. # Check existence of ccache package
  86. function ccacheCheck() {
  87. if [[ $(pacman -Q | awk '{print $1}' | grep -wE "ccache" | wc -l) -eq 0 ]]; then
  88. echo -e "NOTE: Please consider using 'ccache' for faster compilation times.\nInstall it by typing 'sudo pacman -S ccache'\n"
  89. fi
  90. }
  91. ###########################################################
  92. # Validate all core build files for Wine and/or DXVK exist
  93. function checkFiles() {
  94. local wine_files=('30-win32-aliases.conf' 'PKGBUILD')
  95. local dxvk_files=('PKGBUILD')
  96. function validatefiles() {
  97. local list=${1}
  98. local name=${2}
  99. local path=${3}
  100. for file in ${list[@]}; do
  101. if [[ ! -f "${path}/${file}" ]]; then
  102. echo -e "Could not locate file ${} for ${name}. Aborting\n"
  103. exit 1
  104. fi
  105. done
  106. }
  107. if [[ ! -v NO_WINE ]]; then
  108. validatefiles "${wine_files[*]}" Wine "${ARCH_BUILDROOT}/0-wine-staging-git"
  109. fi
  110. if [[ ! -v NO_DXVK ]]; then
  111. validatefiles "${dxvk_files[*]}" DXVK "${ARCH_BUILDROOT}/0-dxvk-git"
  112. fi
  113. }
  114. ###########################################################
  115. # Disable or enable Wine Staging, depending on user's
  116. # choice
  117. function checkStaging() {
  118. # Enable Wine Staging
  119. if [[ ! -v NO_STAGING ]]; then
  120. sed -i 's/enable_staging=[0-9]/enable_staging=1/' "${ARCH_BUILDROOT}/0-wine-staging-git/PKGBUILD"
  121. wine_name="wine-staging-git"
  122. # Enable Wine, disable Staging
  123. else
  124. sed -i 's/enable_staging=[0-9]/enable_staging=0/' "${ARCH_BUILDROOT}/0-wine-staging-git/PKGBUILD"
  125. wine_name="wine"
  126. fi
  127. }
  128. ###########################################################
  129. # Check package dependencies beforehand, just to avoid
  130. # annoying situations which could occur later while the script
  131. # is already running.
  132. # Just for "packages which are not found" array <=> ERRPKGS
  133. # We need to set it outside of checkDepends function
  134. # because it is a global variable for all checked packages
  135. l=0
  136. function checkDepends() {
  137. # The first and the second argument
  138. local packagedir=${1}
  139. local package=${2}
  140. # We get necessary variables to check from this file
  141. local file="./${packagedir}/PKGBUILD"
  142. # All but the (zero), the first and the second argument
  143. # We check the value of these file variables
  144. local file_vars=${@:3}
  145. for var in ${file_vars[*]}; do
  146. # Get the variable and set it as a new variable in the current shell
  147. # This is applicable only to variable arrays! Do not use if the variable is not an array.
  148. local field=$(awk "/^${var}/,/)/" ${file} | sed -r "s/^${var}=|[)|(|']//g")
  149. local i=0
  150. for parse in ${field[*]}; do
  151. if [[ ! $parse =~ ^# ]]; then
  152. local PKGS[$i]=$(printf '%s' $parse | sed 's/[=|>|<].*$//')
  153. let i++
  154. fi
  155. done
  156. # Sort list and delete duplicate index values
  157. local PKGS=($(sort -u <<< "${PKGS[*]}"))
  158. for pkg in ${PKGS[*]}; do
  159. if [[ $(printf $(pacman -Q ${pkg} &>/dev/null)$?) -ne 0 ]]; then
  160. ERRPKGS[$l]=${pkg}
  161. echo -e "\e[91mError:\e[0m Dependency '${pkg}' not found, required by '${package}' (${file} => ${var})"
  162. let l++
  163. fi
  164. done
  165. done
  166. echo -e "\e[92m==>\e[0m\e[1m Dependency check for ${package} done.\e[0m\n"
  167. }
  168. function check_alldeps() {
  169. if [[ -v ERRPKGS ]]; then
  170. echo -e "The following dependencies are missing:\n\e[91m\
  171. $(for o in ${ERRPKGS[@]}; do printf '%s\n' ${o}; done)\
  172. \e[0m\n"
  173. exit 1
  174. fi
  175. }
  176. ###########################################################
  177. # Prepare building environment for the current runtime
  178. function prepare_env() {
  179. # Copy Wine & DXVK patch files
  180. cp -rf ${ARCH_BUILDROOT}/../wine_custom_patches ${ARCH_BUILDROOT}/0-wine-staging-git/wine-patches
  181. cp -rf ${ARCH_BUILDROOT}/../dxvk_custom_patches ${ARCH_BUILDROOT}/0-dxvk-git/dxvk-patches
  182. # Create identifiable directory for this build
  183. mkdir -p ${ARCH_BUILDROOT}/compiled_pkg/"${datedir}"
  184. }
  185. ########################################################
  186. # Parse Wine hash override if Staging is set to be installed
  187. function check_gitOverride_wine() {
  188. # If staging is to be installed and Wine git is frozen to a specific commit
  189. # We need to determine exact commit to use for Wine Staging
  190. # to avoid any mismatches
  191. #
  192. # Basically, when user has defined 'git_commithash_wine' variable (commit), we
  193. # iterate through Wine commits and try to determine previously set
  194. # Wine Staging commit. We use that Wine Staging commit instead of
  195. # the one user has defined in 'git_commithash_wine' variable
  196. #
  197. if [[ ! -v NO_STAGING ]] && [[ "${git_commithash_wine}" != HEAD ]]; then
  198. function form_commit_array() {
  199. cd "${commit_dir}"
  200. if [[ $? -ne 0 ]]; then
  201. echo -e "Error: couldn't access Wine folder ${commit_dir} to check commits. Aborting\n"
  202. exit 1
  203. fi
  204. local array_name=${1}
  205. local commits_raw=$(eval ${2})
  206. local i=0
  207. for commit in ${commits_raw[*]}; do
  208. eval ${array_name}[$i]="${commit}"
  209. let i++
  210. done
  211. if [[ $? -ne 0 ]]; then
  212. echo -e "Error: couldn't parse Wine commits in ${commit_dir}. Aborting\n"
  213. exit 1
  214. fi
  215. cd "${ARCH_BUILDROOT}/0-wine-staging-git/"
  216. }
  217. function staging_change_freeze_commit() {
  218. local wine_commits_raw="git log --pretty=oneline | awk '{print \$1}' | tr '\n' ' '"
  219. # TODO this check may break quite easily
  220. # It depends on the exact comment syntax Wine Staging developers are using (Rebase against ...)
  221. # Length and order of these two "array" variables MUST MATCH!
  222. local staging_refcommits_raw="git log --pretty=oneline | awk '{ if ((length(\$NF)==40 || length(\$NF)==41) && \$(NF-1)==\"against\") print \$1; }'"
  223. local staging_rebasecommits_raw="git log --pretty=oneline | awk '{ if ((length(\$NF)==40 || length(\$NF)==41) && \$(NF-1)==\"against\") print substr(\$NF,1,40); }' | tr '\n' ' '"
  224. # Syntax: <function> <array_name> <raw_commit_list>
  225. commit_dir="${ARCH_BUILDROOT}/0-wine-staging-git/wine-git"
  226. form_commit_array wine_commits "${wine_commits_raw}"
  227. commit_dir="${ARCH_BUILDROOT}/0-wine-staging-git/wine-staging-git"
  228. form_commit_array staging_refcommits "${staging_refcommits_raw}"
  229. form_commit_array staging_rebasecommits "${staging_rebasecommits_raw}"
  230. # User has selected vanilla Wine commit to freeze to
  231. # We must get the previous Staging commit from rebase_commits array, and
  232. # change git_commithash_wine value to that
  233. # Get all vanilla Wine commits
  234. # Filter all newer than defined in 'git_commithash_wine'
  235. #
  236. echo -e "Determining valid Wine Staging git commit. This takes a while.\n"
  237. local i=0
  238. for dropcommit in ${wine_commits[@]}; do
  239. if [[ "${dropcommit}" == "${git_commithash_wine}" ]]; then
  240. break
  241. else
  242. local wine_dropcommits[$i]="${dropcommit}"
  243. let i++
  244. fi
  245. done
  246. wine_commits=("${wine_commits[@]:${#wine_dropcommits[*]}}")
  247. # For the filtered array list, iterate through 'staging_rebasecommits' array list until
  248. # we get a match
  249. for vanilla_commit in ${wine_commits[@]}; do
  250. local k=0
  251. for rebase_commit in ${staging_rebasecommits[@]}; do
  252. if [[ "${vanilla_commit}" == "${rebase_commit}" ]]; then
  253. # This is the commit we use for vanilla Wine
  254. git_commithash_wine="${vanilla_commit}"
  255. # This is equal commit we use for Wine Staging
  256. git_commithash_winestaging="${staging_refcommits[$k]}"
  257. break 2
  258. fi
  259. let k++
  260. done
  261. done
  262. }
  263. elif [[ ! -v NO_STAGING ]] && [[ "${git_commithash_wine}" == HEAD ]]; then
  264. git_commithash_winestaging=HEAD
  265. fi
  266. staging_change_freeze_commit
  267. }
  268. ###########################################################
  269. function set_gitOverride() {
  270. local git_name=${1}
  271. local git_commithash=${2}
  272. local pkgbuild_file=${3}
  273. # Match string ${git_name}#commit=<replacethis>
  274. # where replace <replacethis>, but exclude ' " and ) after that
  275. #
  276. # TODO consider when there is nothing/no string after = symbol
  277. sed -i "s!\(${git_name}#commit=\)\(.*[^'|^\"|^\)]\)!\1${git_commithash}!" "${pkgbuild_file}"
  278. }
  279. ###########################################################
  280. # Remove any existing pkg,src or tar.xz packages left by previous pacman commands
  281. function cleanUp() {
  282. rm -rf ${ARCH_BUILDROOT}/*/{pkg,src,*.tar.xz}
  283. rm -rf ${ARCH_BUILDROOT}/0-wine-staging-git/{*.patch}
  284. rm -rf ${ARCH_BUILDROOT}/0-dxvk-git/{*.patch}
  285. }
  286. ###########################################################
  287. # Build & install package
  288. function build_pkg() {
  289. local pkgname=${1}
  290. local pkgname_friendly=${2}
  291. local pkgdir=${3}
  292. local cleanlist=${4}
  293. # Create package and install it to the system
  294. # We need to download git sources beforehand in order
  295. # to determine git commit hashes
  296. cd "${ARCH_BUILDROOT}"/${pkgdir}
  297. bash -c "updpkgsums && makepkg -o"
  298. # Check git commit hashes
  299. if [[ $? -eq 0 ]] && \
  300. [[ ${5} == gitcheck ]]; then
  301. if [[ ${pkgname} == wine ]]; then
  302. check_gitOverride_wine
  303. local pkgbuild_file="${ARCH_BUILDROOT}/${pkgdir}/PKGBUILD"
  304. set_gitOverride "wine.git" "${git_commithash_wine}" ${pkgbuild_file}
  305. sed -i "s/\(^_wine_commit=\).*/\1${git_commithash_wine}/" ${pkgbuild_file}
  306. if [[ ! -v NO_STAGING ]]; then
  307. set_gitOverride "wine-staging.git" "${git_commithash_winestaging}" ${pkgbuild_file}
  308. sed -i "s/\(^_staging_commit=\).*/\1${git_commithash_winestaging}/" ${pkgbuild_file}
  309. fi
  310. elif [[ ${pkgname} == dxvk ]]; then
  311. local pkgbuild_file="${ARCH_BUILDROOT}/${pkgdir}/PKGBUILD"
  312. set_gitOverride "dxvk.git" "${git_commithash_dxvk}" ${pkgbuild_file}
  313. fi
  314. fi
  315. if [[ $? -eq 0 ]]; then bash -c "updpkgsums && makepkg"; else exit 1; fi
  316. # After successful compilation...
  317. if [[ $(ls ./${pkgname}-*tar.xz 2>/dev/null | wc -l) -ne 0 ]]; then
  318. if [[ ! -v NO_INSTALL ]]; then
  319. yes | sudo pacman -U ${pkgname}-*.tar.xz
  320. fi
  321. mv ${pkgname}-*.tar.xz ${ARCH_BUILDROOT}/compiled_pkg/${datedir}/ && \
  322. echo -e "\nCompiled ${pkgname_friendly} is stored at '$(readlink -f ${ARCH_BUILDROOT}/compiled_pkg/${datedir}/)/'\n"
  323. for rml in ${cleanlist[*]}; do
  324. rm -rf "${ARCH_BUILDROOT}/${pkgdir}/${rml}"
  325. done
  326. else
  327. echo -e "Error occured during ${pkgname} compilation.\n"
  328. for rml in ${cleanlist[*]}; do
  329. rm -rf "${ARCH_BUILDROOT}/${pkgdir}/${rml}"
  330. done
  331. exit 1
  332. fi
  333. cd "${ARCH_BUILDROOT}"
  334. }
  335. ##########################################################
  336. # Update user's PlayOnLinux Wine prefixes if present
  337. function updatePOL() {
  338. # Check whether we will update user's PoL wine prefixes
  339. if [[ ! -v NO_POL ]]; then
  340. # Check existence of PoL default folder in user's homedir
  341. if [[ ! -d "$HOME/.PlayOnLinux" ]]; then
  342. echo -e "\e[1mWARNING:\e[0m Couldn't find PoL directories in $USER's homedir.\n"
  343. return 0
  344. fi
  345. fi
  346. if [[ ! -v NO_WINE ]]; then
  347. # If a new Wine Staging version was installed and 'System' version of Wine has been used in
  348. # PoL wineprefix configurations, update those existing PoL wineprefixes
  349. for wineprefix in $(find $HOME/.PlayOnLinux/wineprefix -mindepth 1 -maxdepth 1 -type d); do
  350. if [[ -d ${wineprefix}/dosdevices ]]; then
  351. # If VERSION string exists, skip updating that prefix.
  352. if [[ $(printf $(grep -ril "VERSION" ${wineprefix}/playonlinux.cfg &> /dev/null)$?) -ne 0 ]]; then
  353. WINEPREFIX=${wineprefix} wineboot -u
  354. fi
  355. fi
  356. done
  357. fi
  358. if [[ ! -v NO_DXVK ]]; then
  359. for wineprefix in $(find $HOME/.PlayOnLinux/wineprefix -mindepth 1 -maxdepth 1 -type d); do
  360. if [[ -d ${wineprefix}/dosdevices ]]; then
  361. WINEPREFIX=${wineprefix} setup_dxvk
  362. fi
  363. done
  364. fi
  365. }
  366. ##########################################################
  367. # Clean these temporary folders & files
  368. # TODO Shall we remove git folders or keep them?
  369. dxvk_wine_cleanlist=('*.patch' '*.diff' 'pkg' 'src' '*-patches' '*.tar.xz') # dxvk-git wine-*git
  370. ##########################################################
  371. # Validate all buildtime files
  372. checkFiles
  373. # Check whether we build Wine or Wine Staging
  374. checkStaging
  375. # Check whether we have ccache installed
  376. ccacheCheck
  377. # Prepare building environment: copy patches and create timestamped folder for compiled packages
  378. prepare_env
  379. # Clean all previous trash we may have
  380. cleanUp
  381. #########################
  382. # Check Wine & DXVK dependencies, depending on whether these packages
  383. # are to be built
  384. echo -e "\e[1mINFO:\e[0m Checking dependencies for packages.\n"
  385. if [[ ! -v NO_WINE ]]; then
  386. checkDepends "0-wine-staging-git" "${wine_name}" _depends makedepends
  387. fi
  388. if [[ ! -v NO_DXVK ]]; then
  389. checkDepends "0-dxvk-git" "dxvk-git" depends makedepends
  390. fi
  391. check_alldeps
  392. #########################
  393. # Compile Wine & DXVK, depending on whether these packages
  394. # are to be built
  395. # Although the folder name is '0-wine-staging-git', we can still build vanilla Wine
  396. if [[ ! -v NO_WINE ]]; then
  397. build_pkg wine "${wine_name}" "0-wine-staging-git" "${dxvk_wine_cleanlist[*]}" gitcheck
  398. fi
  399. if [[ ! -v NO_DXVK ]]; then
  400. build_pkg dxvk DXVK "0-dxvk-git" "${dxvk_wine_cleanlist[*]}" gitcheck
  401. fi
  402. #########################
  403. # Update user's PlayonLinux wine prefixes if needed
  404. if [[ ! -v NO_POL ]]; then
  405. echo -e "Updating your PlayOnLinux Wine prefixes.\n"
  406. updatePOL
  407. fi