Files
rustdesk-windows-build/.gitea/workflows/windows.yml
T
2026-09-13 16:03:45 +03:00

1070 lines
31 KiB
YAML

name: RustDesk Windows x64
on:
workflow_dispatch:
env:
RUSTDESK_VERSION: "1.4.9"
# Build target constants, not software versions.
RUST_TARGET: x86_64-pc-windows-msvc
VCPKG_TRIPLET: x64-windows-static
jobs:
resolve-config:
name: Resolve upstream build config
runs-on: rustdesk-android
steps:
- name: Clone selected RustDesk tag
shell: bash
run: |
set -euxo pipefail
rm -rf rustdesk-config build-config
git clone \
--branch "${RUSTDESK_VERSION}" \
--depth 1 \
https://github.com/rustdesk/rustdesk.git \
rustdesk-config
- name: Extract upstream tool versions
shell: bash
run: |
set -euxo pipefail
mkdir -p build-config
python3 - <<'PY'
import re
from pathlib import Path
repo = Path("rustdesk-config")
flutter_file = repo / ".github/workflows/flutter-build.yml"
bridge_file = repo / ".github/workflows/bridge.yml"
topmost_file = repo / ".github/workflows/third-party-RustDeskTempTopMostWindow.yml"
flutter = flutter_file.read_text(encoding="utf-8")
bridge = bridge_file.read_text(encoding="utf-8")
topmost = topmost_file.read_text(encoding="utf-8") if topmost_file.exists() else ""
def env_value(text, name, required=True):
m = re.search(
rf'(?m)^\s*{re.escape(name)}:\s*["\']?([^"\'#\s]+)',
text,
)
if m:
return m.group(1).strip()
if required:
raise SystemExit(f"Unable to resolve {name}")
return ""
windows_rust = (
env_value(flutter, "SCITER_RUST_VERSION", False)
or env_value(flutter, "RUST_VERSION")
)
bridge_flutter_match = re.search(
r'flutter-version:\s*["\']([^"\']+)["\']',
bridge,
)
if not bridge_flutter_match:
raise SystemExit("Unable to resolve bridge Flutter version")
topmost_match = re.search(
r"git\s+checkout\s+([0-9a-fA-F]{40})",
topmost,
)
values = {
"WINDOWS_RUST_VERSION": windows_rust,
"LLVM_VERSION": env_value(flutter, "LLVM_VERSION"),
"WINDOWS_FLUTTER_VERSION": env_value(flutter, "FLUTTER_VERSION"),
"VCPKG_COMMIT_ID": env_value(flutter, "VCPKG_COMMIT_ID"),
"BRIDGE_RUST_VERSION": env_value(bridge, "RUST_VERSION"),
"BRIDGE_FLUTTER_VERSION": bridge_flutter_match.group(1),
"FRB_VERSION": env_value(bridge, "FLUTTER_RUST_BRIDGE_VERSION"),
"CARGO_EXPAND_VERSION": env_value(bridge, "CARGO_EXPAND_VERSION", False),
"TOPMOST_COMMIT": topmost_match.group(1) if topmost_match else "HEAD",
"USE_CUSTOM_ENGINE": "1" if "windows-x64-release.zip" in flutter else "0",
}
out = Path("build-config/build-config.env")
out.write_text(
"".join(f"{k}={v}\n" for k, v in values.items()),
encoding="utf-8",
)
for k, v in values.items():
print(f"{k}={v}")
PY
- name: Upload build config
uses: https://github.com/actions/upload-artifact@v7
with:
name: rustdesk-build-config
path: build-config/build-config.env
if-no-files-found: error
retention-days: 1
generate-bridge:
name: Generate Flutter Rust Bridge
needs: [resolve-config]
runs-on: rustdesk-android
steps:
- name: Download build config
uses: https://github.com/actions/download-artifact@v8
with:
name: rustdesk-build-config
path: build-config
- name: Load build config
shell: bash
run: |
set -euxo pipefail
while IFS='=' read -r key value; do
[ -z "${key}" ] && continue
echo "${key}=${value}" >> "${GITHUB_ENV}"
done < build-config/build-config.env
- name: Clone selected RustDesk tag
shell: bash
run: |
set -euxo pipefail
rm -rf rustdesk bridge-artifact
git clone \
--branch "${RUSTDESK_VERSION}" \
--depth 1 \
https://github.com/rustdesk/rustdesk.git \
rustdesk
git -C rustdesk submodule update --init --recursive
- name: Prepare bridge toolchain
shell: bash
run: |
set -euxo pipefail
rustup toolchain install \
"${BRIDGE_RUST_VERSION}" \
--profile minimal \
--component rustfmt
export RUSTUP_TOOLCHAIN="${BRIDGE_RUST_VERSION}"
echo "RUSTUP_TOOLCHAIN=${BRIDGE_RUST_VERSION}" >> "${GITHUB_ENV}"
if [ -x "/opt/flutter-${BRIDGE_FLUTTER_VERSION}/bin/flutter" ]; then
FLUTTER_DIR="/opt/flutter-${BRIDGE_FLUTTER_VERSION}"
else
FLUTTER_DIR="${HOME}/.cache/rustdesk/flutter-${BRIDGE_FLUTTER_VERSION}"
if [ ! -x "${FLUTTER_DIR}/bin/flutter" ]; then
rm -rf "${FLUTTER_DIR}"
mkdir -p "$(dirname "${FLUTTER_DIR}")"
git clone \
--branch "${BRIDGE_FLUTTER_VERSION}" \
--depth 1 \
https://github.com/flutter/flutter.git \
"${FLUTTER_DIR}"
fi
fi
git config --global --add safe.directory "${FLUTTER_DIR}" || true
export PATH="${FLUTTER_DIR}/bin:${HOME}/.cargo/bin:${PATH}"
echo "${FLUTTER_DIR}/bin" >> "${GITHUB_PATH}"
flutter config --no-analytics
flutter --version
rustc --version
if [ -n "${CARGO_EXPAND_VERSION}" ]; then
current="$(
cargo expand --version 2>/dev/null | awk '{print $2}' || true
)"
if [ "${current}" != "${CARGO_EXPAND_VERSION}" ]; then
cargo install \
cargo-expand \
--version "${CARGO_EXPAND_VERSION}" \
--locked \
--force
fi
fi
current="$(
flutter_rust_bridge_codegen --version 2>/dev/null |
awk '{print $2}' ||
true
)"
if [ "${current}" != "${FRB_VERSION}" ]; then
cargo install \
flutter_rust_bridge_codegen \
--version "${FRB_VERSION}" \
--features uuid \
--locked \
--force
fi
- name: Generate bridge
shell: bash
run: |
set -euxo pipefail
cd rustdesk
rm -rf flutter/.dart_tool
if ! (cd flutter && flutter pub get); then
if grep -q \
'extended_text:[[:space:]]*14\.0\.0' \
flutter/pubspec.yaml; then
sed -i \
's/extended_text:[[:space:]]*14\.0\.0/extended_text: 13.0.0/g' \
flutter/pubspec.yaml
(cd flutter && flutter pub get)
else
exit 1
fi
fi
flutter_rust_bridge_codegen \
--rust-input ./src/flutter_ffi.rs \
--dart-output ./flutter/lib/generated_bridge.dart \
--c-output ./flutter/macos/Runner/bridge_generated.h
test -f ./src/bridge_generated.rs
test -f ./src/bridge_generated.io.rs
test -f ./flutter/lib/generated_bridge.dart
test -f ./flutter/lib/generated_bridge.freezed.dart
- name: Prepare bridge artifact
shell: bash
run: |
set -euxo pipefail
rm -rf bridge-artifact
mkdir -p bridge-artifact/src
mkdir -p bridge-artifact/flutter/lib
cp rustdesk/src/bridge_generated.rs \
bridge-artifact/src/
cp rustdesk/src/bridge_generated.io.rs \
bridge-artifact/src/
cp rustdesk/flutter/lib/generated_bridge.dart \
bridge-artifact/flutter/lib/
cp rustdesk/flutter/lib/generated_bridge.freezed.dart \
bridge-artifact/flutter/lib/
- name: Upload bridge
uses: https://github.com/actions/upload-artifact@v7
with:
name: rustdesk-bridge
path: bridge-artifact/
if-no-files-found: error
retention-days: 1
build-windows:
name: Build Windows x64
needs: [resolve-config, generate-bridge]
runs-on: rustdesk-windows
env:
RUSTUP_HOME: C:\BuildTools\rustup
CARGO_HOME: C:\BuildTools\cargo
PUB_CACHE: C:\BuildTools\pub-cache
VCPKG_ROOT: C:\vcpkg
steps:
- name: Download build config
uses: https://github.com/actions/download-artifact@v8
with:
name: rustdesk-build-config
path: build-config
- name: Load build config
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Get-Content ".\build-config\build-config.env" |
ForEach-Object {
if ([string]::IsNullOrWhiteSpace($_)) {
return
}
$parts = $_ -split "=", 2
$name = $parts[0]
$value = $parts[1]
[Environment]::SetEnvironmentVariable(
$name,
$value,
"Process"
)
Add-Content `
-Path $env:GITHUB_ENV `
-Value "$name=$value"
}
- name: Clone selected RustDesk tag
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Remove-Item ".\rustdesk" `
-Recurse -Force -ErrorAction SilentlyContinue
Remove-Item ".\bridge-download" `
-Recurse -Force -ErrorAction SilentlyContinue
git -c core.longpaths=true clone `
--branch "$env:RUSTDESK_VERSION" `
--depth 1 `
https://github.com/rustdesk/rustdesk.git `
rustdesk
if ($LASTEXITCODE -ne 0) {
throw "RustDesk clone failed"
}
git -C rustdesk `
-c core.longpaths=true `
submodule update --init --recursive
if ($LASTEXITCODE -ne 0) {
throw "RustDesk submodule checkout failed"
}
- name: Prepare selected Windows toolchain
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Write-Host "RustDesk: $env:RUSTDESK_VERSION"
Write-Host "Rust: $env:WINDOWS_RUST_VERSION"
Write-Host "LLVM: $env:LLVM_VERSION"
Write-Host "Flutter: $env:WINDOWS_FLUTTER_VERSION"
Write-Host "vcpkg: $env:VCPKG_COMMIT_ID"
# Rust
rustup toolchain install `
"$env:WINDOWS_RUST_VERSION" `
--profile minimal `
--component rustfmt `
--target "$env:RUST_TARGET"
if ($LASTEXITCODE -ne 0) {
throw "Rust toolchain setup failed"
}
$env:RUSTUP_TOOLCHAIN = $env:WINDOWS_RUST_VERSION
Add-Content $env:GITHUB_ENV `
"RUSTUP_TOOLCHAIN=$env:WINDOWS_RUST_VERSION"
# LLVM: reuse installed version when possible, otherwise install
# the version requested by the selected RustDesk tag.
$clang = Get-Command clang -ErrorAction SilentlyContinue
$llvmBin = $null
if ($clang) {
$firstLine = (& $clang.Source --version |
Select-Object -First 1)
if ($firstLine -match [regex]::Escape($env:LLVM_VERSION)) {
$llvmBin = Split-Path $clang.Source -Parent
}
}
if (-not $llvmBin) {
$llvmRoot = "C:\BuildTools\llvm-$env:LLVM_VERSION"
$llvmBin = "$llvmRoot\bin"
if (-not (Test-Path "$llvmBin\clang.exe")) {
$installer = (
"C:\BuildTools\downloads\" +
"LLVM-$env:LLVM_VERSION-win64.exe"
)
$url = (
"https://github.com/llvm/llvm-project/releases/download/" +
"llvmorg-$env:LLVM_VERSION/" +
"LLVM-$env:LLVM_VERSION-win64.exe"
)
Invoke-WebRequest -Uri $url -OutFile $installer
$p = Start-Process `
-FilePath $installer `
-ArgumentList @("/S", "/D=$llvmRoot") `
-Wait `
-PassThru
if ($p.ExitCode -ne 0) {
throw "LLVM installation failed"
}
}
}
if (-not (Test-Path "$llvmBin\libclang.dll")) {
throw "libclang.dll not found"
}
$env:LIBCLANG_PATH = $llvmBin
$env:Path = "$llvmBin;$env:Path"
Add-Content $env:GITHUB_ENV `
"LIBCLANG_PATH=$llvmBin"
Add-Content $env:GITHUB_PATH $llvmBin
# Flutter
$flutterRoot = (
"C:\BuildTools\flutter-" +
$env:WINDOWS_FLUTTER_VERSION
)
if (-not (Test-Path "$flutterRoot\bin\flutter.bat")) {
Remove-Item $flutterRoot `
-Recurse -Force -ErrorAction SilentlyContinue
git clone `
--branch "$env:WINDOWS_FLUTTER_VERSION" `
--depth 1 `
https://github.com/flutter/flutter.git `
$flutterRoot
if ($LASTEXITCODE -ne 0) {
throw "Flutter SDK setup failed"
}
}
git config --system --add safe.directory `
($flutterRoot -replace "\\", "/")
git -C $flutterRoot reset --hard HEAD
$env:FLUTTER_ROOT = $flutterRoot
$env:Path = "$flutterRoot\bin;$env:Path"
Add-Content $env:GITHUB_ENV `
"FLUTTER_ROOT=$flutterRoot"
Add-Content $env:GITHUB_PATH `
"$flutterRoot\bin"
& "$flutterRoot\bin\flutter.bat" config --no-analytics
& "$flutterRoot\bin\flutter.bat" config --enable-windows-desktop
& "$flutterRoot\bin\flutter.bat" precache --windows
if ($LASTEXITCODE -ne 0) {
throw "Flutter Windows precache failed"
}
# Apply every Flutter patch shipped by the selected RustDesk tag
# that cleanly applies to the selected Flutter SDK.
$patches = Get-ChildItem `
".\rustdesk\.github\patches" `
-Filter "flutter_*.diff" `
-File `
-ErrorAction SilentlyContinue
foreach ($patch in $patches) {
git -C $flutterRoot apply --check $patch.FullName 2>$null
if ($LASTEXITCODE -eq 0) {
Write-Host "Applying $($patch.Name)"
git -C $flutterRoot apply $patch.FullName
if ($LASTEXITCODE -ne 0) {
throw "Flutter patch failed: $($patch.Name)"
}
}
}
# Replace stock engine only when the selected upstream workflow
# explicitly uses RustDesk's custom Windows x64 engine.
if ($env:USE_CUSTOM_ENGINE -eq "1") {
$zip = "C:\BuildTools\downloads\rustdesk-engine.zip"
$extract = (
"C:\BuildTools\rustdesk-engine-" +
$env:WINDOWS_FLUTTER_VERSION
)
Invoke-WebRequest `
-Uri "https://github.com/rustdesk/engine/releases/download/main/windows-x64-release.zip" `
-OutFile $zip
Remove-Item $extract `
-Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory `
-Force -Path $extract | Out-Null
Expand-Archive `
-Path $zip `
-DestinationPath $extract `
-Force
$dest = Join-Path `
$flutterRoot `
"bin\cache\artifacts\engine\windows-x64-release"
Remove-Item "$dest\*" `
-Recurse -Force -ErrorAction SilentlyContinue
Copy-Item "$extract\*" "$dest\" `
-Recurse -Force
}
# vcpkg
if (-not (Test-Path "$env:VCPKG_ROOT\.git")) {
Remove-Item $env:VCPKG_ROOT `
-Recurse -Force -ErrorAction SilentlyContinue
git clone `
https://github.com/microsoft/vcpkg.git `
$env:VCPKG_ROOT
}
$current = git -C $env:VCPKG_ROOT rev-parse HEAD
if ($current -ne $env:VCPKG_COMMIT_ID) {
git -C $env:VCPKG_ROOT fetch `
origin "$env:VCPKG_COMMIT_ID"
git -C $env:VCPKG_ROOT checkout `
--force "$env:VCPKG_COMMIT_ID"
foreach ($dir in @("installed", "buildtrees", "packages")) {
Remove-Item `
(Join-Path $env:VCPKG_ROOT $dir) `
-Recurse -Force -ErrorAction SilentlyContinue
}
}
& "$env:VCPKG_ROOT\bootstrap-vcpkg.bat" -disableMetrics
if ($LASTEXITCODE -ne 0) {
throw "vcpkg bootstrap failed"
}
- name: Restore generated bridge
uses: https://github.com/actions/download-artifact@v8
with:
name: rustdesk-bridge
path: bridge-download
- name: Copy generated bridge into RustDesk
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$files = @{
"bridge-download\src\bridge_generated.rs" =
"rustdesk\src\bridge_generated.rs"
"bridge-download\src\bridge_generated.io.rs" =
"rustdesk\src\bridge_generated.io.rs"
"bridge-download\flutter\lib\generated_bridge.dart" =
"rustdesk\flutter\lib\generated_bridge.dart"
"bridge-download\flutter\lib\generated_bridge.freezed.dart" =
"rustdesk\flutter\lib\generated_bridge.freezed.dart"
}
foreach ($source in $files.Keys) {
if (-not (Test-Path $source)) {
throw "Missing bridge file: $source"
}
Copy-Item $source $files[$source] -Force
}
if (-not (Test-Path "rustdesk\flutter\windows\CMakeLists.txt")) {
throw "Selected RustDesk tag has no Flutter Windows project"
}
- name: Patch RustDesk server configuration
shell: pwsh
env:
ID_SERVER: ${{ secrets.RUSTDESK_ID_SERVER }}
PUB_KEY: ${{ secrets.RUSTDESK_KEY }}
run: |
$ErrorActionPreference = "Stop"
if ([string]::IsNullOrWhiteSpace($env:ID_SERVER)) {
throw "RUSTDESK_ID_SERVER secret is empty"
}
if ([string]::IsNullOrWhiteSpace($env:PUB_KEY)) {
throw "RUSTDESK_KEY secret is empty"
}
$pythonCode = @'
import json
import os
import re
from pathlib import Path
path = Path(r"rustdesk/libs/hbb_common/src/config.rs")
if not path.exists():
raise SystemExit(f"config.rs not found: {path}")
server = os.environ["ID_SERVER"].strip()
key = os.environ["PUB_KEY"].strip()
if not server:
raise SystemExit("RUSTDESK_ID_SERVER is empty")
if not key:
raise SystemExit("RUSTDESK_KEY is empty")
text = path.read_text(encoding="utf-8")
text, server_count = re.subn(
r"pub const RENDEZVOUS_SERVERS\s*:\s*[^=]+?="
r"\s*&\[(?:.|\n)*?\];",
"pub const RENDEZVOUS_SERVERS: &[&str] = &["
+ json.dumps(server)
+ "];",
text,
count=1,
)
text, key_count = re.subn(
r"pub const RS_PUB_KEY\s*:\s*[^=]+?=\s*.*?;",
"pub const RS_PUB_KEY: &str = "
+ json.dumps(key)
+ ";",
text,
count=1,
flags=re.S,
)
if server_count != 1:
raise SystemExit(
f"RENDEZVOUS_SERVERS replacement count: {server_count}"
)
if key_count != 1:
raise SystemExit(
f"RS_PUB_KEY replacement count: {key_count}"
)
path.write_text(text, encoding="utf-8")
print(f"ID server configured: {server}")
print("Server public key configured successfully")
print("Relay configuration untouched")
'@
$pythonCode | python -
if ($LASTEXITCODE -ne 0) {
throw "RustDesk configuration patch failed"
}
Write-Host ""
Write-Host "Checking patched RustDesk configuration..."
$config = Get-Content `
"rustdesk\libs\hbb_common\src\config.rs" `
-Raw
if ($config -notmatch "RENDEZVOUS_SERVERS") {
throw "RENDEZVOUS_SERVERS not found after patch"
}
if ($config -notmatch "RS_PUB_KEY") {
throw "RS_PUB_KEY not found after patch"
}
Write-Host "Custom ID server: OK"
Write-Host "Custom public key: OK"
Write-Host "Relay untouched: OK"
- name: Install RustDesk vcpkg dependencies
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Set-Location rustdesk
$env:VCPKG_DEFAULT_HOST_TRIPLET = $env:VCPKG_TRIPLET
& "$env:VCPKG_ROOT\vcpkg.exe" `
install `
--triplet "$env:VCPKG_TRIPLET" `
--x-install-root="$env:VCPKG_ROOT\installed"
if ($LASTEXITCODE -ne 0) {
throw "vcpkg install failed"
}
- name: Build RustDesk
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
$repo = (Resolve-Path "rustdesk").Path
$windowsCmake = Join-Path `
$repo `
"flutter\windows\CMakeLists.txt"
if (-not (Test-Path $windowsCmake)) {
git -C $repo restore `
--source=HEAD -- flutter/windows
}
if (-not (Test-Path $windowsCmake)) {
throw "flutter/windows/CMakeLists.txt is missing"
}
Push-Location (Join-Path $repo "libs\virtual_display\dylib")
try {
cargo build --locked --release
if ($LASTEXITCODE -ne 0) {
throw "virtual display build failed"
}
}
finally {
Pop-Location
}
Push-Location $repo
try {
cargo build `
--locked `
--features "hwcodec,vram,flutter" `
--lib `
--release
if ($LASTEXITCODE -ne 0) {
throw "RustDesk Rust build failed"
}
}
finally {
Pop-Location
}
$flutterDir = Join-Path $repo "flutter"
Push-Location $flutterDir
try {
flutter pub get
if ($LASTEXITCODE -ne 0) {
throw "flutter pub get failed"
}
}
finally {
Pop-Location
}
# Restore the Windows project after dependency resolution.
git -C $repo restore `
--source=HEAD -- flutter/windows
if (-not (Test-Path $windowsCmake)) {
throw "flutter/windows disappeared after pub get"
}
Push-Location $flutterDir
try {
flutter build windows --release --no-pub
if ($LASTEXITCODE -ne 0) {
throw "Flutter Windows build failed"
}
}
finally {
Pop-Location
}
$release = Join-Path `
$repo `
"flutter\build\windows\x64\runner\Release"
if (-not (Test-Path "$release\rustdesk.exe")) {
throw "rustdesk.exe was not produced"
}
$virtualDisplayDll = Join-Path `
$repo `
"target\release\deps\dylib_virtual_display.dll"
if (-not (Test-Path $virtualDisplayDll)) {
throw "dylib_virtual_display.dll was not produced"
}
Copy-Item `
$virtualDisplayDll `
"$release\dylib_virtual_display.dll" `
-Force
$packageDir = Join-Path $repo "dist\rustdesk"
Remove-Item $packageDir `
-Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory `
-Force -Path $packageDir | Out-Null
Copy-Item "$release\*" "$packageDir\" `
-Recurse -Force
- name: Build WindowInjection.dll
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Set-Location rustdesk
$source = ".\third-party\RustDeskTempTopMostWindow"
Remove-Item `
$source `
-Recurse `
-Force `
-ErrorAction SilentlyContinue
git clone `
https://github.com/rustdesk-org/RustDeskTempTopMostWindow `
$source
if ($LASTEXITCODE -ne 0) {
throw "RustDeskTempTopMostWindow clone failed"
}
if (
-not [string]::IsNullOrWhiteSpace($env:TOPMOST_COMMIT) -and
$env:TOPMOST_COMMIT -ne "HEAD"
) {
git `
-C $source `
checkout `
"$env:TOPMOST_COMMIT"
if ($LASTEXITCODE -ne 0) {
throw "RustDeskTempTopMostWindow checkout failed"
}
}
$vswhere = `
"${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
if (-not (Test-Path $vswhere)) {
throw "vswhere.exe not found"
}
$vsInfo = & $vswhere `
-latest `
-products * `
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
-format json |
ConvertFrom-Json
if (-not $vsInfo) {
throw "Visual Studio C++ Build Tools not found"
}
$vsPath = $vsInfo[0].installationPath
$vsVersion = $vsInfo[0].installationVersion
Write-Host "Visual Studio:"
Write-Host " Path: $vsPath"
Write-Host " Version: $vsVersion"
$vsMajor = [int]($vsVersion.Split(".")[0])
$platformToolset = switch ($vsMajor) {
17 { "v143" }
16 { "v142" }
15 { "v141" }
default {
throw "Unsupported Visual Studio major version: $vsMajor"
}
}
Write-Host "PlatformToolset: $platformToolset"
$msbuild = & $vswhere `
-latest `
-products * `
-requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
-find "MSBuild\**\Bin\MSBuild.exe" |
Select-Object -First 1
if (-not $msbuild) {
throw "MSBuild.exe not found"
}
Write-Host "MSBuild: $msbuild"
& $msbuild `
"$source\WindowInjection\WindowInjection.vcxproj" `
"-p:Configuration=Release" `
"-p:Platform=x64" `
"-p:PlatformToolset=$platformToolset" `
"/p:TargetVersion=Windows10"
if ($LASTEXITCODE -ne 0) {
throw "WindowInjection.dll build failed"
}
$dll = `
"$source\WindowInjection\x64\Release\WindowInjection.dll"
if (-not (Test-Path $dll)) {
throw "WindowInjection.dll not found: $dll"
}
Copy-Item `
$dll `
".\dist\rustdesk\WindowInjection.dll" `
-Force
Write-Host ""
Write-Host "WindowInjection.dll built successfully"
Write-Host "PlatformToolset: $platformToolset"
- name: Add usbmmidd
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Set-Location rustdesk
$zip = ".\third-party\usbmmidd_v2.zip"
$extract = ".\third-party\usbmmidd"
Remove-Item $extract `
-Recurse -Force -ErrorAction SilentlyContinue
Invoke-WebRequest `
-Uri "https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip" `
-OutFile $zip
Expand-Archive `
-Path $zip `
-DestinationPath $extract `
-Force
$usb = Join-Path $extract "usbmmidd_v2"
Remove-Item "$usb\Win32" `
-Recurse -Force -ErrorAction SilentlyContinue
foreach ($file in @(
"deviceinstaller64.exe",
"deviceinstaller.exe",
"usbmmidd.bat"
)) {
Remove-Item `
(Join-Path $usb $file) `
-Force `
-ErrorAction SilentlyContinue
}
Copy-Item $usb `
".\dist\rustdesk\usbmmidd_v2" `
-Recurse -Force
- name: Build portable executable
shell: pwsh
run: |
$ErrorActionPreference = "Stop"
Set-Location rustdesk
$runnerRes = Get-ChildItem `
".\flutter\build\windows\x64" `
-Filter "Runner.res" `
-Recurse `
-ErrorAction SilentlyContinue |
Select-Object -First 1
if ($runnerRes) {
Copy-Item $runnerRes.FullName `
".\libs\portable\Runner.res" `
-Force
}
$manifest = ".\res\manifest.xml"
Get-Content $manifest |
Where-Object { $_ -notmatch "dpiAware" } |
Set-Content $manifest -Encoding utf8
Push-Location ".\libs\portable"
try {
python -m pip install `
--disable-pip-version-check `
-r requirements.txt
if ($LASTEXITCODE -ne 0) {
throw "portable requirements installation failed"
}
python `
.\generate.py `
-f ..\..\dist\rustdesk\ `
-o . `
-e ..\..\dist\rustdesk\rustdesk.exe
if ($LASTEXITCODE -ne 0) {
throw "portable packer generation failed"
}
}
finally {
Pop-Location
}
$packer = ".\target\release\rustdesk-portable-packer.exe"
if (-not (Test-Path $packer)) {
throw "rustdesk-portable-packer.exe not found"
}
$outputName = (
"rustdesk-" +
$env:RUSTDESK_VERSION +
"-custom-windows-x86_64.exe"
)
$output = Join-Path ".\dist" $outputName
Copy-Item $packer $output -Force
$hash = Get-FileHash $output -Algorithm SHA256
(
$hash.Hash.ToLower() +
" " +
$outputName
) | Set-Content "$output.sha256" -Encoding ASCII
- name: Upload Windows build
uses: https://github.com/actions/upload-artifact@v7
with:
name: rustdesk-windows-x86_64-${{ env.RUSTDESK_VERSION }}
path: |
rustdesk/dist/rustdesk-*-custom-windows-x86_64.exe
rustdesk/dist/rustdesk-*-custom-windows-x86_64.exe.sha256
rustdesk/dist/rustdesk/
if-no-files-found: error
retention-days: 14