O sistema de pacotes do Zig é uma das features mais recentes e poderosas da linguagem. Introduzido na versão 0.11.0 e aprimorado nas versões subsequentes, o Zig Package Manager permite que você compartilhe código, gerencie dependências e crie módulos reutilizáveis de forma elegante — tudo sem precisar de ferramentas externas como npm, pip, cargo ou vcpkg.
Neste tutorial completo, você vai aprender tudo sobre o build.zig.zon (o arquivo de manifesto de pacotes), como adicionar dependências de repositórios remotos ou locais, criar seus próprios módulos e publicar pacotes para a comunidade.
Pré-requisito: Ter o Zig instalado e conhecer o básico do Zig Build System. Se você ainda não está familiarizado com o
build.zig, recomendamos começar por lá.
O que é o Zig Package Manager?
Evolução do Gerenciamento de Pacotes no Zig
Antes do sistema de pacotes nativo, desenvolvedores Zig dependiam de:
- Git submodules — frágeis, difíceis de atualizar
- Vendoring — copiar código manualmente, sem versionamento
- System package managers — não portáveis entre plataformas
- Conan/vcpkg — ferramentas externas, complexas para projetos simples
O Zig Package Manager resolve todos esses problemas com uma solução integrada, simples e portátil.
Componentes do Sistema de Pacotes
| Componente | Descrição |
|---|---|
build.zig.zon | Manifesto do pacote (metadados + dependências) |
zig fetch | Comando para baixar e adicionar dependências |
zig build --fetch | Baixa todas as dependências declaradas |
b.dependency() | API no build.zig para acessar dependências |
b.createModule() | Cria módulos reutilizáveis |
| Cache global | .cache/zig/ armazena dependências baixadas |
Arquitetura: Como Funciona
Seu Projeto
├── build.zig # Configuração do build
├── build.zig.zon # Manifesto (nome, versão, deps)
└── src/
└── main.zig
Dependências (em ~/.cache/zig/)
├── p/ # Pacotes baixados
│ ├── 1220abc.../ # Hash único do pacote
│ │ ├── build.zig
│ │ └── src/
│ └── 1220def.../
└── tmp/ # Downloads temporários
O sistema usa content-addressable storage — cada pacote é identificado pelo hash do seu conteúdo, garantindo integridade e reproducibilidade.
O Arquivo build.zig.zon — Manifesto do Pacote
O build.zig.zon (Zig Object Notation) é o coração do sistema de pacotes. É um arquivo de configuração declarativo que define metadados do seu projeto e suas dependências.
Estrutura Básica
.{
.name = .@"meu-projeto",
.version = "0.1.0",
.fingerprint = 0x1234abcd, // Gerado automaticamente
.minimum_zig_version = "0.15.0",
.dependencies = .{},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
"LICENSE",
"README.md",
},
}
Campos do build.zig.zon
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
.name | enum | ✅ | Nome do pacote (prefixado com @) |
.version | string | ✅ | Versão semântica (semver) |
.fingerprint | integer | ✅ | Hash único do pacote (gerado por zig build) |
.minimum_zig_version | string | ❌ | Versão mínima do Zig necessária |
.dependencies | struct | ❌ | Dependências do projeto |
.paths | array | ✅ | Arquivos/pastas incluídos no pacote |
O Campo .name
O nome do pacote usa um enum prefixado para evitar colisões:
.{
// ✅ Correto — usa prefixo @
.name = .@"minha-lib",
// ✅ Correto — sem hífen, sem problema
.name = .minhalib,
// ❌ Incorreto — hífen sem prefixo
// .name = .minha-lib, // Erro de sintaxe!
}
Boas práticas para nomes:
- Use nomes descritivos e únicos
- Prefira
minha-libsobrelibgenérico - Verifique se o nome já existe em repositórios populares
O Campo .fingerprint
O fingerprint é um hash único gerado automaticamente pelo Zig:
.{
.name = .@"meu-projeto",
.version = "0.1.0",
.fingerprint = 0x9b80, // Gerado por `zig build`
// ...
}
⚠️ Nunca altere manualmente o fingerprint. Ele garante que pacotes com nomes similares não colidam.
O Campo .paths
Define quais arquivos são incluídos quando o pacote é distribuído:
.{
.paths = .{
// Arquivos essenciais
"build.zig",
"build.zig.zon",
// Código-fonte
"src",
// Documentação
"README.md",
"LICENSE",
"CHANGELOG.md",
// Assets (opcional)
"assets",
},
}
O que NÃO incluir:
.paths = .{
// ❌ Não incluir arquivos gerados
// ".zig-cache", // Cache de compilação
// "zig-out", // Artefatos de build
// ❌ Não incluir arquivos de desenvolvimento
// ".git", // Repositório git
// ".github", // CI configs
// "tests/fixtures", // Arquivos de teste grandes
// ❌ Não incluir secrets
// ".env", // Variáveis de ambiente
// "secrets.json", // Chaves privadas
}
Exemplo Completo: Manifesto de Biblioteca
.{
.name = .@"zig-json-parser",
.version = "1.2.0",
.fingerprint = 0x8f3a2b1c,
.minimum_zig_version = "0.15.0",
.dependencies = .{
// Dependências serão adicionadas aqui
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
"README.md",
"LICENSE",
"CHANGELOG.md",
},
}
Adicionando Dependências
Método 1: Usando zig fetch --save
A forma mais simples e recomendada de adicionar uma dependência:
# Adicionar de uma URL
zig fetch --save https://github.com/user/repo/archive/refs/tags/v1.0.0.tar.gz
# Adicionar de um repositório Git
zig fetch --save git+https://github.com/user/repo#v1.0.0
# Adicionar do GitHub (sintaxe simplificada)
zig fetch --save git+https://github.com/hendriknielaender/zBench
O que acontece:
- O Zig baixa o pacote
- Calcula o hash de integridade
- Atualiza automaticamente o
build.zig.zon - Armazena no cache global (
~/.cache/zig/)
Exemplo de build.zig.zon após zig fetch:
.{
.name = .@"meu-projeto",
.version = "0.1.0",
.dependencies = .{
.zbench = .{
.url = "git+https://github.com/hendriknielaender/zBench#v0.9.2",
.hash = "1220c4c79d6a7c7713b6c7391c96276b9b4f72b3b8d4f6c4e3e1a2b3c4d5e6f7a8b9c",
},
},
.paths = .{ "build.zig", "build.zig.zon", "src" },
}
Método 2: Edição Manual do build.zig.zon
Para maior controle, você pode editar manualmente:
.{
.dependencies = .{
// Dependência de tarball
.minha_dep = .{
.url = "https://example.com/lib-1.0.0.tar.gz",
.hash = "1220abc123...", // Hash obrigatório!
},
// Dependência Git com tag específica
.outra_dep = .{
.url = "git+https://github.com/user/repo#v2.0.0",
.hash = "1220def456...",
},
// Dependência Git com commit específico
.dep_commit = .{
.url = "git+https://github.com/user/repo#abc123def",
.hash = "1220abc789...",
},
// Dependência Git (main branch — não recomendado para produção)
.dep_latest = .{
.url = "git+https://github.com/user/repo",
.hash = "1220fff000...",
},
},
}
⚠️ Aviso: O hash é obrigatório para garantir integridade. Para obtê-lo, execute
zig build --fetchapós adicionar a URL.
Método 3: Dependências Locais (Path)
Para desenvolvimento local ou monorepos:
.{
.dependencies = .{
// Dependência em caminho relativo
.minha_lib_local = .{
.path = "../minha-lib",
},
// Dependência em caminho absoluto
.outra_lib = .{
.path = "/home/user/projetos/outra-lib",
},
},
}
Cenários comuns para dependências locais:
- Monorepo: Vários pacotes no mesmo repositório
- Desenvolvimento simultâneo: Editando lib e app ao mesmo tempo
- Forks locais: Modificando uma dependência
- Projetos privados: Código que não pode ser publicado
Configurando Dependências no build.zig
Declarar no build.zig.zon não é suficiente — você também precisa configurar no build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// === Configurar dependências ===
// Obtém a dependência declarada no build.zig.zon
const zbench = b.dependency("zbench", .{
.target = target,
.optimize = optimize,
});
// Cria o executável
const exe = b.addExecutable(.{
.name = "meu-app",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
// === Adicionar módulos da dependência ===
// Adiciona o módulo "zbench" da dependência
exe.root_module.addImport("zbench", zbench.module("zbench"));
b.installArtifact(exe);
// ... resto do build.zig
}
Fluxo de dados:
build.zig.zon build.zig Código Zig
│ │ │
│ Declara dep │ Obtém com │ Usa com
│ "zbench" │ b.dependency() │ @import()
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────────┐
│ .zbench │──────────▶│ zbench │────────────▶│ @import() │
│ = {...}│ │ module │ │ ("zbench") │
└─────────┘ └─────────┘ └─────────────┘
Exemplo Prático: Adicionando uma Biblioteca de Logging
Vamos adicionar a biblioteca zul (Zig Utility Library) passo a passo:
Passo 1: Buscar a dependência
zig fetch --save git+https://github.com/vsrinivas/zul
Passo 2: Verificar o build.zig.zon atualizado
.{
.name = .@"meu-app",
.version = "0.1.0",
.dependencies = .{
.zul = .{
.url = "git+https://github.com/vsrinivas/zul#v0.3.2",
.hash = "1220a1b2c3d4e5f6...",
},
},
.paths = .{ "build.zig", "build.zig.zon", "src" },
}
Passo 3: Configurar no build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Obtém a dependência zul
const zul = b.dependency("zul", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "meu-app",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
// Adiciona o módulo "zul"
exe.root_module.addImport("zul", zul.module("zul"));
b.installArtifact(exe);
// Steps run e test...
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
Passo 4: Usar no código Zig
const std = @import("std");
const zul = @import("zul");
pub fn main() !void {
// Usa a biblioteca zul
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Exemplo: parsing de UUID
const uuid = try zul.UUID.parse("550e8400-e29b-41d4-a716-446655440000");
std.debug.print("UUID: {s}\n", .{uuid});
}
Gerenciamento de Versões
Versionamento Semântico (Semver)
O Zig usa semver para versionamento de pacotes:
MAJOR.MINOR.PATCH
1.2.3
│ │ │
│ │ └── Correções de bugs (backward compatible)
│ │
│ └────── Novas features (backward compatible)
│
└────────── Breaking changes
Exemplos:
.version = "0.1.0", // Desenvolvimento inicial
.version = "1.0.0", // Primeiro release estável
.version = "1.2.0", // Nova feature backward compatible
.version = "2.0.0", // Breaking changes
Atualizando Dependências
Para atualizar uma dependência para uma nova versão:
# 1. Remover a dependência antiga do build.zig.zon (opcional)
# 2. Adicionar a nova versão
zig fetch --save git+https://github.com/user/repo#v2.0.0
# 3. Rebuild para usar a nova versão
zig build
Comparação com outras ferramentas:
| Ferramenta | Comando de Update |
|---|---|
| Zig | zig fetch --save <url> |
| Cargo | cargo update |
| npm | npm update |
| pip | pip install --upgrade |
Pinning de Versões
Para garantir builds reproduzíveis, sempre use versões específicas:
// ✅ Bom — versão específica
.url = "git+https://github.com/user/repo#v1.2.3",
// ✅ Bom — commit específico (ainda mais seguro)
.url = "git+https://github.com/user/repo#abc123def",
// ⚠️ Cuidado — pode quebrar a qualquer momento
.url = "git+https://github.com/user/repo#main",
// ❌ Ruim — sem controle de versão
.url = "https://example.com/latest.tar.gz",
Resolvendo Conflitos de Versão
Quando duas dependências requerem versões incompatíveis:
// Pacote A requer lib X v1.x
// Pacote B requer lib X v2.x (breaking changes)
Soluções:
- Atualizar Pacote A para versão compatível com X v2.x
- Fork e adaptar uma das dependências
- Remover uma dependência e usar alternativa
- Contribuir upstream para resolver o conflito
O Zig não tem resolução automática de conflitos — você deve gerenciá-los manualmente.
Criando Módulos Reutilizáveis
O que é um Módulo Zig?
Um módulo é uma unidade de código compilável que pode ser:
- Importada em outros projetos via
@import() - Compartilhada como dependência
- Testada isoladamente
Estrutura de uma Biblioteca (Library)
minha-lib/
├── build.zig # Configuração do build
├── build.zig.zon # Manifesto do pacote
├── src/
│ └── root.zig # Ponto de entrada da lib
├── README.md
└── LICENSE
Criando uma Biblioteca do Zero
Passo 1: Inicializar o projeto
mkdir minha-lib && cd minha-lib
zig init
Isso cria a estrutura básica incluindo src/root.zig.
Passo 2: Definir a API pública
No src/root.zig, exporte apenas o que deve ser público:
// src/root.zig
const std = @import("std");
// === API Pública ===
/// Estrutura de dados principal
pub const Config = struct {
name: []const u8,
value: i32,
};
/// Função pública
pub fn init(name: []const u8, value: i32) Config {
return .{
.name = name,
.value = value,
};
}
/// Processa a configuração
pub fn process(config: Config) !void {
std.debug.print("Processando {s}: {d}\n", .{
config.name, config.value,
});
}
// === Interno (não exportado) ===
// Funções privadas começam sem 'pub'
fn helper() void {
// implementação interna
}
// Testes inline
const testing = std.testing;
test "Config init" {
const cfg = init("teste", 42);
try testing.expectEqualStrings("teste", cfg.name);
try testing.expectEqual(42, cfg.value);
}
Passo 3: Configurar o build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// === Biblioteca ===
const lib = b.addLibrary(.{
.name = "minha-lib",
.linkage = .static, // ou .dynamic
.root_module = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
}),
});
b.installArtifact(lib);
// === Testes ===
const lib_unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
}),
});
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_lib_unit_tests.step);
}
Passo 4: Configurar o build.zig.zon
.{
.name = .@"minha-lib",
.version = "0.1.0",
.fingerprint = 0x1234abcd,
.minimum_zig_version = "0.15.0",
.dependencies = .{},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
"README.md",
"LICENSE",
},
}
Múltiplos Módulos em um Pacote
Um pacote pode expor vários módulos:
// build.zig
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// Módulo principal
const lib = b.addLibrary(.{
.name = "minha-lib",
.linkage = .static,
.root_module = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
}),
});
// Módulo adicional: utils
const utils_mod = b.createModule(.{
.root_source_file = b.path("src/utils.zig"),
.target = target,
.optimize = optimize,
});
lib.root_module.addImport("utils", utils_mod);
// Módulo adicional: crypto
const crypto_mod = b.createModule(.{
.root_source_file = b.path("src/crypto.zig"),
.target = target,
.optimize = optimize,
});
lib.root_module.addImport("crypto", crypto_mod);
b.installArtifact(lib);
}
Uso no código cliente:
const minha_lib = @import("minha-lib");
const utils = @import("utils");
const crypto = @import("crypto");
Organizando um Pacote Complexo
Para bibliotecas maiores, organize assim:
minha-lib/
├── build.zig
├── build.zig.zon
├── src/
│ ├── root.zig # Re-exporta tudo
│ ├── core/
│ │ ├── mod.zig # Módulo core
│ │ ├── types.zig
│ │ └── error.zig
│ ├── io/
│ │ ├── mod.zig # Módulo io
│ │ ├── reader.zig
│ │ └── writer.zig
│ └── utils/
│ ├── mod.zig # Módulo utils
│ └── string.zig
├── tests/
│ └── integration.zig
├── examples/
│ └── basic.zig
├── README.md
└── LICENSE
src/root.zig:
// Re-exporta submódulos
pub const core = @import("core/mod.zig");
pub const io = @import("io/mod.zig");
pub const utils = @import("utils/mod.zig");
// Re-exporta tipos comuns
pub const Config = core.types.Config;
pub const Error = core.error.Error;
Dependências Remotas vs Locais
Quando Usar Cada Tipo
| Tipo | Use Quando | Exemplo |
|---|---|---|
| Remota (URL/Git) | Dependência estável, publicada | zbench, zul |
| Local (path) | Desenvolvimento simultâneo | Editando lib e app juntos |
| Local (path) | Código privado/proprietário | Libs internas da empresa |
| Local (path) | Fork temporário | Testando modificações |
Alternando entre Remoto e Local
Durante o desenvolvimento, você pode alternar:
// build.zig.zon — versão para produção
.{
.dependencies = .{
.minha_lib = .{
.url = "git+https://github.com/user/lib#v1.0.0",
.hash = "1220abc...",
},
},
}
// build.zig.zon — versão para desenvolvimento
.{
.dependencies = .{
.minha_lib = .{
.path = "../minha-lib", // Caminho local
},
},
}
Dica: Use branches Git ou comentários para gerenciar:
.{
.dependencies = .{
// Produção:
// .minha_lib = .{ .url = "...", .hash = "..." },
// Desenvolvimento:
.minha_lib = .{ .path = "../minha-lib" },
},
}
Monorepo: Múltiplos Pacotes
Estrutura típica de monorepo:
meu-monorepo/
├── packages/
│ ├── core/ # Pacote: core
│ │ ├── build.zig
│ │ ├── build.zig.zon
│ │ └── src/
│ │
│ ├── utils/ # Pacote: utils
│ │ ├── build.zig
│ │ ├── build.zig.zon
│ │ └── src/
│ │
│ └── app/ # Pacote: app (depende de core e utils)
│ ├── build.zig
│ ├── build.zig.zon # Depende de core e utils via path
│ └── src/
│
└── README.md
packages/app/build.zig.zon:
.{
.name = .@"app",
.version = "0.1.0",
.dependencies = .{
.core = .{ .path = "../core" },
.utils = .{ .path = "../utils" },
},
.paths = .{ "build.zig", "build.zig.zon", "src" },
}
Publicando Pacotes
Preparando para Publicação
Antes de publicar, verifique:
# 1. Build funciona?
zig build
# 2. Testes passam?
zig build test
# 3. Documentação atualizada?
# README.md completo
# CHANGELOG.md atualizado
# 4. Versão correta?
# build.zig.zon → .version
# 5. Arquivos necessários incluídos?
# build.zig.zon → .paths
Checklist de Qualidade
-
zig buildfunciona sem erros -
zig build testpassa todos os testes - README.md com:
- Descrição do projeto
- Instruções de instalação
- Exemplos de uso
- Documentação da API
- Licença
- CHANGELOG.md com histórico de versões
- Código documentado (doc comments com
///) - Sem arquivos desnecessários em
.paths
Distribuição
O Zig não tem um registro central de pacotes (tipo crates.io ou npm). A distribuição é feita via:
- GitHub/GitLab — Tags de release com tarballs
- Git — Referências diretas a commits/tags
- Servidor próprio — URLs de tarball
Criando um release no GitHub:
# 1. Atualizar versão no build.zig.zon
# 2. Commit
git add .
git commit -m "Release v1.0.0"
# 3. Tag
git tag v1.0.0
git push origin v1.0.0
# 4. Criar release no GitHub (interface web)
# 5. Anexar tarball gerado automaticamente pelo GitHub
URL para zig fetch:
# Usar a URL do tarball do release
zig fetch --save https://github.com/user/repo/archive/refs/tags/v1.0.0.tar.gz
# Ou usar Git diretamente
zig fetch --save git+https://github.com/user/repo#v1.0.0
Documentação com Autodoc
O Zig pode gerar documentação automaticamente:
# Gerar documentação
zig build --prefix docs/
# Ou usando zig directly
zig build-lib -femit-docs src/root.zig
Exemplo de código bem documentado:
/// Representa uma configuração de conexão.
///
/// Exemplo:
/// ```zig
/// const config = Config{
/// .host = "localhost",
/// .port = 8080,
/// };
/// ```
pub const Config = struct {
/// Endereço do servidor
host: []const u8,
/// Porta de conexão (padrão: 8080)
port: u16 = 8080,
/// Timeout em milissegundos
timeout_ms: u32 = 5000,
};
/// Inicializa uma conexão com a configuração fornecida.
///
/// Parâmetros:
/// - `allocator`: Alocador para recursos da conexão
/// - `config`: Configuração de conexão
///
/// Retorna: `Connection` ou erro
///
/// Erros possíveis:
/// - `error.InvalidHost`: Host inválido
/// - `error.ConnectionRefused`: Conexão recusada
pub fn connect(allocator: std.mem.Allocator, config: Config) !Connection {
// implementação
}
Melhores Práticas
1. Use Versões Específicas
// ✅ Bom — versão fixa
.url = "git+https://github.com/user/repo#v1.2.3",
// ⚠️ Evite — branch pode mudar
.url = "git+https://github.com/user/repo#main",
2. Mantenha o Cache Limpo
# O cache pode crescer com o tempo
# Limpe periodicamente (ou deixe o Zig gerenciar)
rm -rf ~/.cache/zig/p/
3. Documente Dependências
No README.md, liste as dependências principais:
## Dependências
- [zul](https://github.com/vsrinivas/zul) v0.3+ — Utilitários
- [zbench](https://github.com/hendriknielaender/zBench) v0.9+ — Benchmarks
4. Minimize Dependências
// ✅ Bom — poucas deps bem escolhidas
.dependencies = .{
.zul = .{ .url = "...", .hash = "..." },
},
// ⚠️ Cuidado — árvore de deps grande
// Cada dependência aumenta tempo de build e risco
5. Teste com CI
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: goto-bus-stop/setup-zig@v2
with:
version: 0.15.0
- run: zig build
- run: zig build test
6. Use Módulos para Organização
// ✅ Bom — módulos bem definidos
const json = @import("json");
const http = @import("http");
const db = @import("db");
// ❌ Ruim — tudo em um arquivo gigante
// src/main.zig com 5000 linhas
Troubleshooting
Problema: “error: HashMismatch”
Causa: O hash no build.zig.zon não corresponde ao conteúdo baixado.
Solução:
# Remover a linha .hash do build.zig.zon
# Executar para obter o hash correto
zig build --fetch
# Copiar o hash do erro e atualizar o build.zig.zon
Problema: “error: DependencyNotFound”
Causa: A dependência não foi baixada.
Solução:
# Baixar todas as dependências
zig build --fetch
# Ou force refetch
rm -rf ~/.cache/zig/p/
zig build --fetch
Problema: “error: FileNotFound” ao importar
Causa: O nome do módulo no addImport() não corresponde ao @import().
Verifique:
// build.zig
exe.root_module.addImport("minha_lib", dep.module("minha_lib"));
// ^^^^^^^^^^^^
// nome do módulo
// código.zig
const lib = @import("minha_lib");
// ^^^^^^^^^
// deve corresponder ao addImport
Problema: Build lento após adicionar deps
Causa: Muitas dependências ou compilação inicial.
Solução:
# Cache é reutilizado após primeira compilação
# Use --summary para ver o que está sendo compilado
zig build --summary all
Problema: Conflito de nomes
Causa: Dois pacotes expõem módulos com o mesmo nome.
Solução: Use aliases no build.zig:
// Renomear na importação
exe.root_module.addImport("lib_a_json", dep_a.module("json"));
exe.root_module.addImport("lib_b_json", dep_b.module("json"));
Exemplo Completo: Projeto com Dependências
Vamos criar um projeto completo que usa múltiplas dependências:
Estrutura:
meu-app/
├── build.zig
├── build.zig.zon
└── src/
└── main.zig
build.zig.zon:
.{
.name = .@"meu-app",
.version = "1.0.0",
.fingerprint = 0x12345678,
.minimum_zig_version = "0.15.0",
.dependencies = .{
// Biblioteca de utilitários
.zul = .{
.url = "git+https://github.com/vsrinivas/zul#v0.3.2",
.hash = "1220a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b",
},
// Biblioteca de benchmarking
.zbench = .{
.url = "git+https://github.com/hendriknielaender/zBench#v0.9.2",
.hash = "1220b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}
build.zig:
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
// === Dependências ===
const zul = b.dependency("zul", .{
.target = target,
.optimize = optimize,
});
const zbench = b.dependency("zbench", .{
.target = target,
.optimize = optimize,
});
// === Executável ===
const exe = b.addExecutable(.{
.name = "meu-app",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
// Adicionar módulos
exe.root_module.addImport("zul", zul.module("zul"));
exe.root_module.addImport("zbench", zbench.module("zbench"));
b.installArtifact(exe);
// === Run step ===
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
run_cmd.addArgs(args);
}
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
// === Test step ===
const unit_tests = b.addTest(.{
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
unit_tests.root_module.addImport("zul", zul.module("zul"));
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Run unit tests");
test_step.dependOn(&run_unit_tests.step);
// === Benchmark step ===
const bench_exe = b.addExecutable(.{
.name = "benchmark",
.root_module = b.createModule(.{
.root_source_file = b.path("src/benchmark.zig"),
.target = target,
.optimize = .ReleaseFast,
}),
});
bench_exe.root_module.addImport("zbench", zbench.module("zbench"));
const run_bench = b.addRunArtifact(bench_exe);
const bench_step = b.step("bench", "Run benchmarks");
bench_step.dependOn(&run_bench.step);
}
src/main.zig:
const std = @import("std");
const zul = @import("zul");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Usando zul para parsing de UUID
const uuid = try zul.UUID.parse("550e8400-e29b-41d4-a716-446655440000");
std.debug.print("UUID: {s}\n", .{uuid});
// Usando zul para StringBuilder
var builder = zul.StringBuilder.init(allocator);
defer builder.deinit();
try builder.append("Hello, ");
try builder.append("Zig Packaging!");
std.debug.print("{s}\n", .{builder.string()});
}
// Testes
const testing = std.testing;
test "UUID parsing" {
const uuid = try zul.UUID.parse("550e8400-e29b-41d4-a716-446655440000");
try testing.expectEqual(uuid, uuid);
}
Comandos:
# Build
zig build
# Run
zig build run
# Test
zig build test
# Benchmark
zig build bench
# Ver dependências
zig build --fetch
ls ~/.cache/zig/p/
Resumo
O Zig Package Manager oferece um sistema de gerenciamento de dependências:
| Aspecto | Implementação Zig |
|---|---|
| Manifesto | build.zig.zon (ZON format) |
| Adicionar deps | zig fetch --save <url> |
| Cache | Content-addressable em ~/.cache/zig/ |
| Uso no código | b.dependency() + addImport() |
| Módulos | b.createModule() + addImport() |
| Versões | Semver + hashes de integridade |
| Publicação | Tags Git + releases GitHub |
Comparação com outras linguagens:
| Zig | Rust | Node.js | Python | |
|---|---|---|---|---|
| Manifesto | build.zig.zon | Cargo.toml | package.json | pyproject.toml |
| Registry | Nenhum (URLs diretas) | crates.io | npm.org | PyPI |
| Lockfile | Implícito (hashes) | Cargo.lock | package-lock.json | poetry.lock |
| Offline | ✅ Sim | ✅ Sim | ✅ Sim | ✅ Sim |
O Zig escolhe simplicidade sobre features complexas: sem registro central, sem árvore de dependências complexa, apenas URLs e hashes.
Próximos Passos
Agora que você domina o sistema de pacotes do Zig:
- 📦 Zig Build System: Guia Completo — Aprofunde no
build.zig - ⚡ Comptime em Zig — Metaprogramação avançada
- 🌐 Zig WebAssembly — Compile para WASM
- 🔍 Documentação oficial de Packaging — Referência completa
Explore a lista de pacotes Zig para descobrir bibliotecas úteis.
Tem dúvidas sobre Zig Packaging? Compartilhe com a comunidade Zig Brasil!