nixpkgs/pkgs/by-name/dx/dxvk/setup_dxvk.sh

337 lines
8.3 KiB
Bash

#!@bash@/bin/bash -e
set -eu -o pipefail
# shellcheck disable=SC2034
{
dxvk32_dir=@dxvk32@/bin
dxvk64_dir=@dxvk64@/bin
}
## Defaults
declare -A dlls=(
[d3d8]="dxvk/d3d8.dll"
[d3d9]="dxvk/d3d9.dll"
[d3d10]="dxvk/d3d10.dll dxvk/d3d10_1.dll dxvk/d3d10core.dll"
[d3d11]="dxvk/d3d11.dll"
[dxgi]="dxvk/dxgi.dll"
)
declare -A obsolete_dlls=(
[mcfgthreads]="mcfgthreads/mcfgthread-12.dll"
)
declare -A targets=([d3d8]=1 [d3d9]=1 [d3d11]=1 [dxgi]=1)
# Option variables
do_cleanup=false
ignore_obsolete=false
do_symlink=false
do_makeprefix=false
## Command-line Parsing
usage() {
echo "DXVK @version@"
echo "Set up Wine prefix with DXVK DLLs"
echo
echo "USAGE"
echo " $0 [install|uninstall] [OPTIONS]"
echo
echo "COMMANDS"
echo " install Copy the DXVK DLLs into the prefix"
echo " uninstall Restore the backed up Wine DLLs in the prefix"
echo
echo "OPTIONS"
echo " --with(out)-dxgi Copy DXVK DXGI DLL into prefix (default: with DXGI)"
echo " --with(out)-d3d10 Copy D3D10 DLLs into prefix (default: without D3D10)"
echo " -s, --symlink Symlink instead of copy"
echo " -f, --force Create a Wine prefix even if it does not exist"
echo " -p, --prefix <PREFIX> Wine prefix to manage (default: \$WINEPREFIX)"
exit 1
}
case "${1:-}" in
cleanup)
do_cleanup=true
shift
;;
uninstall|install)
action=$1
shift
;;
-h|--help)
usage
;;
*)
if [ -n "${1:-}" ]; then
echo "Unrecognized command: $1"
fi
usage
;;
esac
while [ -n "${1:-}" ]; do
case "$1" in
--with-dxgi)
targets[dxgi]=1
;;
--without-dxgi)
unset "targets[dxgi]"
;;
--with-d3d10)
targets[d3d10]=1
;;
--without-d3d10)
unset "targets[d3d10]"
;;
-s|--symlink)
do_symlink=true
;;
--no-symlink)
do_symlink=false
;;
-f|--force)
do_makeprefix=true
;;
--no-force)
do_makeprefix=false
;;
-p|--prefix)
shift
if [ -n "${1:-}" ]; then
WINEPREFIX=$1
else
echo "Required PREFIX missing"
usage
fi
;;
--ignore-obsolete)
shift
ignore_obsolete=true
;;
-h|--help)
usage
;;
*)
echo "Unrecognized option: $1"
usage
;;
esac
shift
done
## Get information on the Wine environment
export WINEPREFIX=${WINEPREFIX:-"$HOME/.wine"}
# check wine prefix before invoking wine, so that we
# don't accidentally create one if the user screws up
if ! $do_makeprefix && [ -n "$WINEPREFIX" ] && ! [ -f "$WINEPREFIX/system.reg" ]; then
echo "$WINEPREFIX: Not a valid wine prefix." >&2
exit 1
fi
export WINEDEBUG=-all
# disable mscoree and mshtml to avoid downloading
# wine gecko and mono
export WINEDLLOVERRIDES="mscoree,mshtml="
wine="wine"
wine64="wine64"
wineboot="wineboot"
# $PATH is the way for user to control where wine is located (including custom Wine versions).
# Pure 64-bit Wine (non Wow64) requries skipping 32-bit steps.
# In such case, wine64 and winebooot will be present, but wine binary will be missing,
# however it can be present in other PATHs, so it shouldn't be used, to avoid versions mixing.
wine_path=$(dirname "$(command -v $wineboot)")
wow64=true
if ! [ -f "$wine_path/$wine" ]; then
wine=$wine64
wow64=false
fi
# resolve 32-bit and 64-bit system32 path
winever=$($wine --version | grep wine)
if [ -z "$winever" ]; then
echo "$wine: Not a wine executable. Check your $wine." >&2
exit 1
fi
# ensure wine placeholder dlls are recreated
# if they are missing
$wineboot -u
win64_sys_path=$($wine64 winepath -u 'C:\windows\system32' 2> /dev/null)
win64_sys_path="${win64_sys_path/$'\r'/}"
if $wow64; then
win32_sys_path=$($wine winepath -u 'C:\windows\system32' 2> /dev/null)
win32_sys_path="${win32_sys_path/$'\r'/}"
fi
if [ -z "${win32_sys_path:-}" ] && [ -z "${win64_sys_path:-}" ]; then
echo 'Failed to resolve C:\windows\system32.' >&2
exit 1
fi
## Utility functions
install_file() {
$do_symlink && file_cmd="ln -sv" || file_cmd="install -m 755 -v"
srcfile=$1
dstfile=$2
if [ -f "${srcfile}.so" ]; then
srcfile="${srcfile}.so"
fi
if ! [ -f "${srcfile}" ]; then
echo "${srcfile}: File not found. Skipping." >&2
return 1
fi
if [ -n "$1" ]; then
if [ -f "${dstfile}" ] || [ -h "${dstfile}" ]; then
if ! [ -f "${dstfile}.old" ]; then
mv -v "${dstfile}" "${dstfile}.old"
else
rm -v "${dstfile}"
fi
fi
$file_cmd "${srcfile}" "${dstfile}"
else
echo "${dstfile}: File not found in wine prefix" >&2
return 1
fi
}
uninstall_file() {
srcfile=$1
dstfile=$2
args=$3
if [ "${args}" = "-f" ]; then
rm -v "${dstfile}"
[ -e "${dstfile}.old" ] && rm -v "${dstfile}.old"
return 0
fi
if [ -f "${srcfile}.so" ]; then
srcfile="${srcfile}.so"
fi
if ! [ -f "${srcfile}" ]; then
echo "${srcfile}: File not found. Skipping." >&2
return 1
fi
if ! [ -f "${dstfile}" ] && ! [ -h "${dstfile}" ]; then
echo "${dstfile}: File not found. Skipping." >&2
return 1
fi
if [ -f "${dstfile}.old" ]; then
rm -v "${dstfile}"
mv -v "${dstfile}.old" "${dstfile}"
return 0
else
return 1
fi
}
install_override() {
dll=$(basename "$1")
if ! $wine reg add 'HKEY_CURRENT_USER\Software\Wine\DllOverrides' /v "$dll" /d native /f >/dev/null 2>&1; then
echo -e "Failed to add override for $dll"
exit 1
fi
}
uninstall_override() {
dll=$(basename "$1")
if ! $wine reg delete 'HKEY_CURRENT_USER\Software\Wine\DllOverrides' /v "$dll" /f > /dev/null 2>&1; then
echo "Failed to remove override for $dll"
fi
}
print_cleanup_message() {
declare -a obsolete_paths=($@)
if ! $ignore_obsolete && [ -n "${obsolete_paths[@]}" ]; then
fold -w $COLUMNS -s <<MSG >&2
Obsolete DLLs detected at the specified Wine prefix. These DLLs are no longer needed \
or managed by the \`setup_dxvk.sh\` script in nixpkgs. You should remove them manually, \
use the cleanup command, or suppress this message using the \`--ignore-obsolete\` option.
MSG
for obspath in "${obsolete_paths[@]}"; do
if $do_cleanup; then
cleanup_file "$obspath"
else
echo " - ${obspath}"
fi
done
! $do_cleanup && echo
fi
}
## Perform the requested command
declare -A paths
for target in "${!targets[@]}"; do
[ "${targets[$target]}" -eq 1 ] || continue
for dll in ${dlls[$target]}; do
dllname=$(basename "$dll")
basedir=$(dirname "$dll")
if [ -n "${win32_sys_path:-}" ]; then
basedir32=${basedir}32_dir
paths["${!basedir32}/$dllname"]="$win32_sys_path/$dllname"
fi
if [ -n "${win64_sys_path:-}" ]; then
basedir64=${basedir}64_dir
paths["${!basedir64}/$dllname"]="$win64_sys_path/$dllname"
fi
done
done
declare -A obsolete_paths
for target in "${!obsolete_dlls[@]}"; do
for dll in ${obsolete_dlls[$target]}; do
dllname=$(basename "$dll")
basedir=$(dirname "$dll")
if [ -e "${win32_sys_path:-}/$dllname" ]; then
obsolete_paths["${basedir}32_dir/$dllname"]="${win32_sys_path:-}/$dllname"
fi
if [ -e "${win64_sys_path:-}/$dllname" ]; then
obsolete_paths["${basedir}64_dir/$dllname"]="${win64_sys_path:-}/$dllname"
fi
done
done
if $do_cleanup; then
declare -n action_paths=obsolete_paths
action=uninstall
args=-f
else
declare -n action_paths=paths
print_cleanup_message "${obsolete_paths[@]}"
fi
for srcpath in "${!action_paths[@]}"; do
"${action}_file" "$srcpath" "${action_paths["$srcpath"]}" "${args:-}"
"${action}_override" "$(basename "$srcpath" .dll)"
done