Perguntas de Entrevista sobre o Build System de Zig
O build system de Zig é reconhecido como um dos mais elegantes e poderosos entre linguagens de sistemas. Diferente de Make, CMake ou Cargo, o build system de Zig é um programa Zig completo, permitindo lógica arbitrária de build sem linguagens adicionais. Entrevistadores testam esse conhecimento especialmente para posições de DevOps e infraestrutura.
Perguntas Fundamentais
Como funciona o build system de Zig?
O build system de Zig é baseado em build.zig, um arquivo Zig que define o grafo de build. É executado em tempo de compilação usando o compilador Zig como runtime. Comandos como zig build executam a função pub fn build() em build.zig.
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "meu-app",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
const run_step = b.step("run", "Executar o aplicativo");
run_step.dependOn(&run_cmd.step);
}
Explique cross-compilation em Zig.
Zig pode compilar para qualquer target suportado sem toolchains adicionais. Basta especificar o target na linha de comando ou no build.zig:
zig build -Dtarget=aarch64-linux-gnu
zig build -Dtarget=x86_64-windows-msvc
zig build -Dtarget=wasm32-wasi
Isso é possível porque Zig inclui internamente os headers de libc para múltiplas plataformas e usa LLVM como backend. É especialmente valioso para embedded e DevOps.
Como integrar código C no build system?
const exe = b.addExecutable(.{ .name = "app", .root_source_file = b.path("src/main.zig") });
exe.addCSourceFiles(.{
.files = &.{ "src/legacy.c", "src/utils.c" },
.flags = &.{ "-Wall", "-O2" },
});
exe.linkLibC();
exe.addIncludePath(b.path("include"));
Zig pode compilar C e Zig no mesmo build, facilitando migração gradual de C para Zig. Veja interop com C para mais detalhes.
Como funciona o gerenciador de pacotes?
O package manager de Zig usa build.zig.zon para declarar dependências:
// build.zig.zon
.{
.name = "meu-projeto",
.version = "0.1.0",
.dependencies = .{
.httpz = .{
.url = "https://github.com/...",
.hash = "...",
},
},
}
E em build.zig, as dependências são importadas e linkadas ao build.
Perguntas Avançadas
Quais são os níveis de otimização e quando usar cada um?
- Debug: Sem otimizações, símbolos de debug, safety checks ativados. Use durante desenvolvimento.
- ReleaseSafe: Otimizações com safety checks mantidos. Bom para produção com diagnóstico.
- ReleaseFast: Máxima performance, sem safety checks. Use quando performance é prioridade absoluta.
- ReleaseSmall: Menor tamanho de binário. Ideal para embedded e WASM.
Como criar steps customizados no build?
const gen_step = b.addSystemCommand(&.{ "python3", "gen_code.py" });
exe.step.dependOn(&gen_step.step);
Steps customizados permitem integrar geradores de código, processadores de assets e qualquer ferramenta externa no pipeline de build.
Como escrever e executar testes com o build system?
O build system de Zig tem suporte nativo a testes. No build.zig, adicione um step de teste:
const unit_tests = b.addTest(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const run_unit_tests = b.addRunArtifact(unit_tests);
const test_step = b.step("test", "Executar testes unitários");
test_step.dependOn(&run_unit_tests.step);
Execute com zig build test. O sistema de build descobre automaticamente todos os blocos test nos arquivos Zig incluídos, sem necessidade de registrar cada teste individualmente. Em entrevistas, demonstre que você sabe integrar testes ao pipeline de build e usar --test-filter para executar testes específicos.
Como publicar e consumir bibliotecas com o gerenciador de pacotes?
O fluxo completo de consumo de pacotes em Zig:
# 1. Adicionar dependência ao build.zig.zon
# 2. Obter o hash do pacote
zig fetch --save https://github.com/autor/lib/archive/commit.tar.gz
// build.zig — importar e usar a dependência
const dep = b.dependency("nome_lib", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("nome_lib", dep.module("nome_lib"));
O gerenciador de pacotes de Zig é baseado em hashes criptográficos de conteúdo, garantindo builds reproduzíveis. Não existe um registry central — qualquer URL de arquivo tar.gz serve como fonte de pacote, incluindo releases do GitHub.
Perguntas de Diagnóstico
Como debugar problemas no build.zig?
- Use
b.verbosepara logs detalhados:zig build --verbose - Inspecione o grafo de dependências:
zig build --summary all - Para steps que falham silenciosamente, adicione
step.expectExitCode(0)explicitamente - O
std.debug.printfunciona normalmente dentro dobuild.zigdurante a execução
Qual a diferença entre b.path() e caminhos literais no build.zig?
Em versões recentes do Zig, todos os caminhos de arquivo dentro do build.zig devem ser criados via b.path("caminho/relativo") em vez de strings literais. Isso garante que o build system possa rastrear dependências de arquivos corretamente e invalidar caches quando arquivos mudam. Usar strings literais diretamente pode resultar em builds que não detectam mudanças em arquivos de entrada e, portanto, não recompilam quando deveriam. Esse é um erro comum ao migrar build.zig de versões mais antigas do Zig para versões mais recentes, onde a API se tornou mais rigorosa sobre o gerenciamento de paths.
Complemente com o estudo do ecossistema de build e pratique com projetos e tutoriais.