287 lines
12 KiB
Bash
Executable file
287 lines
12 KiB
Bash
Executable file
#!/usr/bin/env bash
|
||
# ==============================================================================
|
||
# DaVinci Resolve Installer for openSUSE Tumbleweed
|
||
#
|
||
# Installs DaVinci Resolve (19/20, free or Studio) on openSUSE Tumbleweed.
|
||
# Tumbleweed is a rolling-release distro that's always on the bleeding edge,
|
||
# which means it often has newer library versions than Resolve expects.
|
||
#
|
||
# This script handles several Tumbleweed-specific compatibility issues:
|
||
#
|
||
# 1. gdk-pixbuf2 — Tumbleweed's version is too new for Resolve's bundled
|
||
# Qt libraries. We fetch a compatible version from Fedora's archives
|
||
# and place it in Resolve's lib directory.
|
||
#
|
||
# 2. GLib replacement — Same as other distros: Resolve's bundled GLib
|
||
# conflicts with the system version. We replace it with system GLib.
|
||
#
|
||
# 3. OpenCL symlink — Resolve looks for libOpenCL.so.1 in its own lib
|
||
# directory. We symlink the system's OpenCL there.
|
||
#
|
||
# 4. libtiff shim — Tumbleweed ships libtiff.so.6, but Resolve wants
|
||
# libtiff.so.5. We create a compatibility symlink.
|
||
#
|
||
# 5. APR libraries — Apache Portable Runtime libs that Resolve's internal
|
||
# database engine sometimes needs on Tumbleweed.
|
||
#
|
||
# 6. XWayland wrapper — Forces Resolve to run under X11 (via XWayland)
|
||
# since it doesn't support native Wayland.
|
||
#
|
||
# Works for Resolve 19 and 20 (free and Studio editions).
|
||
#
|
||
# Prerequisites:
|
||
# - openSUSE Tumbleweed with NVIDIA drivers installed
|
||
# - DaVinci Resolve ZIP or .run downloaded to ~/Downloads/
|
||
#
|
||
# Usage:
|
||
# sudo ./install-resolve-tw.sh
|
||
# # or specify a file directly:
|
||
# sudo ./install-resolve-tw.sh /path/to/DaVinci_Resolve_Linux.zip
|
||
# ==============================================================================
|
||
|
||
# Ensure we're running in bash (not sh/dash)
|
||
[ -n "${BASH_VERSION:-}" ] || exec /usr/bin/env bash "$0" "$@"
|
||
set -euo pipefail
|
||
# Add sbin paths — some tools like ldconfig live in /sbin on openSUSE
|
||
export PATH="$PATH:/sbin:/usr/sbin"
|
||
# Enable debug mode with DEBUG=1 for verbose output
|
||
[[ "${DEBUG:-0}" == "1" ]] && set -x
|
||
|
||
# Coloured logging helpers for easy visual scanning of output
|
||
say() { echo -e "\033[1;32m==>\033[0m $*"; }
|
||
warn() { echo -e "\033[1;33m[!]\033[0m $*"; }
|
||
err() { echo -e "\033[1;31m[ERROR]\033[0m $*"; }
|
||
have() { command -v "$1" >/dev/null 2>&1; }
|
||
# zypper wrapper — --no-recommends keeps the install lean, || true prevents
|
||
# a missing optional package from killing the script
|
||
pkg_install() { sudo zypper -n in --no-recommends "$@" || true; }
|
||
|
||
# Resolve the real user's home directory for finding the ZIP in ~/Downloads/
|
||
TARGET_USER="${SUDO_USER:-$USER}"
|
||
TARGET_HOME="$(getent passwd "$TARGET_USER" | cut -d: -f6)"
|
||
USR_APP_DIR="$TARGET_HOME/.local/share/applications"
|
||
# Track temp dirs and X11 auth changes for cleanup on exit
|
||
WORKDIR=""
|
||
XHOST_ADDED=""
|
||
|
||
# Cleanup handler — removes temp extraction directory and revokes X11 root
|
||
# access that we may have granted for the GUI installer
|
||
cleanup() {
|
||
[[ -n "$WORKDIR" && -d "$WORKDIR" ]] && rm -rf "$WORKDIR"
|
||
[[ -n "$XHOST_ADDED" ]] && xhost -SI:localuser:root >/dev/null 2>&1 || true
|
||
}
|
||
trap cleanup EXIT
|
||
|
||
# Auto-detect the newest Resolve installer in ~/Downloads/. Checks for
|
||
# both .zip and .run files, preferring .zip (more common download format).
|
||
pick_latest() {
|
||
local z r
|
||
z=$(ls -t "$TARGET_HOME"/Downloads/DaVinci_Resolve*_Linux.zip 2>/dev/null | head -n1 || true)
|
||
r=$(ls -t "$TARGET_HOME"/Downloads/DaVinci_Resolve*_Linux.run 2>/dev/null | head -n1 || true)
|
||
[[ -n "$z" ]] && { echo "$z"; return; }
|
||
[[ -n "$r" ]] && { echo "$r"; return; }
|
||
echo ""
|
||
}
|
||
|
||
# -------- inputs ----------
|
||
SRC="${1:-}"
|
||
[[ -z "$SRC" ]] && SRC="$(pick_latest)"
|
||
[[ -n "$SRC" ]] || { err "Give a path to DaVinci Resolve Linux .zip or .run (or put it in ~/Downloads)."; exit 1; }
|
||
[[ -e "$SRC" ]] || { err "File not found: $SRC"; exit 1; }
|
||
|
||
# ==================== Dependencies ====================
|
||
#
|
||
# Install runtime libraries that Resolve needs. Tumbleweed uses zypper
|
||
# as its package manager. Key packages:
|
||
# libOpenCL1: OpenCL support for GPU-accelerated processing
|
||
# libjpeg62: JPEG library (Resolve uses the older ABI)
|
||
# libX11-xcb1 + xcb-*: X11/XCB protocol libraries for display
|
||
# libglib/gio/etc: GLib stack (system versions to replace bundled ones)
|
||
# libapr1/util: Apache Portable Runtime (Resolve's DB engine needs these)
|
||
say "Installing runtime tools + common libs…"
|
||
sudo zypper -n ref || true
|
||
RUNTIME_PKGS=(
|
||
unzip xhost curl rpm cpio
|
||
xwayland desktop-file-utils xdg-utils
|
||
libOpenCL1 libjpeg62 libX11-xcb1 libxcb-xinerama0 libxkbcommon-x11-0 libxcb-keysyms1
|
||
libxcb-icccm4 libxcb-cursor0 libxcb-xfixes0 libxcb-randr0 libxcb-shape0
|
||
libglib-2_0-0 libgobject-2_0-0 libgmodule-2_0-0 libgio-2_0-0 libgthread-2_0-0
|
||
libapr1-0 libapr-util1-0 # APR libs Resolve sometimes needs on TW
|
||
)
|
||
pkg_install "${RUNTIME_PKGS[@]}"
|
||
|
||
# Ensure gthread exists (blackmagic GUI installer needs it)
|
||
if ! ldconfig -p 2>/dev/null | grep -q 'libgthread-2\.0\.so\.0'; then
|
||
pkg_install libgthread-2_0-0
|
||
fi
|
||
|
||
# -------- prepare installer --------
|
||
RUN_PATH=""
|
||
if [[ "$SRC" == *.run ]]; then
|
||
RUN_PATH="$(readlink -f "$SRC")"
|
||
elif [[ "$SRC" == *.zip ]]; then
|
||
say "Validating ZIP…"
|
||
unzip -tqq "$SRC" >/dev/null 2>&1 || { err "ZIP CRC failed. Re-download from Blackmagic."; exit 1; }
|
||
BASE="${XDG_CACHE_HOME:-$TARGET_HOME/.cache}/resolve-installer"
|
||
mkdir -p "$BASE"
|
||
WORKDIR="$(mktemp -d -p "$BASE")"
|
||
say "Extracting…"
|
||
unzip -q "$SRC" -d "$WORKDIR"
|
||
RUN_PATH="$(find "$WORKDIR" -maxdepth 3 -type f -name 'DaVinci_Resolve*_Linux.run' | head -n1 || true)"
|
||
[[ -n "$RUN_PATH" && -f "$RUN_PATH" ]] || { err "Could not find DaVinci_Resolve*_Linux.run inside ZIP."; exit 1; }
|
||
else
|
||
err "Unsupported file type: $SRC"
|
||
fi
|
||
say "Using installer: $RUN_PATH"
|
||
|
||
# ==================== Run Installer ====================
|
||
#
|
||
# Blackmagic's installer is a GUI application. We try running it as the
|
||
# current user first. If that doesn't result in /opt/resolve/bin/resolve
|
||
# being created (e.g. permission denied writing to /opt), we retry with
|
||
# sudo while passing through the display environment variables so the
|
||
# GUI can still render.
|
||
#
|
||
# QT_QPA_PLATFORM=xcb forces the installer to use X11 (not Wayland).
|
||
# SKIP_PACKAGE_CHECK=1 bypasses Resolve's distro check (it doesn't
|
||
# recognise openSUSE as a supported distro).
|
||
say "Running Blackmagic installer (user)…"
|
||
chmod +x "$RUN_PATH" || true
|
||
set +e
|
||
env QT_QPA_PLATFORM=xcb SKIP_PACKAGE_CHECK=1 "$RUN_PATH"
|
||
RC_USER=$?
|
||
set -e
|
||
say "User-run exit code: $RC_USER"
|
||
|
||
if [[ ! -x /opt/resolve/bin/resolve ]]; then
|
||
if [[ -n "${DISPLAY:-}" ]] && have xhost; then
|
||
xhost +SI:localuser:root >/dev/null 2>&1 && XHOST_ADDED=1 || true
|
||
fi
|
||
say "Running Blackmagic installer (sudo fallback)…"
|
||
set +e
|
||
sudo -E env DISPLAY="${DISPLAY:-:0}" XAUTHORITY="${XAUTHORITY:-$HOME/.Xauthority}" \
|
||
XDG_RUNTIME_DIR="/run/user/$(id -u "$TARGET_USER")" \
|
||
QT_QPA_PLATFORM=xcb SKIP_PACKAGE_CHECK=1 "$RUN_PATH"
|
||
RC_SUDO=$?
|
||
set -e
|
||
say "Sudo-run exit code: $RC_SUDO"
|
||
fi
|
||
|
||
[[ -d /opt/resolve/libs ]] || { err "/opt/resolve not present; installer likely cancelled."; exit 1; }
|
||
|
||
# ==================== Tumbleweed-Specific Fixes ====================
|
||
#
|
||
# gdk-pixbuf2 fix:
|
||
# Tumbleweed's gdk-pixbuf2 is too new for Resolve's bundled Qt libraries
|
||
# (ABI mismatch causes crashes). The workaround is to grab a compatible
|
||
# version from Fedora's package archives and place it in Resolve's lib
|
||
# directory. We try archived Fedora 38/40 builds first, then fall back
|
||
# to scraping Rawhide for the latest version.
|
||
say "Applying gdk-pixbuf + GLib + OpenCL + APR tweaks for Tumbleweed…"
|
||
tmp="$(mktemp -d)"
|
||
rpmfile="$tmp/gdk.rpm"
|
||
fetch_ok=""
|
||
|
||
# Try stable archived Fedora builds first (x86_64)
|
||
for url in \
|
||
"https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/38/Everything/x86_64/os/Packages/g/gdk-pixbuf2-2.42.10-2.fc38.x86_64.rpm" \
|
||
"https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/40/Everything/x86_64/os/Packages/g/gdk-pixbuf2-2.42.10-8.fc40.x86_64.rpm" \
|
||
; do
|
||
if curl -fsSL -o "$rpmfile" "$url"; then fetch_ok="1"; break; fi
|
||
done
|
||
|
||
# Last resort: scrape Rawhide index for the latest gdk-pixbuf2 x86_64 rpm
|
||
if [[ -z "$fetch_ok" ]]; then
|
||
idx="https://dl.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/Packages/g/"
|
||
html="$(curl -fsSL "$idx" || true)"
|
||
cand="$(printf "%s" "$html" | grep -o 'gdk-pixbuf2-[^\" ]*\.x86_64\.rpm' | head -n1 || true)"
|
||
if [[ -n "$cand" ]]; then
|
||
curl -fsSL -o "$rpmfile" "${idx}${cand}" && fetch_ok="1"
|
||
fi
|
||
fi
|
||
|
||
if [[ -n "$fetch_ok" ]]; then
|
||
say "Extracting Fedora gdk-pixbuf2 into /opt/resolve/libs…"
|
||
( cd "$tmp" && rpm2cpio "$rpmfile" | cpio -idmv >/dev/null 2>&1 )
|
||
if [[ -d "$tmp/usr/lib64" ]]; then
|
||
sudo cp -vr "$tmp/usr/lib64/"* /opt/resolve/libs/ || true
|
||
else
|
||
warn "No usr/lib64 in RPM payload — skipping copy."
|
||
fi
|
||
else
|
||
warn "Could not fetch a Fedora gdk-pixbuf2 RPM (all URLs failed)."
|
||
fi
|
||
rm -rf "$tmp"
|
||
|
||
# Symlink the system's OpenCL library into Resolve's lib directory.
|
||
# Resolve needs libOpenCL.so.1 for GPU-accelerated processing (effects,
|
||
# colour grading, neural engine). On Tumbleweed it's usually provided
|
||
# by ocl-icd (OpenCL Installable Client Driver).
|
||
ocl="$(ldconfig -p 2>/dev/null | awk '/libOpenCL\.so\.1/{print $4; exit}')"
|
||
[[ -z "${ocl:-}" && -e /usr/lib64/ocl-icd/libOpenCL.so.1.0.0 ]] && ocl=/usr/lib64/ocl-icd/libOpenCL.so.1.0.0
|
||
[[ -n "${ocl:-}" ]] && sudo ln -sf "$ocl" /opt/resolve/libs/libOpenCL.so.1 || warn "libOpenCL.so.1 not found."
|
||
|
||
# Replace Resolve’s bundled GLib with the system version. Same fix as on
|
||
# Arch/Mint/Rocky — the bundled version is older and conflicts with other
|
||
# system libraries that Resolve also loads.
|
||
if ls /lib64/libglib-2.0.* >/dev/null 2>&1; then
|
||
sudo rm -f /opt/resolve/libs/libglib-2.0.so* || true
|
||
sudo cp -va /lib64/libglib-2.0.* /opt/resolve/libs/
|
||
elif ls /usr/lib64/libglib-2.0.* >/dev/null 2>&1; then
|
||
sudo rm -f /opt/resolve/libs/libglib-2.0.so* || true
|
||
sudo cp -va /usr/lib64/libglib-2.0.* /opt/resolve/libs/
|
||
fi
|
||
|
||
# libtiff compatibility shim — Tumbleweed ships libtiff.so.6, but Resolve
|
||
# links against libtiff.so.5. Creating a symlink works because the ABI
|
||
# is backwards-compatible between these versions.
|
||
if ! ldconfig -p | grep -q 'libtiff\.so\.5'; then
|
||
[[ -e /usr/lib64/libtiff.so.6 && ! -e /opt/resolve/libs/libtiff.so.5 ]] && \
|
||
sudo ln -s /usr/lib64/libtiff.so.6 /opt/resolve/libs/libtiff.so.5 || true
|
||
fi
|
||
|
||
# ==================== XWayland Wrapper ====================
|
||
#
|
||
# Create a wrapper script that forces Resolve to run under X11 (XWayland)
|
||
# and sets up the library search path. Tumbleweed defaults to Wayland on
|
||
# most desktop environments, but Resolve doesn't support native Wayland.
|
||
#
|
||
# Key environment variables:
|
||
# QT_QPA_PLATFORM=xcb: Force X11 mode
|
||
# __GLX_VENDOR_LIBRARY_NAME=nvidia: Use NVIDIA's GLX implementation
|
||
# QT_XCB_GL_INTEGRATION=none: Disable Qt's XCB GL integration
|
||
# (avoids conflicts with NVIDIA GL)
|
||
# QT_OPENGL=desktop: Use desktop OpenGL (not GLES)
|
||
# LD_LIBRARY_PATH: Prioritise our patched libs in /opt/resolve/
|
||
say "Creating /usr/local/bin/resolve wrapper…"
|
||
sudo tee /usr/local/bin/resolve >/dev/null <<'EOF'
|
||
#!/usr/bin/env bash
|
||
# Force X11/XWayland + NVIDIA GLVND
|
||
export QT_QPA_PLATFORM=xcb
|
||
export __GLX_VENDOR_LIBRARY_NAME=nvidia
|
||
export QT_XCB_GL_INTEGRATION=none
|
||
export QT_OPENGL=desktop
|
||
# Prefer the libs we just placed in /opt/resolve/libs
|
||
export LD_LIBRARY_PATH="/opt/resolve/libs:/opt/resolve/bin:${LD_LIBRARY_PATH:-}"
|
||
exec /opt/resolve/bin/resolve "$@"
|
||
EOF
|
||
sudo chmod +x /usr/local/bin/resolve
|
||
|
||
# Copy and patch desktop entries to use our wrapper instead of launching
|
||
# Resolve directly. User-level entries in ~/.local/share/applications/
|
||
# take priority over system entries in /usr/share/applications/.
|
||
say "Patching desktop entries to use wrapper…"
|
||
mkdir -p "$USR_APP_DIR"
|
||
for f in /usr/share/applications/davinci-resolve.desktop \
|
||
/usr/share/applications/com.blackmagicdesign.resolve.desktop; do
|
||
if [[ -f "$f" ]]; then
|
||
install -m 0644 "$f" "$USR_APP_DIR/"
|
||
tgt="$USR_APP_DIR/$(basename "$f")"
|
||
sed -i 's|^Exec=.*|Exec=/usr/local/bin/resolve %u|g' "$tgt"
|
||
sed -i 's|^TryExec=.*|TryExec=/usr/local/bin/resolve|g' "$tgt" || true
|
||
sed -i 's|^Path=.*|Path=/opt/resolve/|g' "$tgt" || true
|
||
fi
|
||
done
|
||
command -v update-desktop-database >/dev/null 2>&1 && update-desktop-database "$USR_APP_DIR" || true
|
||
|
||
say "Done. Launch with: resolve"
|