En Zig, la construcción de proyectos se gestiona a través de un archivo especial llamado build.zig. Este archivo actúa como una especie de “script” que le indica al compilador cómo compilar, enlazar y empaquetar tu código. En lugar de usar un archivo de configuración estático (por ejemplo, un Makefile), Zig ofrece un lenguaje de programación completo para describir los pasos de construcción, lo que brinda flexibilidad y expresividad.
¿Dónde se ubica el archivo?
El archivo build.zig debe colocarse en la raíz del proyecto. Cuando ejecutas zig build desde la línea de comandos, Zig busca este archivo para determinar los objetivos disponibles.
El flujo de trabajo básico
- Inicializas un
Buildconconst b = Build.create(arena);. - Definir los objetivos:
const exe = b.addExecutable("mi_programa", "src/main.zig");. - Configuras opciones de compilación y enlazado.
- Finalizas con
b.install(exe);y llamas areturn b.default_step;.
Estructura típica del archivo build.zig
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
// 1. Creación de una instancia de Build
// El parámetro 'b' es un puntero a la estructura Build proporcionada por Zig.
// No se necesita crear una nueva instancia; Zig ya la proporciona cuando invocas 'zig build'.
// 2. Definir el objetivo principal: un ejecutable
const exe = b.addExecutable("hola_mundo", "src/main.zig");
// 'addExecutable' recibe dos argumentos:
// - Nombre del ejecutable que se generará (por ejemplo, 'hola_mundo')
// - Ruta al archivo fuente principal (en este caso, 'src/main.zig')
// 3. Configurar opciones de compilación (opcional)
exe.setBuildMode(b.standardReleaseOptions()); // Usa modo de lanzamiento por defecto
// 'setBuildMode' permite elegir entre Debug, ReleaseSafe, ReleaseFast, etc.
// 4. Añadir dependencias (si las hubiera)
// Ejemplo: agregar una librería externa 'mylib'
// const lib = b.addStaticLibrary("mylib", "lib/mylib.zig");
// exe.linkLibrary(lib);
// 5. Instalar el ejecutable (para 'zig build install')
b.installArtifact(exe);
// 6. Exponer el paso de construcción por defecto
// Cuando el usuario ejecuta 'zig build', este paso se ejecutará.
return b.default_step;
}
Comandos útiles relacionados con el build system
zig build– Compila el proyecto utilizando el paso por defecto definido enbuild.zig.zig build -Dverbose– Muestra información detallada del proceso de compilación.zig build clean– Elimina los artefactos generados en el directoriozig-out.zig build -Droot-dir=./build– Cambia el directorio de salida a./build.
Definiendo múltiples objetivos en un proyecto
Es común que un proyecto contenga más de un binario, una librería y quizá pruebas unitarias. El siguiente ejemplo muestra cómo declarar varios objetivos en un solo build.zig.
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
// 1. Binario principal
const app = b.addExecutable("app_principal", "src/app.zig");
app.setBuildMode(b.standardReleaseOptions());
b.installArtifact(app);
// 2. Binario auxiliar (por ejemplo, una herramienta CLI)
const helper = b.addExecutable("herramienta_cli", "src/cli.zig");
helper.setBuildMode(b.standardReleaseOptions());
b.installArtifact(helper);
// 3. Biblioteca estática
const lib = b.addStaticLibrary("mi_libreria", "lib/lib.zig");
lib.setBuildMode(b.standardReleaseOptions());
b.installArtifact(lib);
// 4. Tests
const test_step = b.step("test", "Ejecuta las pruebas");
const test = b.addTest("tests/test_suite.zig");
test.setBuildMode(b.standardReleaseOptions());
test_step.dependOn(&test.step);
}
Integrando dependencias externas
Zig permite incluir paquetes externos a través de la sección dependencies en el build.zig. Aquí tienes un ejemplo con la biblioteca zls (Zig Language Server).
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
// 1. Añadir dependencia externa
const zls = b.dependency("zls", .{
.target = b.standardTargetOptions(.{}),
.use_llvm = true,
});
// 2. Usar la dependencia en un binario
const exe = b.addExecutable("mi_app", "src/main.zig");
exe.root_source_file = &b.path("src/main.zig");
exe.addIncludePath(zls.include_dirs.get(0)); // Incluye los headers
exe.linkLibrary(zls.artifact("zls").handle); // Enlaza la librería
b.installArtifact(exe);
}
Personalizando la salida y las opciones de enlazado
El sistema de construcción permite configurar la carpeta de salida y las opciones del enlazador.
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
const exe = b.addExecutable("salida_custom", "src/main.zig");
// Cambiar el directorio de salida
exe.setOutputDir(b.path("build/bin"));
// Agregar argumentos personalizados al enlazador
exe.linkSystemLibrary("m"); // enlaza con la librería math
exe.linkSystemLibrary("c"); // enlaza con la librería C estándar
b.installArtifact(exe);
}
Ejemplo completo: proyecto con tests y documentación
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) !void {
// 1. Ejecutable principal
const app = b.addExecutable("mi_aplicacion", "src/main.zig");
app.setBuildMode(b.standardReleaseOptions());
b.installArtifact(app);
// 2. Tests unitarios
const test_step = b.step("test", "Ejecuta los tests");
const test = b.addTest("tests/main_test.zig");
test.setBuildMode(b.standardReleaseOptions());
test_step.dependOn(&test.step);
// 3. Generar documentación con `zig build docs`
const docs_step = b.step("docs", "Genera la documentación");
const docs = b.addRunCommand("docs", &[_][]const u8{
"zig",
"build",
"--help",
});
docs_step.dependOn(&docs.step);
}
Conclusiones
El archivo build.zig ofrece un enfoque programático para la construcción
