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.

591 lines
18 KiB

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