Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ pinned `avalonia-src` producer submodule at upstream Avalonia `12.1.3` (commit
| `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) |
| `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) |
Expand Down Expand Up @@ -52,6 +53,10 @@ mirrored and locally built hosts.
Applications with compiled AXAML and Rust view-models still build their own
host from a source checkout, as described below.

For complete standalone starting points using the release, see the
[app templates](templates/README.md): minimal window, input form, and
multi-window workspace.

After the crates are published to crates.io, `rustolonia = "=12.1.0"` is an
alternative to the git dependency.

Expand All @@ -75,6 +80,14 @@ boundaries.

## Creating a new app

For a standalone code-first app using the latest published release, copy
one of the [root `templates/`](templates/README.md)
outside this repository and run `cargo run --locked` from the copied directory.
Each includes an independent workspace and pinned release dependency, with no
.NET SDK or local source-checkout requirements.

For compiled AXAML and generated Rust view-models, use the source-build scaffold:

```pwsh
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 -UpdateLockFile
Expand Down
4 changes: 4 additions & 0 deletions rust/templates/avalonia-app/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Avalonia Rust external consumer

For a code-first app using the prebuilt GitHub release with no .NET SDK or
source-checkout dependencies, use the
[root standalone templates](../../../templates/README.md) instead.

Two source checkouts are required: Rustolonia (Rust crates, interop, projection
tool and NativeAOT host) and its pinned Avalonia producer (framework and XAML
compiler). The producer normally lives at `avalonia-src` inside Rustolonia.
Expand Down
103 changes: 103 additions & 0 deletions templates/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Standalone app templates

Copy one of these directories into a new project and start building. Every
template is an independent Cargo workspace using the published Rustolonia
bindings and prebuilt NativeAOT host, not this repository's source build.

| Template | Starting point | Structure |
| --- | --- | --- |
| [minimal](minimal/README.md) | One window, a label, and a button callback | `main.rs` bootstrap, `ui.rs` composition |
| [form](form/README.md) | Text input, validation, Submit and Clear actions | `main.rs`, `ui.rs`, UI-independent `model.rs` |
| [multi-window](multi-window/README.md) | Main workspace opening independent text-preview windows | `main.rs`, `ui.rs`, `ui/preview.rs` |

All three pin **v12.1.0**, the latest stable release when prepared. Tags and
lockfiles are deliberate: a moving `master` dependency could mismatch the
released host. There are no placeholders to substitute, local path
dependencies, registry patches, AXAML compilation, or generation steps.

## Copy and run

Install Rust 1.88 or newer and the native linker toolchain for your platform.
No .NET SDK or initialized Avalonia producer checkout is needed. Cargo may
fetch the tagged source's submodules, but the templates never build them.

From the repository root, choose `minimal`, `form`, or `multi-window`:

```powershell
$template = 'minimal'
$destination = Join-Path $HOME 'my-rustolonia-app'
if (Test-Path -LiteralPath $destination) { throw "Destination already exists: $destination" }
New-Item -ItemType Directory -Path $destination | Out-Null
Get-ChildItem -LiteralPath (Join-Path .\templates $template) -Force |
Where-Object Name -ne 'target' |
Copy-Item -Destination $destination -Recurse
Set-Location $destination
cargo run --locked
```

On macOS/Linux, copying the directory with `cp -R` preserves its dotfiles;
remove any copied `target` directory before starting your own project.
Keep `.cargo/config.toml`, `.gitignore`, and `Cargo.lock` alongside the sources.
No sibling template or repository file is required by a copied app.

You can also try a template in place:

```powershell
cd templates\minimal
cargo run --locked
```

Run Cargo from the template directory, not from the repository root using
`--manifest-path`: Cargo discovers configuration from its working directory.
Each template overrides the source checkout's host-download opt-out.
Explicit environment variables still win; unset `RUSTOLONIA_NO_DOWNLOAD`,
`RUSTOLONIA_HOST_DIR`, `RUSTOLONIA_HOST_LIB`, `RUSTOLONIA_HOST_BASE_URL`, and
`RUSTOLONIA_HOST_CHECKSUMS` if you previously selected a local host or mirror.

The first build downloads the release host for your platform, checks its
SHA-256 against the checksum embedded in the tagged bindings, and caches it.
The default `dev-host-path` feature finds that cache when the app starts.

## Customize

Rename the package and update its description in `Cargo.toml`, then change
the window title and UI in `src/ui.rs`. `main.rs` only bootstraps the runtime.
Keep business logic in separate modules, as illustrated by `form/src/model.rs`.
Register UI subscriptions through `AppScope` to retain them for the app lifetime.
Startup errors propagate from `main`; callbacks report runtime failures to stderr.

After renaming the package, run `cargo build` to refresh `Cargo.lock`, then
commit it in your new app's repository. Normal builds should use `--locked`.

```powershell
cargo fmt
cargo clippy --locked -- -D warnings
cargo build --release --locked
```

To update Rustolonia, consult
[the latest release](https://github.com/Devolutions/rustolonia/releases/latest),
change the exact `tag` in `Cargo.toml`, run `cargo update -p rustolonia`, and
commit the manifest and lockfile together. Do not move an existing release tag
or mix bindings with a host from a different version.

## Platforms and shipping

Release hosts support Windows, macOS, and Linux (glibc), on x64 and arm64.
Linux needs X11/XWayland and fontconfig. See the
[platform requirements](https://github.com/Devolutions/rustolonia/blob/v12.1.0/rust/PLATFORMS.md#prebuilt-host-platform-floors).
Build on the target platform with its native Rust toolchain.

These are development skeletons, not installer projects. A release-profile
build still embeds the development cache location by default and is **not**
portable on its own. For distribution, disable the dependency's default
features, rebuild, and ship the matching extracted release host, native
dependencies, and notices beside the executable (or in `../Frameworks` inside
a macOS bundle). Follow the
[host distribution guide](https://github.com/Devolutions/rustolonia/blob/v12.1.0/rust/rustolonia/README.md).

For compiled AXAML and generated view-model adapters, use the separate
[source-build scaffold](../rust/templates/avalonia-app/README.md) through
`rust/new-app.ps1`. It intentionally remains under `rust/templates/`: its
placeholders and producer-checkout requirements are different from these
copy-out release consumers.
3 changes: 3 additions & 0 deletions templates/form/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Allow release host downloads when building inside the Rustolonia checkout.
[env]
RUSTOLONIA_NO_DOWNLOAD = "0"
1 change: 1 addition & 0 deletions templates/form/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/target/
Loading
Loading