Cross-compilation para ARM, WebAssembly e outros targets
1. Introdução à Cross-compilation em Rust
Cross-compilation é o processo de gerar código binário para uma plataforma diferente daquela em que o compilador está sendo executado. Em Rust, isso é essencial por diversas razões: dispositivos embarcados com recursos limitados, servidores ARM em datacenters, módulos WebAssembly para navegadores, e aplicativos móveis para Android e iOS.
A diferença fundamental entre compilação nativa e cruzada está no conceito de target triple. Um target triple segue o formato <arch>-<vendor>-<os>-<abi> (ex: arm-unknown-linux-gnueabihf). Rust suporta oficialmente dezenas de targets, incluindo ARM (várias variantes), WebAssembly, x86_64, MIPS, RISC-V, entre outros.
O compilador rustc já inclui suporte nativo para cross-compilation, mas requer toolchains específicas e bibliotecas C para cada target.
2. Configuração do Ambiente de Cross-compilation
O primeiro passo é adicionar o target desejado ao seu ambiente Rust:
// Adicionando targets
$ rustup target add arm-unknown-linux-gnueabihf
$ rustup target add wasm32-unknown-unknown
$ rustup target add aarch64-linux-android
Para gerenciar múltiplos targets, você pode usar toolchains específicas:
$ rustup toolchain install nightly --target arm-unknown-linux-gnueabihf
$ rustup toolchain list
Dependendo do target, você precisará instalar linkers e bibliotecas C. Para ARM Linux:
# Ubuntu/Debian
$ sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
# macOS (usando homebrew)
$ brew install arm-linux-gnueabihf-binutils
3. Compilando para ARM (Embedded e Linux)
Targets ARM comuns incluem arm-unknown-linux-gnueabihf (ARM Linux com hardware float) e thumbv7em-none-eabihf (ARM Cortex-M4 sem sistema operacional).
Configure o arquivo .cargo/config.toml:
[target.arm-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
rustflags = ["-C", "target-feature=+crt-static"]
[target.thumbv7em-none-eabihf]
linker = "arm-none-eabi-gcc"
rustflags = ["-C", "link-arg=-nostartfiles"]
Exemplo prático: compilando para Raspberry Pi:
// src/main.rs
use std::process::Command;
fn main() {
let output = Command::new("uname")
.arg("-m")
.output()
.expect("Falha ao executar comando");
println!("Arquitetura: {}",
String::from_utf8_lossy(&output.stdout).trim());
println!("Olá do Rust rodando em ARM!");
}
Compile com:
$ cargo build --target arm-unknown-linux-gnueabihf --release
$ scp target/arm-unknown-linux-gnueabihf/release/meu_app pi@192.168.1.100:~/
4. Compilando para WebAssembly (WASM)
Rust oferece dois targets WASM principais: wasm32-unknown-unknown (para navegadores) e wasm32-wasi (para ambientes server-side).
Para compilar para o navegador:
// src/lib.rs
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn fibonacci(n: u32) -> u32 {
match n {
0 => 0,
1 => 1,
_ => fibonacci(n - 1) + fibonacci(n - 2),
}
}
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Olá, {}! Bem-vindo ao WebAssembly com Rust!", name)
}
Crie o projeto e compile:
$ cargo new --lib meu_wasm
$ cd meu_wasm
$ cargo add wasm-bindgen
$ cargo build --target wasm32-unknown-unknown --release
$ wasm-pack build --target web
O wasm-pack gera automaticamente os arquivos JavaScript de glue e o pacote pronto para uso no navegador:
<script type="module">
import init, { fibonacci, greet } from './pkg/meu_wasm.js';
async function main() {
await init();
console.log(greet("Mundo"));
console.log(`Fibonacci(10) = ${fibonacci(10)}`);
}
main();
</script>
5. Compilando para Outros Targets (Android, iOS, Windows)
Android
Para compilar para Android, use os targets aarch64-linux-android (64 bits) ou armv7-linux-androideabi (32 bits). Você precisará do Android NDK:
$ rustup target add aarch64-linux-android
$ export ANDROID_NDK_HOME=/path/to/android-ndk
$ export CC_aarch64_linux_android=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android21-clang
$ cargo build --target aarch64-linux-android --release
iOS
Para iOS, use os targets aarch64-apple-ios (dispositivos físicos) e x86_64-apple-ios (simulador):
$ rustup target add aarch64-apple-ios
$ cargo build --target aarch64-apple-ios --release
No macOS, o Xcode fornece as toolchains necessárias automaticamente.
Windows a partir de Linux/macOS
Para compilar binários Windows:
# Para usar a ABI GNU (Mingw)
$ sudo apt-get install mingw-w64
$ rustup target add x86_64-pc-windows-gnu
$ cargo build --target x86_64-pc-windows-gnu --release
# Para usar a ABI MSVC (requer Wine + MSVC toolchain)
$ rustup target add x86_64-pc-windows-msvc
6. Gerenciamento de Dependências e C FFI
Ao fazer cross-compilation com dependências C, configure variáveis de ambiente e o arquivo build.rs:
// build.rs
use std::env;
fn main() {
let target = env::var("TARGET").unwrap();
if target.contains("arm") {
println!("cargo:rustc-link-search=/usr/arm-linux-gnueabihf/lib");
println!("cargo:rustc-link-lib=static=my_c_lib");
} else if target.contains("wasm32") {
println!("cargo:rustc-cfg=wasm");
}
// Configurar pkg-config para cross-compilation
if target.contains("linux") && !target.contains("x86_64") {
env::set_var("PKG_CONFIG_ALLOW_CROSS", "1");
env::set_var("PKG_CONFIG_LIBDIR",
format!("/usr/{}/lib/pkgconfig", target));
}
}
Dicas importantes:
- Use
cccrate para compilar código C condicionalmente - Configure
CCeARpara o linker correto - Evite paths absolutos em bibliotecas C
7. Testando e Depurando Binários Cross-compilados
Para testar binários ARM sem hardware físico, use QEMU:
$ sudo apt-get install qemu-user qemu-system-arm
# Executar binário ARM64
$ qemu-aarch64 -L /usr/aarch64-linux-gnu target/aarch64-unknown-linux-gnu/release/meu_app
# Executar testes
$ cargo test --target arm-unknown-linux-gnueabihf -- --test-threads=1
Para depuração remota com GDB:
$ qemu-arm -g 1234 target/arm-unknown-linux-gnueabihf/debug/meu_app
$ gdb-multiarch target/arm-unknown-linux-gnueabihf/debug/meu_app
(gdb) target remote localhost:1234
(gdb) continue
8. Boas Práticas e Automação
Crie scripts de build com just ou Makefile:
# Makefile
TARGETS := arm-unknown-linux-gnueabihf wasm32-unknown-unknown x86_64-pc-windows-gnu
.PHONY: all $(TARGETS)
all: $(TARGETS)
$(TARGETS):
cargo build --target $@ --release
test-arm:
qemu-arm -L /usr/arm-linux-gnueabihf target/arm-unknown-linux-gnueabihf/debug/meu_app
deploy-arm:
scp target/arm-unknown-linux-gnueabihf/release/meu_app pi@192.168.1.100:~/
Para CI/CD com GitHub Actions:
# .github/workflows/cross-compile.yml
name: Cross-compilation
on: [push]
jobs:
build:
strategy:
matrix:
target: [arm-unknown-linux-gnueabihf, wasm32-unknown-unknown]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.target }}
- run: sudo apt-get install gcc-arm-linux-gnueabihf
- run: cargo build --target ${{ matrix.target }} --release
Checklist final:
- Use
cfg!(target_arch = "arm")para código condicional - Verifique features específicas do target com
#[cfg(target_arch = "wasm32")] - Teste em ambientes reais sempre que possível
- Documente as dependências de toolchain no README do projeto
Referências
- The Rust Cross-compilation Book — Guia oficial da equipe Rust sobre configuração de cross-compilation com rustup.
- Rust and WebAssembly — Documentação completa do grupo Rust/WASM, incluindo wasm-pack e wasm-bindgen.
- Embedded Rust Book — Guia oficial para desenvolvimento embarcado com Rust, incluindo cross-compilation para ARM Cortex-M.
- Cross Compiling Rust for Android — Tutorial da Mozilla sobre compilação cruzada de Rust para Android.
- Rust on Raspberry Pi — Guia prático e exemplos de código para compilar Rust para Raspberry Pi (ARM Linux).
- Awesome Rust Embedded — Lista curada de recursos, bibliotecas e ferramentas para desenvolvimento embarcado com Rust.