Skip to content
All insights

Academy

Cross-Compilation and Nightly Features: Advanced rustup for Power Users

Master cross-compilation with rustup: build for ARM, WebAssembly, and embedded devices, tap into nightly features, and manage multi-platform builds easily.

5 min read

Cross-Compilation and Nightly Features: Advanced rustup for Power Users
On this page

Most Rust developers use rustup to install stable Rust and never think about it again. The tool sits quietly in the background, doing its job without demanding attention—like a really good system administrator. But rustup has capabilities that become essential when your projects outgrow the "compile for my own machine" stage: cross-compiling for ARM servers, embedded microcontrollers, or WebAssembly; accessing nightly-only features for experimental work; and managing multiple toolchains for projects with different requirements.

Cross-compilation—building on one platform for another—is one of those capabilities that sounds exotic until you need it. Then it's urgent. Your development team works on macOS. Your servers run Linux x86_64. Your edge devices run Linux ARM64. Your web widgets need WebAssembly. Without cross-compilation, you'd need build machines for every target platform. With rustup and Cargo, you add one target, run one command, and get a binary for any platform Rust supports—which, as of now, is over 200 target triples.

At RantAI, where we deploy to x86 cloud servers and ARM-based edge devices from macOS development machines, cross-compilation through rustup is a daily workflow. This article, drawn from Chapter 7, Section 7.3 of our guide "The Rust Programming Language," covers the advanced capabilities that power users need.

Cross-Compilation: Three Steps#

Step 1: Add the Target#

Bash
rustup target add aarch64-unknown-linux-gnu     # ARM64 Linux
rustup target add wasm32-unknown-unknown        # WebAssembly
rustup target add x86_64-pc-windows-msvc        # Windows (from Linux/Mac)
rustup target add thumbv7em-none-eabihf         # ARM Cortex-M (embedded)
rustup target list --installed                  # See what you have

Step 2: Build for the Target#

Bash
cargo build --target aarch64-unknown-linux-gnu
cargo build --target wasm32-unknown-unknown --release

The compiled binary runs on the target platform, not your development machine. For some targets, you'll also need a linker for that platform (e.g., aarch64-linux-gnu-gcc for ARM Linux).

Step 3 (Optional): Set a Default Target#

Create .cargo/config.toml in your project:

TOML
[build]
target = "aarch64-unknown-linux-gnu"

[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"

Now cargo build automatically cross-compiles without the --target flag. This is useful for projects that always deploy to a specific platform different from the development machine.

Nightly Features: The Cutting Edge#

Some Rust features are only available on the nightly channel—they're experimental, potentially unstable, and might change before stabilization:

Bash
rustup override set nightly   # Use nightly for this project
Rust
#![feature(async_closure)]  // Enable a specific nightly feature

let async_add = async |a: i32, b: i32| -> i32 { a + b };

Nightly features are gated behind #![feature(...)] attributes. This makes their usage explicit—you always know which unstable features your project depends on. If a feature changes in a nightly update, the compiler tells you exactly what broke and why.

Pinning Nightly Versions#

For reproducibility, pin to a specific nightly date:

TOML
# rust-toolchain.toml
[toolchain]
channel = "nightly-2024-06-15"
components = ["rustfmt", "clippy"]

This ensures every build uses the same nightly, regardless of when it runs. Without pinning, rustup update might give you a newer nightly where features have changed—breaking your build.

Managing Multiple Toolchains#

Bash
rustup toolchain list                 # See all installed toolchains
rustup run nightly cargo build        # One-off: use nightly for a single command
rustup run 1.75.0 cargo test          # Use a specific version

rustup run lets you use any installed toolchain for a single command without changing your default or override. This is perfect for testing compatibility across Rust versions or trying a nightly feature without committing to nightly for the whole project.

WebAssembly: Rust in the Browser#

Bash
rustup target add wasm32-unknown-unknown
cargo install wasm-pack  # Higher-level WASM tooling

# Build a WASM module
cargo build --target wasm32-unknown-unknown --release
# Or with wasm-pack for web integration:
wasm-pack build --target web

Rust compiles to WebAssembly with the same safety guarantees and performance characteristics as native code. The resulting WASM modules run in browsers, Node.js, and standalone WASM runtimes (Wasmtime, Wasmer). This makes Rust one of the best languages for performance-critical web applications—image processing, cryptography, data visualization, and game engines running at near-native speed in the browser.

Embedded: Rust Without an OS#

Bash
rustup target add thumbv7em-none-eabihf   # ARM Cortex-M4F
rustup component add llvm-tools-preview    # Binary utilities
cargo install cargo-binutils              # Size analysis, objdump

cargo build --target thumbv7em-none-eabihf --release

Rust supports #![no_std] environments—embedded systems without an operating system, without heap allocation, without standard library I/O. The ownership system's compile-time memory management is particularly valuable here: no garbage collector means no unpredictable pauses, and the compiler's stack analysis helps verify that your program fits in the device's limited memory.

Broader Implications: One Toolchain, Every Platform#

At RantAI, our CI pipeline cross-compiles for three targets from a single Linux build machine. Developers work on macOS, build for Linux ARM, and test with QEMU. rustup makes this multi-platform workflow seamless—the same commands, the same configuration, the same reproducibility guarantees, regardless of how many platforms you target.

Practical Applications & Strategic Takeaways#

For web developers: wasm32-unknown-unknown opens the door to running Rust in browsers. Performance-critical frontend logic—parsing, computation, rendering—can be written in Rust and called from JavaScript.

For embedded developers: thumbv7em-none-eabihf for ARM Cortex-M. Rust is one of the best languages for embedded: no GC, predictable memory usage, and compile-time safety for hardware-level code.

For teams: Pin nightly versions in rust-toolchain.toml if you use nightly features. Unpinned nightly builds are reproducibility time bombs.

Our Commitment to Open Knowledge#

RantAI is committed to open education. Advanced rustup is covered in Chapter 7, Section 7.3 of our guide, "The Rust Programming Language," freely available online.

Explore these concepts further: https://trpl.rantai.dev

Support Our Mission & Get Your Handbook#

What targets do you cross-compile for? Any tips for WASM or embedded Rust? Share!

#RustLang #CrossCompilation #Rustup #Nightly #WebAssembly #RantAI #LearnRust #Embedded #ARM #MultiPlatform

Next article

The Perfect Rust Dev Environment: VS Code, rust-analyzer, and the Tools That Matter