From 47e6015ebd250a30b481d2f35c4944e60490ec2a Mon Sep 17 00:00:00 2001 From: Proggerdogger <143052591+Proggerdogger@users.noreply.github.com> Date: Sun, 19 Jul 2026 13:07:50 +1000 Subject: [PATCH] Add Debian/Ubuntu preflight dependency check for build-shotcut.sh Detect missing host build tools before a long compile and print one sorted sudo apt install command. Disable with ACTION_PREFLIGHT=0. --- README.md | 8 ++ scripts/build-shotcut.sh | 17 ++++ scripts/preflight-deps.sh | 186 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100755 scripts/preflight-deps.sh diff --git a/README.md b/README.md index 6b878f5325..522278df40 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,14 @@ The fastest way to build and try Shotcut development version is through [Qt Crea First, check dependencies are satisfied and various paths are correctly set to find different libraries and include files (Qt, MLT, frei0r and so forth). +If you build with `scripts/build-shotcut.sh`, run the Debian/Ubuntu preflight checker to verify host build tools up front: + +``` +scripts/preflight-deps.sh +``` + +`build-shotcut.sh` runs this check by default before fetching or compiling. Disable it with `ACTION_PREFLIGHT=0` in `build-shotcut.conf`. + #### Configure In a new directory in which to make the build (separate from the source): diff --git a/scripts/build-shotcut.sh b/scripts/build-shotcut.sh index 93c1864d1b..21af41f323 100755 --- a/scripts/build-shotcut.sh +++ b/scripts/build-shotcut.sh @@ -18,6 +18,7 @@ INSTALL_DIR="$HOME/shotcut" AUTO_APPEND_DATE=0 SOURCE_DIR="$INSTALL_DIR/src" ACTION_CLEAN_SOURCE=0 +ACTION_PREFLIGHT=1 ACTION_GET=1 ACTION_CONFIGURE=1 ACTION_COMPILE_INSTALL=1 @@ -2259,6 +2260,22 @@ End-of-shotcut-wrapper function perform_action { trace "Entering perform_action @ = $@" # Test that may fail goes here, before we do anything + if test 1 = "$ACTION_PREFLIGHT"; then + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + if [ -x "$SCRIPT_DIR/preflight-deps.sh" ]; then + set +e + "$SCRIPT_DIR/preflight-deps.sh" + PREFLIGHT_EXIT=$? + set -e + if test "$PREFLIGHT_EXIT" = "1"; then + die "Missing build dependencies. Install them with the sudo apt install command printed above, or set ACTION_PREFLIGHT=0 to skip." + elif test "$PREFLIGHT_EXIT" = "2"; then + warn "Preflight check not supported on this OS. Continuing without the dependency check." + fi + else + warn "Preflight script not found at $SCRIPT_DIR/preflight-deps.sh. Skipping dependency check." + fi + fi if test 1 = "$ACTION_CLEAN_SOURCE"; then clean_dirs fi diff --git a/scripts/preflight-deps.sh b/scripts/preflight-deps.sh new file mode 100755 index 0000000000..04c914a36b --- /dev/null +++ b/scripts/preflight-deps.sh @@ -0,0 +1,186 @@ +#!/bin/bash +# Check host build dependencies for scripts/build-shotcut.sh on Debian/Ubuntu. +# Exit 0 = all present, 1 = missing packages, 2 = unsupported OS. +# Never installs packages; only reports. + +set -uo pipefail + +OS_FAMILY="" +MISSING_PACKAGES=() + +add_missing() { + local label="$1" + local pkg="$2" + echo "missing: ${label} (provided by apt package: ${pkg})" + MISSING_PACKAGES+=("$pkg") +} + +have_cmd() { + command -v "$1" >/dev/null 2>&1 +} + +check_command() { + local cmd="$1" + local pkg="$2" + if ! have_cmd "$cmd"; then + add_missing "$cmd" "$pkg" + return 1 + fi + return 0 +} + +check_perl_module() { + local module="$1" + local pkg="$2" + if ! have_cmd perl; then + # perl itself is reported by check_command; skip module probe. + return 1 + fi + if ! perl -M"$module" -e 1 >/dev/null 2>&1; then + add_missing "perl module $module" "$pkg" + return 1 + fi + return 0 +} + +check_pkg_config() { + local pc="$1" + local pkg="$2" + if ! have_cmd pkg-config && ! have_cmd pkgconf; then + # pkg-config itself is reported separately; skip PC checks. + return 1 + fi + local pc_bin=pkg-config + have_cmd pkg-config || pc_bin=pkgconf + if ! "$pc_bin" --exists "$pc" >/dev/null 2>&1; then + add_missing "$pc" "$pkg" + return 1 + fi + return 0 +} + +check_header() { + local header="$1" + local pkg="$2" + local path + for path in /usr/include /usr/local/include; do + if [ -f "$path/$header" ] || [ -d "$path/$header" ]; then + return 0 + fi + done + add_missing "header $header" "$pkg" + return 1 +} + +detect_os() { + local id="" id_like="" + if [ -f /etc/os-release ]; then + # shellcheck disable=SC1091 + . /etc/os-release + id="${ID:-}" + id_like="${ID_LIKE:-}" + fi + + case "$id" in + debian|ubuntu|linuxmint|pop|raspbian|elementary|zorin|neon) + OS_FAMILY="debian" + return + ;; + esac + + case " $id_like " in + *" debian "*|*" ubuntu "*) + OS_FAMILY="debian" + return + ;; + esac + + if [ -f /etc/debian_version ]; then + OS_FAMILY="debian" + return + fi + + OS_FAMILY="unsupported" +} + +check_debian_deps() { + check_command git git || true + check_command make make || true + check_command cmake cmake || true + check_command ninja ninja-build || true + check_command meson meson || true + check_command python3 python3 || true + check_command perl perl || true + check_command autoconf autoconf || true + check_command automake automake || true + # Debian's libtool package provides libtoolize; libtool-bin adds the + # libtool wrapper. Either is enough for the autoconf build path. + if ! have_cmd libtool && ! have_cmd libtoolize; then + add_missing "libtool/libtoolize" libtool + fi + check_command autoreconf autoconf || true + check_command aclocal automake || true + check_command autopoint gettext || true + check_command gettext gettext || true + # Debian may provide pkg-config or pkgconf + if ! have_cmd pkg-config && ! have_cmd pkgconf; then + add_missing "pkg-config" pkg-config + fi + check_command gcc gcc || true + check_command g++ g++ || true + check_command glslc glslc || true + + if ! have_cmd nasm && ! have_cmd yasm; then + add_missing "nasm or yasm" nasm + fi + + if ! have_cmd curl && ! have_cmd wget; then + add_missing "curl or wget" curl + fi + + check_perl_module "List::MoreUtils" liblist-moreutils-perl || true + check_perl_module "XML::Parser" libxml-parser-perl || true + + # Eigen3: prefer pkg-config, fall back to headers. + if have_cmd pkg-config || have_cmd pkgconf; then + check_pkg_config eigen3 libeigen3-dev || true + else + check_header "eigen3/Eigen/Core" libeigen3-dev || \ + check_header "Eigen/Core" libeigen3-dev || true + fi +} + +print_install_hint() { + local sorted + # Use absolute paths: PATH may be empty in tests / constrained environments. + sorted=$(printf '%s\n' "${MISSING_PACKAGES[@]}" | /usr/bin/sort -u | /usr/bin/tr '\n' ' ') + sorted=${sorted%% } + echo "" + echo "Install missing dependencies with: sudo apt install -y ${sorted}" +} + +main() { + detect_os + + if [ "$OS_FAMILY" != "debian" ]; then + echo "Preflight dependency check is not supported on this OS." + echo "Only Debian/Ubuntu-family distributions are supported." + echo "Install the build tools required by scripts/build-shotcut.sh manually, then continue." + exit 2 + fi + + echo "Checking dependencies for Debian/Ubuntu..." + echo "" + check_debian_deps + + if [ ${#MISSING_PACKAGES[@]} -eq 0 ]; then + echo "" + echo "All required dependencies are installed." + exit 0 + fi + + print_install_hint + exit 1 +} + +main "$@"