Zig e WebAssembly — Ferramentas, Compilação e Runtime WASM
O Zig é uma das melhores linguagens para desenvolvimento WebAssembly. Com suporte nativo a WASM como target de compilação, binários extremamente pequenos e controle total sobre alocação de memória, o Zig produz módulos WASM que frequentemente são menores e mais rápidos que equivalentes em C, C++ ou Rust.
Por Que Zig para WebAssembly
O Zig possui características que o tornam ideal para WASM:
- Binários minúsculos: Um hello world WASM em Zig pode ter menos de 1 KB
- Sem runtime: Nenhum código de inicialização oculto no binário
- Controle de memória: Sem GC, ideal para o modelo de memória linear do WASM
- Compilação nativa:
wasm32-freestandingewasm32-wasisão targets de primeira classe - Interop C: Use qualquer biblioteca C compilável para WASM
Compilando para WebAssembly
Target wasm32-freestanding (Browser)
// src/lib.zig
export fn somar(a: i32, b: i32) i32 {
return a + b;
}
export fn fatorial(n: u32) u64 {
if (n <= 1) return 1;
var resultado: u64 = 1;
var i: u32 = 2;
while (i <= n) : (i += 1) {
resultado *= i;
}
return resultado;
}
export fn fibonacci(n: u32) u64 {
if (n <= 1) return n;
var a: u64 = 0;
var b: u64 = 1;
var i: u32 = 2;
while (i <= n) : (i += 1) {
const temp = a + b;
a = b;
b = temp;
}
return b;
}
# Compilar para WASM
zig build-lib src/lib.zig -target wasm32-freestanding -dynamic -O ReleaseSmall
build.zig para WASM
const std = @import("std");
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const lib = b.addSharedLibrary(.{
.name = "app",
.root_source_file = b.path("src/lib.zig"),
.target = b.resolveTargetQuery(.{
.cpu_arch = .wasm32,
.os_tag = .freestanding,
}),
.optimize = optimize,
});
// Exportar tabela de memória
lib.export_memory = true;
lib.initial_memory = 65536; // 1 página (64KB)
b.installArtifact(lib);
}
Usando no Browser
<!DOCTYPE html>
<html>
<head><title>Zig WASM Demo</title></head>
<body>
<script>
async function init() {
const response = await fetch('app.wasm');
const bytes = await response.arrayBuffer();
const { instance } = await WebAssembly.instantiate(bytes, {
env: {
// Funções importadas do JavaScript
log: (valor) => console.log('Zig diz:', valor),
}
});
// Chamar funções exportadas do Zig
console.log('2 + 3 =', instance.exports.somar(2, 3));
console.log('10! =', instance.exports.fatorial(10));
console.log('fib(20) =', instance.exports.fibonacci(20));
}
init();
</script>
</body>
</html>
WASI — WebAssembly System Interface
Para aplicações que precisam de acesso ao sistema de arquivos e rede:
// src/main.zig - WASI
const std = @import("std");
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
try stdout.print("Olá do Zig WASI!\n", .{});
// Acessar argumentos
var args = std.process.args();
while (args.next()) |arg| {
try stdout.print("Arg: {s}\n", .{arg});
}
// Acessar variáveis de ambiente
const path = std.posix.getenv("PATH") orelse "não definido";
try stdout.print("PATH: {s}\n", .{path});
}
# Compilar para WASI
zig build-exe src/main.zig -target wasm32-wasi -O ReleaseSmall
# Executar com wasmtime
wasmtime main.wasm
# Executar com wasmer
wasmer main.wasm
Interação Avançada com JavaScript
Passando Strings
// Zig: exportar string para JavaScript
var buffer: [1024]u8 = undefined;
export fn obter_saudacao(nome_ptr: [*]const u8, nome_len: usize) usize {
const nome = nome_ptr[0..nome_len];
const resultado = std.fmt.bufPrint(&buffer, "Olá, {s}! Bem-vindo ao Zig WASM.", .{nome}) catch return 0;
return resultado.len;
}
export fn obter_buffer_ptr() [*]const u8 {
return &buffer;
}
// JavaScript: trocar strings com Zig
const encoder = new TextEncoder();
const decoder = new TextDecoder();
function saudar(nome) {
const nomeBytes = encoder.encode(nome);
const memory = instance.exports.memory;
const memView = new Uint8Array(memory.buffer);
// Copiar nome para memória WASM
const nomePtr = instance.exports.__heap_base;
memView.set(nomeBytes, nomePtr);
// Chamar função Zig
const resultLen = instance.exports.obter_saudacao(nomePtr, nomeBytes.length);
const bufPtr = instance.exports.obter_buffer_ptr();
// Ler resultado
const resultado = decoder.decode(memView.slice(bufPtr, bufPtr + resultLen));
console.log(resultado);
}
Canvas e Gráficos
// Renderização em canvas via WASM
const LARGURA: u32 = 800;
const ALTURA: u32 = 600;
var framebuffer: [LARGURA * ALTURA * 4]u8 = undefined;
export fn obter_framebuffer() [*]u8 {
return &framebuffer;
}
export fn obter_largura() u32 {
return LARGURA;
}
export fn obter_altura() u32 {
return ALTURA;
}
export fn renderizar(tempo: f64) void {
for (0..ALTURA) |y| {
for (0..LARGURA) |x| {
const idx = (y * LARGURA + x) * 4;
const fx = @as(f32, @floatFromInt(x)) / @as(f32, @floatFromInt(LARGURA));
const fy = @as(f32, @floatFromInt(y)) / @as(f32, @floatFromInt(ALTURA));
_ = tempo;
framebuffer[idx + 0] = @intFromFloat(fx * 255); // R
framebuffer[idx + 1] = @intFromFloat(fy * 255); // G
framebuffer[idx + 2] = 128; // B
framebuffer[idx + 3] = 255; // A
}
}
}
Otimização de Tamanho
Técnicas para minimizar o binário WASM:
# Usar ReleaseSmall
zig build -Doptimize=ReleaseSmall -Dtarget=wasm32-freestanding
# Strip de seções desnecessárias
wasm-strip output.wasm
# Otimizar com wasm-opt (Binaryen)
wasm-opt -O3 -o output-opt.wasm output.wasm
| Otimização | Tamanho típico |
|---|---|
| Debug | ~50 KB |
| ReleaseSafe | ~20 KB |
| ReleaseFast | ~15 KB |
| ReleaseSmall | ~5 KB |
| ReleaseSmall + strip | ~2 KB |
| ReleaseSmall + wasm-opt | ~1.5 KB |
Edge Computing com WASM
O Zig é usado por empresas como Cloudflare para Workers WASM em edge computing, aproveitando o startup rápido e tamanho mínimo dos binários.
Boas Práticas
- Use
ReleaseSmallpara binários web — cada byte conta - Minimize imports — reduza dependências do host
- Pré-aloque memória — evite crescimento dinâmico da memória WASM
- Teste em múltiplos runtimes — wasmtime, wasmer, browser
- Profile com ferramentas WASM — use wasm-opt analyze para identificar gargalos
Próximos Passos
Explore as bibliotecas gráficas para renderização WASM, os frameworks web para backends WASI, e o case da Cloudflare para uso em produção. Consulte nossos tutoriais para projetos WASM práticos.