Files
chanora/docs/release/windows-build.md
T
EdisonJwa 8094ec7277 docs(release): add Windows build instructions + PowerShell helper
The development host is Linux x86_64; `flutter build windows` cannot
be cross-compiled and requires a Windows host with Visual Studio
2022's C++ Desktop workload. This commit adds the instructions for
producing the Windows v0.2.0-beta.1 Internal Beta build on an Azure
VM, plus a PowerShell helper that automates the build itself.

docs/release/windows-build.md (v0.1.0):
  - Toolchain pin table (Windows Server 2022, VS 2022 Build Tools
    + C++ workload, Flutter 3.41.9, Rust 1.95 stable, FRB 2.12.0,
    CMake, audiopus build dependency).
  - Azure VM provisioning recipe: Standard_D4s_v5 (4 vCPU / 16 GiB),
    Premium SSD 128 GiB, RDP locked to caller IP, auto-shutdown,
    cost estimate (<USD 1 per build session).
  - Step-by-step PowerShell to install VS 2022 Build Tools with the
    required components, Git for Windows, rustup, Flutter SDK,
    flutter_rust_bridge_codegen, and CMake.
  - Two upload paths for source: temporary git remote OR zip archive
    over RDP clipboard.
  - flutter create --platforms=windows to scaffold the
    windows/ platform folder (the product Flutter app was created
    with only linux + android).
  - cargo build -p chanora_bridge to produce chanora_bridge.dll.
  - flutter build windows --release to produce chanora_flutter.exe
    and the bundle.
  - Drop the DLL next to the EXE so dart:ffi loads it.
  - Smoke-test instructions including the cn.teamspeak.app UDP 9987
    egress gotcha for some Azure regions.
  - Packaging into chanora-v0.2.0-beta.1-windows-x64.zip.
  - Known-issue / caveat table.
  - Reproducibility note (build is not bit-reproducible in this Beta).

tools/build-windows.ps1:
  - Parameter switches: -SkipRustBuild, -RegenerateBindings, -Version.
  - Verifies flutter, cargo, rustc, cmake, git on PATH.
  - Adds the x86_64-pc-windows-msvc target via rustup if missing.
  - Runs flutter create --platforms=windows if the windows/ folder
    is absent in apps/chanora_flutter/.
  - Optionally regenerates FRB bindings.
  - cargo build --release -p chanora_bridge --target x86_64-pc-windows-msvc.
  - flutter pub get + flutter build windows --release.
  - Copies the DLL into the Release bundle.
  - Compress-Archive into chanora-<version>-windows-x64.zip.
  - Prints final artefact paths.

This is documentation + helper only; no actual Windows binaries are
produced by this commit. To produce the binaries, follow §3-§13 of
docs/release/windows-build.md on a Windows host.
2026-05-14 23:02:56 +08:00

17 KiB
Raw Blame History

Building Chanora v0.2.0-beta.1 on Windows via Azure VM

Document type: Release / Platform Build Instructions Version: 0.1.0 Status: Draft Language: English Product: Chanora Repo path: docs/release/windows-build.md


1. Purpose

This document gives exact step-by-step instructions for building the Chanora v0.2.0-beta.1 Internal Beta on a Windows host, using an Azure Virtual Machine. It exists because the development host is Linux; flutter build windows requires a Windows host with Visual Studio 2022 and cannot be cross-compiled.

After following this doc you will have:

  • chanora_flutter.exe — the Windows desktop binary.
  • chanora_bridge.dll — the Rust cdylib loaded by the .exe via FFI.
  • A complete release bundle directory the app needs at runtime.

The doc assumes you have:

  • An Azure subscription with permission to create VMs.
  • An RDP client (Windows: built-in; macOS: Microsoft Remote Desktop; Linux: remmina or rdesktop).
  • The Chanora source code locally (this repository).

2. Toolchain versions pinned for this build

Tool Version Why
Windows Server 2022 Datacenter LTS, plenty of Azure images, ships PowerShell 5.1 + Server Core APIs
Visual Studio 2022 Build Tools (Community works too) Required by flutter build windows; provides MSVC, Windows SDK, CMake, link.exe
Visual Studio workload "Desktop development with C++" Provides MSVC v143, Windows 10/11 SDK, CMake tools, C++ ATL
Flutter SDK 3.41.9 stable Matches the Linux/Beta build; bridge codegen is version-sensitive
Dart SDK 3.11.5 Comes with Flutter 3.41.9
Rust toolchain stable 1.95 (or newer) Workspace rust-version = "1.95"
Rust target x86_64-pc-windows-msvc Native Windows ABI; produces MSVC-compatible .dll
cargo-ndk N/A Not needed for Windows; only Android needs it
Opus library bundled via audiopus_sys build script + cmake On Windows there is no system libopus by default; we build it from source
Git for Windows latest Convenient git + the bundled Bash for running flutter if needed
7-Zip (optional) latest Convenient for unpacking the source bundle if you uploaded it as zip

3. Azure VM provisioning

Setting Value Rationale
Image Windows Server 2022 Datacenter — x64 Gen2 Most common LTS Windows image
Size Standard_D4s_v5 (4 vCPU, 16 GiB) or larger The Cargo cold build pulls hundreds of crates; 4 cores keeps the build under 30 minutes
OS disk Premium SSD 128 GiB Default 128 GiB is enough for VS 2022 (~10 GiB), Flutter SDK (~2 GiB), Rust toolchain (~1 GiB), source + build artefacts (~15 GiB)
Auth Password (you'll RDP in) Sufficient for a short-lived build VM
Inbound port rules Allow RDP (3389) only from your IP Lock RDP to your IP via NSG; never open to 0.0.0.0/0
Networking New VNet + public IP Standard for an ad-hoc build host
Auto-shutdown Enable, 19:00 local time Stops you forgetting and burning hours

3.2 Estimated cost

Standard_D4s_v5 in West US 2 is about USD $0.20/hour for the compute plus ~USD $0.01/hour for the disk. A first cold build (provision → install everything → compile → archive) is typically 23 hours. Total: under USD $1 per build session if you deallocate after.

Cost gotcha: Stopped (deallocated) VMs do not bill for compute; Stopped (in the OS shutdown sense, but not deallocated in Azure) still bills compute. Always check the Azure portal shows the VM as Stopped (deallocated).

3.3 Provisioning checklist

  1. Azure Portal → Create a resourceWindows Server 2022 Datacenter (x64 Gen2).
  2. Choose region near you.
  3. Size: Standard_D4s_v5.
  4. Administrator account: pick a username (e.g. chanora) + a strong password.
  5. Inbound ports: RDP only, restricted to your public IP.
  6. Disks: keep Premium SSD 128 GiB.
  7. Networking: defaults; ensure auto-assign public IP.
  8. Management → Auto-shutdown: On, time = end of your work day, notification = email.
  9. Review + create.

3.4 First RDP login

  1. Get the VM's public IP from the Azure portal.
  2. RDP in as chanora / your password.
  3. (Optional) Open Server Manager → Local Server → IE Enhanced Security Configuration → turn Off for Administrators so the downloads in §4 don't get blocked.

4. Install the toolchain (one-time per VM)

Run all of these in an elevated PowerShell (right-click PowerShell → Run as Administrator).

4.1 Visual Studio 2022 Build Tools + workload

# Download the VS 2022 Build Tools bootstrapper
Invoke-WebRequest -Uri 'https://aka.ms/vs/17/release/vs_buildtools.exe' `
                  -OutFile "$env:TEMP\vs_buildtools.exe"

# Install with the C++ desktop workload (this is what Flutter requires).
# --quiet suppresses UI; --wait blocks until done; takes 10-15 minutes.
& "$env:TEMP\vs_buildtools.exe" --quiet --wait --norestart `
    --add Microsoft.VisualStudio.Workload.VCTools `
    --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 `
    --add Microsoft.VisualStudio.Component.Windows11SDK.22621 `
    --add Microsoft.VisualStudio.Component.VC.CMake.Project `
    --add Microsoft.VisualStudio.Component.VC.ATL `
    --includeRecommended

When this completes, reboot the VM (Visual Studio Build Tools needs it for environment variables).

4.2 Git for Windows

winget install --id Git.Git --silent --accept-source-agreements --accept-package-agreements

4.3 Rust (stable, with the MSVC target)

# Download rustup-init for Windows.
Invoke-WebRequest -Uri 'https://win.rustup.rs/x86_64' `
                  -OutFile "$env:TEMP\rustup-init.exe"

# Install the default toolchain (stable-x86_64-pc-windows-msvc).
& "$env:TEMP\rustup-init.exe" -y --default-toolchain stable --profile minimal

# Open a NEW PowerShell so PATH picks up cargo.
# Then verify:
cargo --version
rustc --version

Expected output: cargo 1.95.0 (or newer), rustc 1.95.0. The default target on Windows is x86_64-pc-windows-msvc — this is what we want.

4.4 Flutter SDK (pinned to 3.41.9 stable)

# Download Flutter SDK
$flutter = 'https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_3.41.9-stable.zip'
Invoke-WebRequest -Uri $flutter -OutFile "$env:TEMP\flutter.zip"
Expand-Archive "$env:TEMP\flutter.zip" -DestinationPath 'C:\'

# Add to PATH for the current user (persists across sessions).
[Environment]::SetEnvironmentVariable(
    'Path',
    [Environment]::GetEnvironmentVariable('Path', 'User') + ';C:\flutter\bin',
    'User'
)

# Open a NEW PowerShell so PATH applies, then:
flutter --version
flutter doctor

flutter doctor should show green on:

  • ✓ Flutter (Channel stable, 3.41.9, on Microsoft Windows …)
  • ✓ Windows Version (Windows … 10.0.20348 or later)
  • ✓ Visual Studio - develop Windows apps (Visual Studio Build Tools 2022 …)

Yellow on Android Studio / Chrome is fine — we're only building Windows.

4.5 flutter_rust_bridge_codegen and Dart deps

cargo install flutter_rust_bridge_codegen --version "=2.12.0"

Takes ~5 minutes (compiles flutter_rust_bridge_codegen from source).

4.6 Opus build dependency

The audiopus Rust crate wraps the C Opus library. On Windows there is no system Opus, so the audiopus_sys build script will attempt to build Opus from source via CMake (which the VS workload already provided). No extra action is required — but verify CMake is on PATH:

cmake --version

Expected: cmake version 3.x (any 3.x ≥ 3.18 is fine).

If CMake is not found, install it explicitly:

winget install --id Kitware.CMake --silent

5. Get the source onto the VM

Two options. Pick whichever is easier for you.

Option A — Push the repo to a temporary git remote

On the Linux host where the repo lives:

# E.g. create a private GitHub repo and push:
git remote add origin https://github.com/<your-user>/chanora.git
git push --all
git push --tags

Then on the Windows VM:

cd C:\
git clone https://github.com/<your-user>/chanora.git
cd chanora
git checkout v0.2.0-beta.1

Option B — Upload the source as a zip via RDP clipboard

On Linux:

cd /home/milkice
git -C chanora archive --format=zip --output=/tmp/chanora-v0.2.0-beta.1.zip v0.2.0-beta.1

Copy /tmp/chanora-v0.2.0-beta.1.zip into the RDP session (clipboard or shared drive), unzip into C:\chanora\.

Either way, you end up with the working tree at C:\chanora\, checked out at the v0.2.0-beta.1 tag.


6. Add the Windows platform to the Flutter app

The product Flutter app was created with --platforms=linux,android, so the windows/ platform folder does not yet exist. Add it once on the build VM:

cd C:\chanora\apps\chanora_flutter
flutter create --platforms=windows .

This creates apps/chanora_flutter/windows/ containing:

windows/
  CMakeLists.txt
  flutter/
    CMakeLists.txt
    generated_plugin_registrant.cc
    ...
  runner/
    main.cpp
    Runner.rc
    chanora_flutter.exe.manifest
    ...

Important: Do not commit this windows/ folder back to the repo from the VM unless you also do the corresponding edits the source-of-truth host uses (icon, manifest, etc.). For Beta it is fine to keep it VM-only.


7. Build the Rust cdylib for Windows

cd C:\chanora
cargo build --release -p chanora_bridge

This builds the workspace, including:

  • The whole tsclientlib git dependency tree (slow first time — expect ~510 minutes for the first compile of audiopus_sys + tsproto etc.).
  • chanora_bridge as a cdylib + staticlib + rlib.

Expected output location:

C:\chanora\target\release\chanora_bridge.dll

(Note: no lib prefix on Windows MSVC.)

Verify:

Get-Item C:\chanora\target\release\chanora_bridge.dll | Format-List Name, Length, LastWriteTime

The DLL is typically ~1618 MiB.


8. Regenerate the FRB bindings (optional — only if you changed the bridge API)

The Linux build already produced lib/src/rust/*.dart and crates/chanora_bridge/src/frb_generated.rs. The bindings are platform-agnostic Dart + Rust source, so they do not need regenerating on Windows. Skip §8 unless you modified crates/chanora_bridge/src/api.rs after v0.2.0-beta.1.

If you do need to regenerate:

cd C:\chanora
flutter_rust_bridge_codegen generate

Takes ~510 minutes the first time on Windows.


9. Build the Flutter Windows binary

cd C:\chanora\apps\chanora_flutter
flutter pub get
flutter build windows --release

flutter build windows:

  1. Invokes CMake on apps/chanora_flutter/windows/.
  2. Builds chanora_flutter.exe via MSVC.
  3. Bundles the Flutter engine DLL (flutter_windows.dll), ICU data, Dart-AOT-compiled app.so (delivered as data\app.so), the Flutter data\ directory, and platform-specific resources.

Build time: ~35 minutes on Standard_D4s_v5 once dependencies are cached.

Expected output location:

C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\

Contents:

File Size (approx) Notes
chanora_flutter.exe ~10 MiB The launcher .exe
flutter_windows.dll ~17 MiB Flutter engine
data\icudtl.dat ~10 MiB Unicode tables
data\app.so varies AOT-compiled Dart code
data\flutter_assets\ varies Images, fonts, ARB-derived .json

10. Add the Rust DLL to the bundle

The Flutter app loads chanora_bridge.dll at runtime via dart:ffi. Drop the DLL next to the .exe (the same directory):

$src = 'C:\chanora\target\release\chanora_bridge.dll'
$dst = 'C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\'
Copy-Item $src $dst -Force

Verify everything is in place:

Get-ChildItem $dst -Recurse | Select-Object FullName, Length |
    Format-Table -AutoSize

You should see:

C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\chanora_flutter.exe
C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\chanora_bridge.dll
C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\flutter_windows.dll
C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\data\app.so
C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\data\icudtl.dat
C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\data\flutter_assets\...

11. Smoke test on the VM

Double-click chanora_flutter.exe (or & '...\chanora_flutter.exe' in PowerShell). The Beta UI should appear:

  • Banner: "Beta build — voice in/out wired; not production ready."
  • Form: cn.teamspeak.app + ChanoraBeta pre-populated.
  • Connect button.

Press Connect → after a few seconds you should see the channel tree of cn.teamspeak.app (Vigorous Pro). Press Start audio → PTT button appears. Hold it to transmit (a Windows mic permission prompt may appear).

Network gotcha: Some Azure regions block UDP 9987 outbound by default. If Connect times out, check the VM's NSG (outbound rules) and the regional firewall.


12. Package the release artefact

$src = 'C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release'
$out = 'C:\chanora-v0.2.0-beta.1-windows-x64.zip'
Compress-Archive -Path "$src\*" -DestinationPath $out -Force
Get-Item $out | Format-List Name, Length

Expected size: ~5080 MiB.


13. Download to your local host

From your local machine (Linux/macOS/Windows):

# Use Azure CLI to copy via SAS, or just RDP the file out.
# Simplest: in the RDP session enable clipboard file transfer
# (mstsc /control or Remmina's "share local folder"), then drag the
# zip out.

Or use Azure Blob Storage if you want versioned hosting.


14. Final artefact paths (what you actually produce)

Inside the VM, after a successful build:

Artefact Path on the VM
Bridge DLL C:\chanora\target\release\chanora_bridge.dll
Flutter EXE C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\chanora_flutter.exe
Complete runtime bundle C:\chanora\apps\chanora_flutter\build\windows\x64\runner\Release\
Release zip C:\chanora-v0.2.0-beta.1-windows-x64.zip

15. After the build — deallocate the VM

# In the Azure CLI on your local host, OR via the portal:
az vm deallocate --resource-group <rg> --name <vm-name>

Verify the portal says Stopped (deallocated).


16. Known issues and caveats

Issue Workaround
audiopus_sys build fails with "cmake not found" Re-run §4.6's winget install Kitware.CMake and open a new PowerShell.
flutter build windows complains about Long Paths Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name LongPathsEnabled -Value 1, then reboot.
Microsoft Defender quarantines chanora_bridge.dll Add C:\chanora\target\release\ to Defender exclusions before the cargo build.
The build VM cannot reach cn.teamspeak.app on UDP 9987 Confirm Azure regional firewall allows outbound UDP. The Linux dev host's verification doesn't translate to Azure VMs automatically.
First cargo build takes > 30 minutes Normal. Subsequent builds reuse target/ and are ~1 minute.
flutter pub get fails behind a corporate proxy Set HTTPS_PROXY and HTTP_PROXY environment variables before running.
The windows/ folder created by flutter create is missing icons Replace windows\runner\resources\app_icon.ico with a Chanora icon. The default Flutter icon ships otherwise. Cosmetic only for Beta.

17. Reproducibility note

This build process is not bit-reproducible on Windows in the current state:

  • The audiopus_sys build script picks the CMake-discovered MSVC toolchain, which embeds its version into the DLL.
  • Dart AOT compilation embeds a Dart kernel hash.
  • Windows resource compilation embeds a build timestamp.

If true reproducibility is required for a future External Beta or MVP Public release, that is Beta+ work; the build above is sufficient for an Internal Beta milestone per DEC-001.


18. Change History

Version Date Description
0.1.0 2026-05-14 Initial Windows build instructions for Chanora v0.2.0-beta.1. Targets Azure VM Standard_D4s_v5 running Windows Server 2022, Visual Studio 2022 Build Tools with the C++ desktop workload, Rust 1.95 stable (x86_64-pc-windows-msvc), Flutter 3.41.9 stable, flutter_rust_bridge 2.12.0. Produces chanora_flutter.exe + chanora_bridge.dll packaged into chanora-v0.2.0-beta.1-windows-x64.zip.