Cross-compilation é o ato de compilar código em uma plataforma para que ele rode em outra. Se você desenvolve no Linux e precisa entregar binários para Windows, macOS ou ARM, sabe que configurar toolchains tradicionais pode ser um pesadelo. A linguagem Zig resolve esse problema de forma radical: a cross-compilation já vem embutida, sem precisar instalar nada além do próprio compilador.
Neste guia, vamos explorar por que Zig se tornou referência em compilação cruzada, como usar o zig cc como compilador C portátil, e como montar pipelines CI/CD que compilam para dezenas de alvos simultaneamente.
Por que Zig é Excepcional em Cross-Compilation
Compiladores tradicionais como GCC exigem que você baixe, configure e mantenha toolchains separadas para cada alvo. Quer compilar de Linux para Windows? Instale mingw-w64. Para ARM? Instale gcc-aarch64-linux-gnu. Para macOS? Boa sorte — quase impossível fora de um Mac.
Zig elimina tudo isso. O compilador já inclui headers e bibliotecas libc para mais de 40 alvos, incluindo:
x86_64-linux-gnuaarch64-linux-gnux86_64-windows-gnuaarch64-macos-noneriscv64-linux-gnuwasm32-wasi
Isso significa que com uma única instalação de Zig, você compila para qualquer uma dessas plataformas. Não precisa de Docker, não precisa de VMs, não precisa de SDKs extras.
Listando Todos os Alvos Disponíveis
Para ver a lista completa de target triples suportados:
zig targets | jq '.arch[]'
zig targets | jq '.os[]'
zig targets | jq '.abi[]'
O comando zig targets retorna um JSON com todas as combinações de arquitetura, sistema operacional e ABI suportadas. São centenas de combinações possíveis.
Cross-Compilando Projetos Zig
A forma mais direta de cross-compilar um projeto Zig é usando a flag -Dtarget:
# Compilar para Windows x86_64
zig build -Dtarget=x86_64-windows-gnu
# Compilar para Linux ARM64 (Raspberry Pi 4, servidores ARM)
zig build -Dtarget=aarch64-linux-gnu
# Compilar para macOS ARM (Apple Silicon)
zig build -Dtarget=aarch64-macos-none
# Compilar para WebAssembly
zig build -Dtarget=wasm32-wasi
Cada um desses comandos produz um binário nativo para o alvo especificado, compilado na sua máquina de desenvolvimento. Sem containers, sem emulação.
Configurando o Build System para Cross-Compilation
No arquivo build.zig, você pode configurar alvos padrão e criar steps dedicados para cada plataforma:
const std = @import("std");
pub fn build(b: *std.Build) void {
// Alvo padrão: plataforma nativa
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "meu-servidor",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
// Step dedicado para build de release multiplataforma
const release_step = b.step("release", "Build para todas as plataformas");
const targets: []const std.Target.Query = &.{
.{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu },
.{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .gnu },
.{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu },
.{ .cpu_arch = .aarch64, .os_tag = .macos },
};
for (targets) |t| {
const release_exe = b.addExecutable(.{
.name = "meu-servidor",
.root_source_file = b.path("src/main.zig"),
.target = b.resolveTargetQuery(t),
.optimize = .ReleaseSafe,
});
release_step.dependOn(&b.addInstallArtifact(release_exe).step);
}
}
Com isso, zig build release compila para Linux x86_64, Linux ARM64, Windows e macOS de uma só vez.
Zig CC: O Compilador C Portátil
Uma das funcionalidades mais revolucionárias de Zig é o zig cc — um drop-in replacement para gcc e clang que já suporta cross-compilation nativamente. Isso significa que projetos C e C++ existentes podem ser cross-compilados com Zig sem modificar uma linha de código.
# Compilar código C para Windows, rodando no Linux
zig cc -target x86_64-windows-gnu -o programa.exe programa.c
# Compilar código C para ARM Linux
zig cc -target aarch64-linux-gnu -o programa programa.c
# Usar como compilador C++ também funciona
zig c++ -target x86_64-windows-gnu -o app.exe app.cpp
Usando zig cc com Projetos Existentes
Muitos projetos C usam make ou cmake. Você pode substituir o compilador:
# Com Make
CC="zig cc -target aarch64-linux-gnu" make
# Com CMake
cmake -DCMAKE_C_COMPILER="zig cc" \
-DCMAKE_C_COMPILER_TARGET="aarch64-linux-gnu" \
-B build
# Com Cargo (Rust) — sim, funciona!
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="zig cc -target aarch64-linux-gnu" \
cargo build --target aarch64-unknown-linux-gnu
Esse é um dos motivos pelo qual projetos como Bun e Ghostty adotaram Zig — a toolchain simplifica enormemente o processo de build multiplataforma.
Cross-Compilation sem Docker
Antes de Zig, muitas equipes dependiam de Docker para cross-compilar. A abordagem típica era:
- Criar uma imagem Docker com a toolchain do alvo
- Montar o código-fonte como volume
- Compilar dentro do container
- Extrair o binário
Com Zig, esse fluxo se resume a um único comando. Não precisa de Docker, não precisa esperar builds de imagem, não precisa gerenciar volumes. Compare:
# Abordagem tradicional com Docker (lento, complexo)
docker build -t cross-arm -f Dockerfile.arm64 .
docker run --rm -v $(pwd):/src cross-arm make
# Abordagem com Zig (instantâneo, simples)
zig build -Dtarget=aarch64-linux-gnu -Doptimize=ReleaseSafe
A diferença de produtividade é brutal — especialmente em pipelines CI/CD onde cada minuto de build custa dinheiro.
Cross-Compilation em Pipelines CI/CD
Com Zig, montar uma matriz de build CI/CD para múltiplas plataformas é trivial. Veja um exemplo para Gitea Actions (funciona também com GitHub Actions):
name: Build Multi-Platform
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
target:
- x86_64-linux-gnu
- aarch64-linux-gnu
- x86_64-windows-gnu
- aarch64-macos-none
steps:
- uses: actions/checkout@v4
- name: Instalar Zig
run: |
wget https://ziglang.org/download/0.14.0/zig-linux-x86_64-0.14.0.tar.xz
tar xf zig-linux-x86_64-0.14.0.tar.xz
echo "$PWD/zig-linux-x86_64-0.14.0" >> $GITHUB_PATH
- name: Build para ${{ matrix.target }}
run: zig build -Dtarget=${{ matrix.target }} -Doptimize=ReleaseSafe
- name: Upload artefato
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.target }}
path: zig-out/bin/
Com essa configuração, cada push de tag compila automaticamente para quatro plataformas em paralelo. Uma máquina Linux produz binários nativos para Linux, Windows, macOS e ARM — tudo em minutos.
Comparação com Toolchains Tradicionais
| Aspecto | GCC Cross | LLVM/Clang | Docker | Zig |
|---|---|---|---|---|
| Instalação | Uma toolchain por alvo | Complexa | Imagem por alvo | Único binário |
| macOS como alvo | Quase impossível | Precisa de SDK | Precisa de osxcross | Nativo |
| Windows como alvo | mingw-w64 | Precisa de headers | Imagem separada | Nativo |
| Compilar C existente | Suportado | Suportado | Depende da imagem | zig cc |
| Tempo de setup | 30min+ por alvo | 20min+ | 10min+ por imagem | 0 minutos |
| Tamanho | 500MB+ por toolchain | 1GB+ | 1GB+ por imagem | ~40MB total |
A vantagem de Zig não é apenas conveniência — é uma mudança fundamental na forma como pensamos sobre builds multiplataforma. Enquanto outras ferramentas resolvem o problema adicionando camadas de complexidade, Zig resolve eliminando a complexidade na raiz.
Go também simplifica cross-compilation com variáveis GOOS/GOARCH — se você quer comparar as abordagens, confira o Golang Brasil. Para cross-compilation em Rust usando cargo cross, veja os guias no Rust Brasil.
Armadilhas Comuns em Cross-Compilation
Mesmo com Zig simplificando o processo, existem pontos de atenção:
1. Dependências de sistema — Se seu projeto Zig usa @cImport para chamar bibliotecas C do sistema (como OpenSSL ou zlib), essas bibliotecas precisam estar disponíveis para o alvo. Prefira implementações puras em Zig ou use bibliotecas estáticas.
2. Syscalls específicas — Funcionalidades como io_uring são específicas do Linux. Ao cross-compilar, use comptime para detectar o alvo e oferecer fallbacks:
const builtin = @import("builtin");
const IoBackend = if (builtin.os.tag == .linux)
@import("io_uring_backend.zig")
else
@import("poll_backend.zig");
3. Testes em alvos cruzados — Cross-compilar é fácil, mas testar exige emulação. Use QEMU para testar binários ARM no x86:
zig build -Dtarget=aarch64-linux-gnu
qemu-aarch64 ./zig-out/bin/meu-programa
4. ABI e linking — Ao cross-compilar para Windows, use a ABI gnu (MinGW) em vez de msvc para evitar dependência do Visual Studio.
Casos de Uso Práticos
A cross-compilation de Zig brilha em cenários reais:
- CLIs multiplataforma — Distribua binários nativos para Linux, macOS e Windows sem manter três ambientes de build
- IoT e embarcados — Compile para ARM, RISC-V e MIPS direto do seu notebook
- Servidores ARM — Com a adoção crescente de ARM em nuvem (AWS Graviton, Ampere), compilar de x86 para ARM é cada vez mais necessário
- WebAssembly — Compile para WASM e rode no browser ou em runtimes como Wasmtime
- Projetos C legados — Use
zig ccpara cross-compilar projetos C existentes sem reescrevê-los
Se você quer entender melhor o ecossistema de ferramentas Zig, ou ver como empresas usam Zig em produção, confira nossos outros guias. E se está migrando de C, nosso artigo sobre migração de C para Zig cobre as diferenças práticas.
Conclusão
Cross-compilation é uma das maiores vantagens competitivas de Zig sobre C e outras linguagens de sistemas. Enquanto toolchains tradicionais exigem configuração complexa, múltiplas instalações e frequentemente Docker, Zig oferece tudo isso em um único binário de 40MB.
Se você trabalha com software que precisa rodar em múltiplas plataformas — e hoje em dia, quase todo software precisa — Zig merece sua atenção. A compilação cruzada não é um recurso extra; é parte fundamental do design da linguagem.