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.

624 lines
18 KiB

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