301 lines
14 KiB
YAML
301 lines
14 KiB
YAML
name: build-linux
|
|
|
|
on:
|
|
push:
|
|
branches: [pro-features]
|
|
workflow_dispatch:
|
|
inputs:
|
|
version_suffix:
|
|
description: "Version suffix (e.g. 'cst', 'beta1'). Empty = vanilla."
|
|
type: string
|
|
default: "cst"
|
|
|
|
env:
|
|
RUST_VERSION: "1.75"
|
|
LLVM_VERSION: "15.0.6"
|
|
# Where provision.sh installs LLVM (binary tarball from llvm.org). Same exact
|
|
# version as the Windows runner uses, distro-portable.
|
|
LLVM_HOME: '/opt/llvm-15.0.6'
|
|
FLUTTER_VERSION: "3.24.5"
|
|
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
|
|
CARGO_EXPAND_VERSION: "1.0.95"
|
|
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1"
|
|
VERSION_BASE: "1.4.6"
|
|
VERSION_SUFFIX: ${{ inputs.version_suffix || 'cst' }}
|
|
|
|
jobs:
|
|
build-x64:
|
|
name: build-linux-x64
|
|
# Distro-agnostic: any Linux runner provisioned by ci/runners/linux/provision.sh
|
|
# carries `self-hosted`, `Linux`, `X64`. To target a specific distro
|
|
# (e.g. force Debian 13), append its label: [self-hosted, Linux, X64, debian-13].
|
|
runs-on: [self-hosted, Linux, X64]
|
|
timeout-minutes: 240
|
|
env:
|
|
VCPKG_ROOT: /opt/vcpkg
|
|
VCPKG_BINARY_SOURCES: "clear;files,/var/cache/vcpkg,readwrite"
|
|
LIBCLANG_PATH: /opt/llvm-15.0.6/lib
|
|
steps:
|
|
- name: Checkout source
|
|
uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Verify host toolchain
|
|
shell: bash
|
|
run: |
|
|
required=(node git bash python3 rustc cargo rustup clang flutter cmake ninja nasm pkg-config dpkg-deb)
|
|
missing=()
|
|
for t in "${required[@]}"; do
|
|
if command -v "$t" >/dev/null 2>&1; then
|
|
printf '%-20s %s\n' "$t" "$(command -v "$t")"
|
|
else
|
|
missing+=("$t")
|
|
printf '%-20s MISSING\n' "$t"
|
|
fi
|
|
done
|
|
if [[ ${#missing[@]} -gt 0 ]]; then
|
|
echo "Missing tools: ${missing[*]}. Re-run provision.sh on the runner host."
|
|
exit 1
|
|
fi
|
|
[[ -d "$VCPKG_ROOT" && -x "$VCPKG_ROOT/vcpkg" ]] || {
|
|
echo "VCPKG_ROOT=$VCPKG_ROOT invalid"; exit 1; }
|
|
[[ -f "$LIBCLANG_PATH/libclang.so" ]] || {
|
|
echo "libclang.so not found at $LIBCLANG_PATH"; exit 1; }
|
|
|
|
- name: Compute version strings
|
|
shell: bash
|
|
run: |
|
|
base="${VERSION_BASE}"
|
|
suffix="${VERSION_SUFFIX}"
|
|
[[ "$base" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
|
|
echo "VERSION_BASE '$base' must be major.minor.patch"; exit 1; }
|
|
if [[ -n "$suffix" ]]; then display="${base}-${suffix}"; else display="${base}"; fi
|
|
echo "Base : $base"
|
|
echo "Suffix : $suffix"
|
|
echo "Display : $display"
|
|
echo "VERSION_DISPLAY=$display" >> "$GITHUB_ENV"
|
|
|
|
- name: Patch Cargo.toml with display version
|
|
shell: bash
|
|
run: |
|
|
sed -i -E "0,/^version[[:space:]]*=/{s/^version[[:space:]]*=[[:space:]]*\"${VERSION_BASE}\"/version = \"${VERSION_DISPLAY}\"/}" Cargo.toml
|
|
grep '^version' Cargo.toml | head -1
|
|
|
|
- name: Ensure Rust toolchain configured
|
|
shell: bash
|
|
run: |
|
|
# provision.sh installs Rust machine-wide at /opt/cargo + /opt/rustup,
|
|
# so this is normally a no-op verification. Kept as a guardrail.
|
|
rustup toolchain install "$RUST_VERSION" --profile minimal --component rustfmt
|
|
rustup default "$RUST_VERSION"
|
|
rustup target add x86_64-unknown-linux-gnu
|
|
rustc --version
|
|
cargo --version
|
|
|
|
- name: Install flutter_rust_bridge codegen tools
|
|
shell: bash
|
|
run: |
|
|
# Pin install destination so binaries land in a deterministic path
|
|
# regardless of CARGO_HOME.
|
|
tools=/opt/cargo-tools
|
|
mkdir -p "$tools/bin"
|
|
cargo install --root "$tools" cargo-expand --version "$CARGO_EXPAND_VERSION" --locked
|
|
cargo install --root "$tools" flutter_rust_bridge_codegen --version "$FLUTTER_RUST_BRIDGE_VERSION" --features uuid --locked
|
|
ls -la "$tools/bin"
|
|
[[ -x "$tools/bin/flutter_rust_bridge_codegen" ]] || { echo "missing fr_bridge_codegen"; exit 1; }
|
|
echo "$tools/bin" >> "$GITHUB_PATH"
|
|
|
|
- name: Generate Rust <-> Dart bridge (with Flutter 3.22.3)
|
|
shell: bash
|
|
run: |
|
|
set -e
|
|
# flutter_rust_bridge_codegen 1.80.1 + freezed produces broken Dart
|
|
# output (wrong FFI types, unprefixed Int/Pointer in part files) when
|
|
# run under Flutter 3.24.5 on Linux. Upstream's bridge.yml works around
|
|
# this by running the bridge generation under Flutter 3.22.3 -- the
|
|
# produced .dart/.freezed.dart files are then compatible with the
|
|
# 3.24.5 build that follows.
|
|
#
|
|
# provision.sh installs Flutter 3.22.3 at /opt/flutter-bridge alongside
|
|
# /opt/flutter (3.24.5). Use the bridge SDK ONLY for pub get + codegen,
|
|
# then unset PATH overrides so subsequent steps use the build SDK.
|
|
export PATH="/opt/cargo-tools/bin:/opt/flutter-bridge/bin:$PATH"
|
|
flutter --version
|
|
command -v flutter_rust_bridge_codegen
|
|
|
|
# extended_text 14.0.0 requires Dart >=3.5 (Flutter 3.24+). Flutter
|
|
# 3.22.3 has Dart 3.4.4, so downgrade to 13.0.0 for the duration of
|
|
# bridge generation. Mirrors upstream bridge.yml.
|
|
(cd flutter && sed -i -e 's/extended_text: 14.0.0/extended_text: 13.0.0/g' pubspec.yaml)
|
|
(cd flutter && flutter pub get)
|
|
|
|
# flutter_rust_bridge_codegen invokes `flutter pub run ffigen`
|
|
# internally, which re-validates pubspec.yaml -- so pubspec.yaml must
|
|
# still be the downgraded version when this runs.
|
|
flutter_rust_bridge_codegen \
|
|
--llvm-path "$LLVM_HOME" \
|
|
--rust-input ./src/flutter_ffi.rs \
|
|
--dart-output ./flutter/lib/generated_bridge.dart \
|
|
--c-output ./flutter/macos/Runner/bridge_generated.h
|
|
cp ./flutter/macos/Runner/bridge_generated.h ./flutter/ios/Runner/bridge_generated.h
|
|
|
|
# Now bridge gen is done. Restore the original pubspec.yaml and
|
|
# re-resolve under the build SDK (3.24.5) so pubspec.lock has the
|
|
# correct entries for the final flutter build linux step.
|
|
(cd flutter && git checkout -- pubspec.yaml)
|
|
(cd flutter && /opt/flutter/bin/flutter pub get)
|
|
|
|
# ============================================================
|
|
# CRITICAL FIX for flutter_rust_bridge_codegen 1.80.1 on Linux
|
|
# ============================================================
|
|
# flutter_rust_bridge_codegen 1.80.1 emits a stray
|
|
# typedef bool = ffi.NativeFunction<ffi.Int Function(ffi.Pointer<ffi.Int>)>;
|
|
# line near the end of generated_bridge.dart on Linux (the Windows
|
|
# generation does not hit this codepath). That typedef shadows
|
|
# dart:core.bool for the whole library AND every part file (notably
|
|
# generated_bridge.freezed.dart), corrupting every `bool` reference in
|
|
# the codebase. Symptoms include:
|
|
# - "Type 'Int' not found" / "Type 'Pointer' not found" in .freezed.dart
|
|
# - "value of type 'bool' can't be assigned to NativeFunction<...>"
|
|
# in every model file
|
|
# - the wire class's `int ptr` mismatching its parent's
|
|
# Pointer<NativeFunction<Bool ...>> type
|
|
#
|
|
# Drop the line. References to `bool` then resolve to dart:core.bool
|
|
# as every line of source code actually intends.
|
|
sed -i '/^typedef bool = /d' flutter/lib/generated_bridge.dart
|
|
if grep -n '^typedef bool = ' flutter/lib/generated_bridge.dart >/dev/null; then
|
|
echo "ERROR: stray 'typedef bool' still present in generated_bridge.dart" >&2
|
|
grep -n '^typedef bool = ' flutter/lib/generated_bridge.dart >&2
|
|
exit 1
|
|
fi
|
|
echo "Stripped stray 'typedef bool = ...' line from generated_bridge.dart"
|
|
|
|
# Second bug: inside `ffi.NativeFunction<...>` template arguments,
|
|
# inner FFI types `Int` and `Pointer` are emitted without the `ffi.`
|
|
# prefix that the parent file's `import 'dart:ffi' as ffi;` requires.
|
|
for f in flutter/lib/generated_bridge.dart flutter/lib/generated_bridge.freezed.dart; do
|
|
[ -f "$f" ] || continue
|
|
sed -i -E '
|
|
s/([^A-Za-z0-9_.])Pointer</\1ffi.Pointer</g
|
|
s/([^A-Za-z0-9_.])Int([> ,)])/\1ffi.Int\2/g
|
|
' "$f"
|
|
done
|
|
|
|
# Third bug: codegen emits `ffi.Pointer<bool>` (lowercase Dart bool,
|
|
# which isn't a NativeType) instead of `ffi.Pointer<ffi.Bool>` (the
|
|
# FFI Bool marker type that satisfies Pointer's bound). Same for any
|
|
# `ffi.Pointer<bool*>` variants if they appear (defensive). This also
|
|
# has to NOT touch `bool` outside Pointer<>.
|
|
sed -i 's/ffi\.Pointer<bool>/ffi.Pointer<ffi.Bool>/g' flutter/lib/generated_bridge.dart
|
|
|
|
# Fourth bug: the wire class's override of store_dart_post_cobject has
|
|
# parameter type `int` (web/stub form) but the active native parent
|
|
# in flutter_rust_bridge expects
|
|
# Pointer<NativeFunction<Bool Function(Int64, Pointer<Void>)>>
|
|
# The internal _lookup is `Void Function(Int)` so we pass ptr.address.
|
|
# Confine the substitution to the lines between `void
|
|
# store_dart_post_cobject(` and the closing `);` to avoid touching
|
|
# other functions.
|
|
sed -i '/void store_dart_post_cobject(/,/);/ {
|
|
s| int ptr,| ffi.Pointer<ffi.NativeFunction<ffi.Bool Function(ffi.Int64, ffi.Pointer<ffi.Void>)>> ptr,|
|
|
s| ptr,| ptr.address,|
|
|
}' flutter/lib/generated_bridge.dart
|
|
|
|
echo "Applied flutter_rust_bridge 1.80.1 Linux-output workarounds (4 patches)"
|
|
|
|
- name: Diagnose generated bridge files
|
|
shell: bash
|
|
run: |
|
|
set +e
|
|
echo "============================================================"
|
|
echo " generated_bridge.dart (first 80 lines)"
|
|
echo "============================================================"
|
|
head -80 flutter/lib/generated_bridge.dart 2>/dev/null || echo "(missing)"
|
|
echo
|
|
echo "============================================================"
|
|
echo " generated_bridge.freezed.dart (first 80 lines)"
|
|
echo "============================================================"
|
|
head -80 flutter/lib/generated_bridge.freezed.dart 2>/dev/null || echo "(missing)"
|
|
echo
|
|
echo "============================================================"
|
|
echo " Search: typedef declarations that might shadow bool/Int/Pointer"
|
|
echo "============================================================"
|
|
grep -nE 'typedef (bool|Int|Pointer|Bool)' \
|
|
flutter/lib/generated_bridge.dart \
|
|
flutter/lib/generated_bridge.freezed.dart 2>/dev/null || echo "(no shadowing typedefs)"
|
|
echo
|
|
echo "============================================================"
|
|
echo " Search: imports that might pull weird symbols"
|
|
echo "============================================================"
|
|
grep -nE '^import|^export|^part ' \
|
|
flutter/lib/generated_bridge.dart \
|
|
flutter/lib/generated_bridge.freezed.dart 2>/dev/null
|
|
echo
|
|
echo "============================================================"
|
|
echo " store_dart_post_cobject signature in generated_bridge.dart"
|
|
echo "============================================================"
|
|
grep -nA2 'store_dart_post_cobject' flutter/lib/generated_bridge.dart 2>/dev/null | head -30
|
|
echo
|
|
echo "============================================================"
|
|
echo " Line 25 of generated_bridge.freezed.dart (the failing one)"
|
|
echo "============================================================"
|
|
sed -n '20,30p' flutter/lib/generated_bridge.freezed.dart 2>/dev/null
|
|
echo
|
|
echo "============================================================"
|
|
echo " flutter_rust_bridge package version actually resolved"
|
|
echo "============================================================"
|
|
grep -A2 'flutter_rust_bridge:' flutter/pubspec.lock | head -10
|
|
|
|
- name: vcpkg install dependencies (x64-linux)
|
|
shell: bash
|
|
env:
|
|
VCPKG_DEFAULT_HOST_TRIPLET: x64-linux
|
|
run: |
|
|
mkdir -p /var/cache/vcpkg
|
|
if ! "$VCPKG_ROOT/vcpkg" install \
|
|
--triplet x64-linux \
|
|
--x-install-root="$VCPKG_ROOT/installed"; then
|
|
find "$VCPKG_ROOT/" -name '*.log' -exec sh -c 'echo "===== {} ====="; cat "{}"' \;
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build RustDesk (.deb)
|
|
shell: bash
|
|
run: |
|
|
set -e
|
|
# build.py on Linux (no pacman/yum/zypper detected) goes to
|
|
# build_flutter_deb() which does:
|
|
# - cargo build --features <features> --lib --release
|
|
# - flutter build linux --release
|
|
# - assembles tmpdeb/ and runs dpkg-deb -b
|
|
# Output: ./rustdesk-<version-from-Cargo.toml>.deb in the repo root.
|
|
python3 build.py --flutter --hwcodec --unix-file-copy-paste
|
|
|
|
mkdir -p ./SignOutput
|
|
# build.py names the .deb after Cargo.toml's version which we patched
|
|
# above, so the file should already carry $VERSION_DISPLAY.
|
|
mv "./rustdesk-${VERSION_DISPLAY}.deb" "./SignOutput/rustdesk-${VERSION_DISPLAY}-amd64.deb"
|
|
|
|
- name: Report signing status of build artifacts
|
|
shell: bash
|
|
run: |
|
|
# .deb files are typically signed with debsign or via the apt repo
|
|
# signing pipeline, not the .deb itself. Just list contents for now.
|
|
for f in ./SignOutput/*.deb; do
|
|
[[ -f "$f" ]] || continue
|
|
size=$(stat -c%s "$f")
|
|
printf '[UNSIGNED] %s (%d bytes)\n' "$(basename "$f")" "$size"
|
|
done
|
|
# Gitea/GHA-style annotation so it surfaces in the run summary.
|
|
echo "::warning title=Unsigned .deb::Wire up debsigs / repo signing before distributing."
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: rustdesk-linux-x64-${{ github.sha }}
|
|
path: SignOutput/rustdesk-*.deb
|
|
if-no-files-found: warn
|
|
retention-days: 14
|