First-class Rust bindings for Avalonia, projected
over a nano-COM ABI served by a NativeAOT host. This repository contains the
complete bindings effort; the Avalonia framework itself is consumed from the
pinned avalonia-src producer submodule at upstream Avalonia 12.1.6 (commit
cf8e564674700348947e93ab19105f27afe859a9).
| Directory | Contents |
|---|---|
avalonia-src/ |
Avalonia producer pinned to the upstream 12.1.6 tag (cf8e564674700348947e93ab19105f27afe859a9), cloned from AvaloniaUI/Avalonia |
avalonia-patches/ |
Additive framework patches applied onto the pinned checkout (see its README + UPSTREAM.md) |
rust/ |
The Rust workspace: rustolonia (safe bindings), rustolonia-macros (rsx!, #[component], #[derive(Lens)], color!, tracks!, fmt!), rustolonia-sys (ABI bindings), rustolonia-bindgen (IR to Rust generator), rustolonia-apk (Cargo-only Android APK packager), avalonia-sample (flagship sample's application-owned view-model API), templates, build scripts, and the checked-in IR |
host/ |
Avalonia.Host - the C# NativeAOT host that serves the ABI, plus its generated object model |
projection/ |
The projection pipeline: IR extraction, C#/header emitters, and the generator tools |
interop/ |
Avalonia.Rust and Avalonia.Rust.Interop - the managed-side view-model interop layer |
apps/system-monitor/ |
NeoHtop, a real Rust-owned system monitor with compiled AXAML presentation and a packaged NativeAOT host |
apps/pdf-viewer/ |
A PDF Oxide-powered sample viewer with rendered page navigation and extracted text |
apps/hash-calculator/ |
A streaming checksum utility (MD5, SHA-1, SHA-256, SHA-512, BLAKE3) with compare and copy |
apps/archive-tool/ |
A dual-pane archive manager (zip/tar/7z/cab and compressed tars) |
apps/android-hello/ |
A code-first app that runs as an Android APK and on the desktop from one UI module (see rust/PLATFORMS.md) |
templates/ |
Copy-out standalone app skeletons using the published bindings and prebuilt host |
tests/ |
Host, IR, and generator test suites |
samples/ |
RustViewModelSample.Managed - the sample presentation project the host consumes |
build/ |
Vendored MSBuild configuration (versioning, signing, analyzers, xunit) |
Code-first applications using the default shared host need only Cargo; no .NET SDK or source checkout:
[dependencies]
rustolonia = { git = "https://github.com/Devolutions/rustolonia", tag = "v12.1.0" }Use the final v12.1.0 tag once its GitHub release is published.
Cargo finds the crate in the rust/ workspace and
resolves rustolonia-sys from the same git revision; no crates.io publication
or [patch.crates-io] is needed. Rust 1.88 or newer is required. Version
12.1.0 is the first Rustolonia release, backed by Avalonia 12.1.3.
The major/minor identify the Avalonia line; the patch counts Rustolonia
releases independently and does not identify the upstream patch.
This checkout prepares Rustolonia 12.1.6 against Avalonia 12.1.6; the
matching patch numbers are coincidental. Applications using this checkout need
a locally built host until the matching release artifacts and checksums are
published.
On the first build, rustolonia-sys downloads the prebuilt NativeAOT host for
your target (Windows, macOS and Linux glibc, x64 and arm64) from the matching
GitHub release, verifies
its SHA-256, and caches it. See rust/rustolonia/README.md
for a hello-world and how to ship the host with your application, and
rust/rustolonia-sys/README.md for offline,
mirrored and locally built hosts.
For a fully static Linux X11 executable, releases containing the separate
musl hosts support the static-host feature and a matching musl Rust
toolchain; see fully static Linux builds.
Existing releases do not yet include these assets. Static hosts on macOS and
Windows still depend on operating-system libraries.
Applications with compiled AXAML and Rust view-models still build their own host from a source checkout, as described below.
Experimental embedded Linux support selects direct DRM/KMS with the Cargo
feature linux-drm, using separate prebuilt hosts in releases containing this
feature. Existing releases do not include DRM assets. Source builds use
-LinuxBackend Drm.
It renders one fullscreen view directly through DRM/KMS without X11; see
embedded Linux setup.
Code-first apps for iOS, Android and the browser can also be built without
.NET tooling, from prebuilt hosts published with releases from the first one
that includes them, each verified against host-checksums.txt:
| Platform | Prebuilt host | Tools needed | Start from |
|---|---|---|---|
| iOS (experimental) | rustolonia-host-<v>-ios*.tar.gz (NativeAOT objects) |
Rust, Xcode | samples/ios-standalone |
| Android | rustolonia-host-<v>-android.apk |
Rust, Android NDK | cargo rustolonia-apk (rust/PLATFORMS.md) |
| Browser | rustolonia-host-<v>-browser-wasm.tar.gz (relink kit) |
Rust, Emscripten SDK 3.1.56 | samples/browser-standalone |
None of these use the desktop host discovery mechanism. The
source-built iOS sample, rust/build-android.ps1
and rust/build-browser.ps1 build the hosts locally instead.
For standalone starting points, see the app templates: code-first apps use a released host, while the Rust-only AXAML template currently needs this Rustolonia source revision.
After the crates are published to crates.io, rustolonia = "=12.1.0" is an
alternative to the git dependency.
git clone --recurse-submodules https://github.com/Devolutions/rustolonia
cd rustolonia
pwsh ./avalonia-patches/apply-avalonia-patches.ps1 -AvaloniaRoot ./avalonia-src
pwsh ./rust/regenerate-and-build.ps1 -Configuration ReleaseThe regeneration pipeline (IR, generated C#, native header, Rust bindings, and
the standalone AXAML template's projection catalog) is deterministic; CI fails
if regenerating changes the checkout. Generated outputs have checked-in
ownership manifests so stale cleanup does not erase another generator's files.
Generator CLIs also provide non-mutating --check modes.
Open Rustolonia.slnx for the managed projects. See
CONTRIBUTING.md for the contributor workflow and code-generation
boundaries.
For a standalone code-first app, copy one of the code-first
root templates/ outside this repository and run
cargo run --locked from the copied directory. They need no .NET SDK or local
source checkout.
For AXAML authoring without .NET, start from the Rust-only AXAML template. It transpiles supported markup to Rust during Cargo builds and uses a matching prebuilt host; it is not full Avalonia AXAML compatibility. Until a release includes the new APIs, the template must point to a checkout of this Rustolonia revision as described in its README. Neither the app build nor the checkout requires a .NET SDK.
For compiled AXAML and generated Rust view-models, use the source-build scaffold:
pwsh ./rust/new-app.ps1 -Name my_app -Destination ../my_app -ProducerRoot ./avalonia-src -RustoloniaRoot .
pwsh ./rust/build-app.ps1 -ProducerRoot ./avalonia-src -Manifest ../my_app/avalonia-app.json -UpdateLockFileThe generated app keeps the producer root and Rustolonia root separate, allows
paths with spaces, and validates the declared roots before writing any files.
References are relative when the checkouts share a volume; the manifest defaults
to the current OS/architecture and global.json pins the supported SDK policy.
Commit Cargo.lock after the first build and omit -UpdateLockFile thereafter.
Normal builds require matching producer revisions/applied patches and initialized
submodules, run Cargo locked, and never format handwritten Rust.
The in-repository system monitor uses the same consumer path without a vendored checkout:
pwsh ./apps/system-monitor/build.ps1.github/workflows/avalonia-rust.yml keeps the native release and cross-build
gates running automatically on pull requests and pushes to master. Native
execution covers Windows/Linux x64 and macOS x64/arm64; Windows/Linux arm64
have cross-build packaging coverage, not native execution coverage. The
original flagship samples remain part of the release gate.
Pull requests run a fast tier; a newer push cancels the in-flight PR run.
Pushes to master and manual runs add the Windows/macOS external-consumer
builds, the system monitor, the packaged sample bundles, the source-integrated
iOS simulator sample, and the unsigned iOS device build. On pull requests the
iOS job builds the packaged simulator host and runs the Rust-only consumer
against it.
Artifacts are named avalonia-rust-native-<rid> for native jobs and
avalonia-rust-cross-<rid> for cross-build jobs, so their provenance remains
unambiguous when both jobs target the same RID.
The quick helper/scaffold suite does not build or launch an application:
pwsh ./rust/tests/test-build-app.ps1Native jobs additionally build and launch a fresh external consumer (Linux on every run; Windows and macOS outside pull requests):
pwsh ./rust/tests/test-build-app.ps1 -RunNativeSmokeLinux native smoke execution needs a display, for example
xvfb-run -a pwsh ./rust/tests/test-build-app.ps1 -RunNativeSmoke.
Native jobs also archive their host as a release tarball and build and launch
a standalone app that depends on the packaged crates through the
rustolonia-sys download path (rust/tests/test-standalone-app.ps1). .github/workflows/release.yml builds
the release host tarballs from master into staged Actions artifacts, publishes
a non-draft GitHub release on the checksum-bearing v* tag by default
(draft=true opts into a draft), and optionally publishes
the crates; see
rust/PRODUCTIZATION.md.