From 315695b4796261237e17772fbd80213c8da773bd Mon Sep 17 00:00:00 2001
From: Joerg Schirottke <master@kanotix.com>
Date: Thu, 27 Aug 2026 12:24:32 +0200
Subject: [PATCH 3/3] feat(build): local .deb build script

Assisted-by: DeepSeek V4 Flash Free
Assisted-by: Muse Spark 1.2 Free
---
 build_deb.sh | 248 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 248 insertions(+)
 create mode 100755 build_deb.sh

diff --git a/build_deb.sh b/build_deb.sh
new file mode 100755
index 0000000..65f6b43
--- /dev/null
+++ b/build_deb.sh
@@ -0,0 +1,248 @@
+#!/bin/sh
+#
+# Build a local rustdesk .deb, mirroring the packaging path used by the official
+# CI (build.py build_flutter_deb: cargo --features flutter + flutter build linux
+# + dpkg-deb). Intended for Debian/Ubuntu hosts.
+#
+# Flutter is downloaded into build/ inside this repo when it is not on PATH, and
+# all other scratch dirs (vcpkg pkg-config shims, ...) live in build/ as well.
+#
+# Usage:
+#   ./build_deb.sh [options] [build.py args...]
+#
+# Options (must come before build.py args):
+#   --install-deps       apt-get install the system build dependencies (needs sudo)
+#   --setup-vcpkg        clone + bootstrap vcpkg and install its dependencies
+#   --linux-pkg-config   build against system pkg-config libs instead of vcpkg
+#                        (needs libvpx-dev libopus-dev libaom-dev libyuv-dev)
+#   --arch ARCH          DEB_ARCH for the deb (amd64, arm64, ...)
+#   -h, --help           show this help
+#
+# Everything after the options is forwarded to ./build.py --flutter (e.g. --drm).
+
+set -eu
+
+REPO_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
+cd "$REPO_ROOT"
+
+usage() {
+  cat <<EOF
+Usage: $0 [options] [build.py args...]
+
+Builds a rustdesk .deb on this Debian/Ubuntu host. The Rust lib, the Flutter
+bundle and the deb packaging all happen locally via ./build.py --flutter.
+
+Options (must come before build.py args):
+  --install-deps       apt-get install the system build dependencies (needs sudo)
+  --setup-vcpkg        clone + bootstrap vcpkg and install its dependencies
+  --linux-pkg-config   build against system pkg-config libs instead of vcpkg
+                       (needs libvpx-dev libopus-dev libaom-dev libyuv-dev)
+  --arch ARCH          DEB_ARCH for the deb (e.g. amd64, arm64)
+  -h, --help           show this help
+
+Remaining arguments are passed through to build.py (e.g. --drm).
+
+Environment:
+  VCPKG_ROOT       vcpkg checkout with installed/<triplet>/ populated (required
+                   unless --setup-vcpkg or --linux-pkg-config is used)
+EOF
+}
+
+install_deps=0
+setup_vcpkg=0
+linux_pkg_config=0
+deb_arch=""
+
+while [ "$#" -gt 0 ]; do
+  case "$1" in
+    --install-deps) install_deps=1; shift ;;
+    --setup-vcpkg) setup_vcpkg=1; shift ;;
+    --linux-pkg-config) linux_pkg_config=1; shift ;;
+    --arch)
+      if [ "$#" -lt 2 ]; then
+        echo "error: --arch needs a value" >&2
+        exit 1
+      fi
+      deb_arch="$2"; shift 2
+      ;;
+    -h|--help) usage; exit 0 ;;
+    *) break ;;
+  esac
+done
+
+if ! command -v dpkg-deb >/dev/null 2>&1; then
+  echo "error: dpkg-deb not found - this script only builds .deb on Debian/Ubuntu-like hosts" >&2
+  exit 1
+fi
+
+missing=0
+for tool in python3 cargo git; do
+  if ! command -v "$tool" >/dev/null 2>&1; then
+    echo "error: missing required tool: $tool" >&2
+    missing=1
+  fi
+done
+if [ "$missing" -eq 1 ]; then
+  echo "  cargo:   curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh" >&2
+  exit 1
+fi
+
+# libs/hbb_common and friends are git submodules; the codegen and cargo build
+# need them checked out.
+git submodule update --init --recursive
+
+# Install Flutter into a build dir inside this repo when it is not on PATH, so a
+# bare Debian/Ubuntu host needs no system-wide Flutter. Pinned to the same 3.24.5
+# CI uses; its dropdown_menu fix is applied to the SDK exactly like CI does.
+FLUTTER_VERSION=${FLUTTER_VERSION:-3.24.5}
+if ! command -v flutter >/dev/null 2>&1; then
+  FLUTTER_DIR="$REPO_ROOT/build/flutter"
+  if [ ! -x "$FLUTTER_DIR/bin/flutter" ]; then
+    echo "Flutter not found on PATH; installing $FLUTTER_VERSION into $FLUTTER_DIR"
+    mkdir -p "$REPO_ROOT/build"
+    curl -fsSL --retry 3 \
+      "https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz" \
+      -o "$REPO_ROOT/build/flutter.tar.xz"
+    tar -xf "$REPO_ROOT/build/flutter.tar.xz" -C "$REPO_ROOT/build"
+    rm -f "$REPO_ROOT/build/flutter.tar.xz"
+    if [ "$FLUTTER_VERSION" = "3.24.5" ]; then
+      git -C "$FLUTTER_DIR" apply "$REPO_ROOT/.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff"
+    fi
+  fi
+  export PATH="$FLUTTER_DIR/bin:$PATH"
+  flutter config --no-analytics --enable-linux-desktop
+fi
+flutter --version
+
+apt_pkgs="build-essential gcc g++ clang libclang-dev cmake ninja-build pkg-config
+git curl wget unzip xz-utils zip nasm yasm tree rpm python3 libssl-dev
+libgtk-3-dev libayatana-appindicator3-dev
+libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
+libasound2-dev libpulse-dev
+libxcb-randr0-dev libxcb-shape0-dev libxcb-xfixes0-dev
+libxdo-dev libxfixes-dev libva-dev"
+
+if [ "$linux_pkg_config" -eq 1 ]; then
+  apt_pkgs="$apt_pkgs libvpx-dev libopus-dev libaom-dev libyuv-dev"
+fi
+
+if [ "$install_deps" -eq 1 ]; then
+  run_apt() {
+    if [ "$(id -u)" -eq 0 ]; then apt-get "$@"; else sudo apt-get "$@"; fi
+  }
+  run_apt update
+  # shellcheck disable=SC2086
+  run_apt install -y $apt_pkgs
+else
+  missing_pkgs=""
+  for pkg in $apt_pkgs; do
+    if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then
+      missing_pkgs="$missing_pkgs $pkg"
+    fi
+  done
+  if [ -n "$missing_pkgs" ]; then
+    echo "warning: some system packages seem to be missing:" >&2
+    for pkg in $missing_pkgs; do
+      echo "  $pkg" >&2
+    done
+    echo "re-run with --install-deps to install them" >&2
+  fi
+fi
+
+if [ "$linux_pkg_config" -eq 1 ]; then
+  for pkg in libvpx-dev libopus-dev libaom-dev libyuv-dev; do
+    if ! dpkg-query -W -f='${Status}' "$pkg" 2>/dev/null | grep -q "install ok installed"; then
+      echo "error: $pkg is required for --linux-pkg-config (install with --install-deps)" >&2
+      exit 1
+    fi
+  done
+
+  # Debian/Ubuntu's libyuv-dev ships no libyuv.pc; provide a minimal one so the
+  # linux-pkg-config build can link the system library.
+  if ! pkg-config --exists libyuv 2>/dev/null; then
+    pcdir="$REPO_ROOT/build/pkgconfig"
+    mkdir -p "$pcdir"
+    libdir=$(dpkg -L libyuv-dev 2>/dev/null | grep '/libyuv\.so$' | head -n1 | xargs dirname)
+    if [ -z "$libdir" ]; then
+      libdir="/usr/lib/x86_64-linux-gnu"
+    fi
+    printf 'prefix=/usr\nexec_prefix=${prefix}\nlibdir=%s\nincludedir=${prefix}/include\n\nName: libyuv\nDescription: YUV scaling library\nVersion: 0.0\nLibs: -L${libdir} -lyuv\nCflags: -I${includedir}\n' "$libdir" > "$pcdir/libyuv.pc"
+    export PKG_CONFIG_PATH="$pcdir${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}"
+    echo "generated $pcdir/libyuv.pc (libdir=$libdir)"
+  fi
+fi
+
+if [ "$setup_vcpkg" -eq 1 ]; then
+  VCPKG_ROOT=${VCPKG_ROOT:-$REPO_ROOT/build/vcpkg}
+  if [ ! -x "$VCPKG_ROOT/vcpkg" ]; then
+    echo "vcpkg not found at $VCPKG_ROOT; cloning into $VCPKG_ROOT"
+    mkdir -p "$REPO_ROOT/build"
+    if [ -d "$VCPKG_ROOT" ]; then
+      if [ ! -d "$VCPKG_ROOT/.git" ]; then
+        echo "error: $VCPKG_ROOT exists but is not a vcpkg checkout; remove it or set VCPKG_ROOT" >&2
+        exit 1
+      fi
+    else
+      git clone https://github.com/microsoft/vcpkg "$VCPKG_ROOT"
+    fi
+  fi
+  (cd "$VCPKG_ROOT" && ./bootstrap-vcpkg.sh)
+  export VCPKG_ROOT
+  "$VCPKG_ROOT/vcpkg" install --x-install-root="$VCPKG_ROOT/installed"
+fi
+
+if [ -z "${VCPKG_ROOT:-}" ] && [ -x "$REPO_ROOT/build/vcpkg/vcpkg" ]; then
+  VCPKG_ROOT="$REPO_ROOT/build/vcpkg"
+  export VCPKG_ROOT
+fi
+
+if [ "$linux_pkg_config" -eq 0 ] && { [ -z "${VCPKG_ROOT:-}" ] || [ ! -d "$VCPKG_ROOT/installed/x64-linux" ]; }; then
+  echo "error: VCPKG_ROOT must point to a vcpkg checkout with installed/x64-linux populated" >&2
+  echo "       set VCPKG_ROOT, run with --setup-vcpkg, or use --linux-pkg-config" >&2
+  exit 1
+fi
+
+# generate flutter/lib/generated_bridge.dart from src/flutter_ffi.rs (build.py does
+# not run the codegen itself). The codegen needs libclang.so, which newer distros
+# ship outside its default search paths (only /usr/lib/llvm-9..14 are scanned).
+LLVM_PATH=""
+for d in /usr/lib/llvm-*; do
+  if [ -f "$d/lib/libclang.so" ]; then
+    LLVM_PATH="$d"
+    break
+  fi
+done
+
+rustup component add rustfmt 2>/dev/null || true
+FRB=flutter_rust_bridge_codegen
+if ! command -v "$FRB" >/dev/null 2>&1; then
+  FRB="$HOME/.cargo/bin/flutter_rust_bridge_codegen"
+fi
+if [ ! -x "$FRB" ]; then
+  cargo install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked
+  FRB="$HOME/.cargo/bin/flutter_rust_bridge_codegen"
+fi
+if [ -n "$LLVM_PATH" ]; then
+  (cd flutter && flutter pub get && "$FRB" --llvm-path "$LLVM_PATH" \
+    --rust-input ../src/flutter_ffi.rs --dart-output ./lib/generated_bridge.dart)
+else
+  (cd flutter && flutter pub get && "$FRB" \
+    --rust-input ../src/flutter_ffi.rs --dart-output ./lib/generated_bridge.dart)
+fi
+
+if [ -n "$deb_arch" ]; then
+  export DEB_ARCH="$deb_arch"
+fi
+
+if [ "$linux_pkg_config" -eq 1 ]; then
+  # build the lib against system pkg-config libs, then package with --skip-cargo
+  # (build.py has no flag for the linux-pkg-config feature)
+  cargo build --locked --features flutter,linux-pkg-config --lib --release
+  python3 build.py --flutter --skip-cargo "$@"
+else
+  python3 build.py --flutter "$@"
+fi
+
+echo
+echo "Built:"
+ls -1 rustdesk-*.deb
\ No newline at end of file
-- 
2.47.3

