Aprende Rust · 6 min
Compila una vez, ejecuta en otra plataforma: cross-compiling en Rust
Cómo compilar desde tu máquina un binario para otro sistema o arquitectura, y qué herramienta usar para resolver el enlazado.
Querer un binario de Linux para Windows, o uno de tu portátil x86_64 para una Raspberry Pi ARM, es cosa de todos los días. A eso se le llama cross-compiling: la máquina donde compilas (el host) y la máquina donde correrá el binario (el target) son distintas. Rust tiene uno de los modelos de targets más limpios que existen, pero conviene entender dónde está el trabajo real antes de elegir herramienta.
El modelo de targets de Rust
Rust identifica cada plataforma con un target triple: una cadena que describe arquitectura, proveedor, sistema y entorno. Por ejemplo aarch64-unknown-linux-gnu (ARM de 64 bits, Linux con glibc) o x86_64-pc-windows-gnu (x86_64, Windows con el toolchain GNU).
Agregar un target y compilar para él son dos comandos:
rustup target list # todos los targets disponibles
rustup target add aarch64-unknown-linux-gnu
cargo build --release --target aarch64-unknown-linux-gnu
El libro de rustc mantiene la lista oficial de plataformas y su nivel de soporte ("Tier 1", "Tier 2", "Tier 3"), que indica cuánta garantía tiene cada target.
El problema real: el enlazado
Aquí está el matiz que casi nadie cuenta al principio. rustup target add instala la biblioteca estándar para ese target, nada más. Compilar tu código a muchas arquitecturas es, de verdad, fácil. Lo difícil es el último paso: enlazar.
Para producir el binario final hace falta un enlazador capaz de generar código para el target y, muchas veces, las bibliotecas C de ese sistema. Si tu proyecto o alguna dependencia usa código nativo en C, necesitas el toolchain de la plataforma destino. Por eso, un cargo build --target ... desde cero suele fallar en el enlazado aunque la compilación haya ido bien. Las herramientas que siguen existen justamente para resolver ese paso.
Qué herramienta usar
| Herramienta | Cómo resuelve el enlazado | Cuándo encaja |
|---|---|---|
cargo-zigbuild | Usa el toolchain de Zig como enlazador | Linux musl y glibc (incluso con versión fija de glibc); simple y sin contenedores |
cross | Contenedores Docker/Podman con el entorno del target ya listo | Muchos targets distintos sin preparar toolchains a mano |
| Toolchain nativa | Instalas el enlazador y las libs del sistema destino tú mismo | Control total; cuando necesitas algo que las otras no cubren |
cargo-zigbuild aprovecha que Zig trae un enlazador multiplataforma. Es la vía más cómoda para Linux y encaja de lleno con los binarios estáticos de musl:
cargo install cargo-zigbuild
rustup target add aarch64-unknown-linux-gnu
cargo zigbuild --release --target aarch64-unknown-linux-gnu
cross toma otro camino: ejecuta la compilación dentro de un contenedor Docker o Podman que ya trae el enlazador y las bibliotecas del target. Tú solo cambias cargo por cross:
cargo install cross
cross build --release --target aarch64-unknown-linux-gnu
cargo-zigbuild (con Zig) o cross (con contenedores) resuelven por ti.Casos de uso
- Distribuir desde CI. Compilar binarios para Linux, Windows y ARM en un solo pipeline, sin una máquina por plataforma.
- Dispositivos ARM. Generar en tu portátil el binario para una Raspberry Pi o un servidor ARM, sin compilar en el propio dispositivo.
- Imágenes de contenedor pequeñas. Un binario estático para
aarch64-unknown-linux-muslcabe en una imagen mínima; aquí conviene repasar musl frente a glibc. - Clientes en Windows. Producir un
.exeparax86_64-pc-windows-gnudesde Linux.
La parte honesta: compilar es fácil, enlazar no siempre
- Las dependencias nativas en C complican todo. Una crate que compila C o se enlaza con una biblioteca del sistema puede necesitar su toolchain, cabeceras y libs del target. Ahí
crosssuele ahorrarte dolores porque el contenedor ya los trae. - Cross-compilar a macOS desde Linux es terreno delicado. El SDK de Apple tiene condiciones de licencia que lo complican legal y técnicamente; no es un camino que recomendemos a la ligera.
- Compilar no es probar. Un binario que enlaza bien no garantiza que funcione en el target. Antes de distribuir, pruébalo en la plataforma real (o en un emulador fiel);
crossincluso ofrece ejecutar los tests dentro del contenedor del target.
Cuándo usarlo / Qué recordar
- El modelo de targets de Rust es sencillo:
rustup target addycargo build --target. El trabajo real es el enlazado. - Para Linux, empieza por
cargo-zigbuild: rápido, sin contenedores y excelente con musl y glibc. - Si tienes muchos targets o dependencias nativas enredadas,
crossy sus contenedores te dan el entorno listo. - macOS desde Linux: evítalo salvo que sepas en qué te metes.
- Compila donde quieras, pero valida en el target real antes de publicar.
Más herramientas para afinar el build, en la caja de herramientas.