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

HerramientaCómo resuelve el enlazadoCuándo encaja
cargo-zigbuildUsa el toolchain de Zig como enlazadorLinux musl y glibc (incluso con versión fija de glibc); simple y sin contenedores
crossContenedores Docker/Podman con el entorno del target ya listoMuchos targets distintos sin preparar toolchains a mano
Toolchain nativaInstalas el enlazador y las libs del sistema destino tú mismoControl 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
Un host, varios destinosTu hostx86_64 Linuxcompilaenlazadozig · crossARM LinuxWindows (.exe)musl (mínimo)
Compilar para otra plataforma es fácil; el paso difícil es el enlazado, que 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-musl cabe en una imagen mínima; aquí conviene repasar musl frente a glibc.
  • Clientes en Windows. Producir un .exe para x86_64-pc-windows-gnu desde 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í cross suele 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); cross incluso ofrece ejecutar los tests dentro del contenedor del target.

Cuándo usarlo / Qué recordar

  • El modelo de targets de Rust es sencillo: rustup target add y cargo 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, cross y 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.

Fuentes

  1. Platform Support - The rustc bookThe rustc book
  2. Cross-compilation - The rustup bookThe rustup book
  3. GitHub - rust-cross/cargo-zigbuild: Compile Cargo project with zig as linkercargo-zigbuild
  4. GitHub - cross-rs/cross: “Zero setup” cross compilation and “cross testing” of Rust cratescross-rs

Construye mejor software.

Seguridad, eficiencia y oficio, con fuentes.