En Zig, la fase de construcción se organiza mediante un sistema de steps (pasos). Cada paso representa una tarea concreta: compilar un archivo, enlazar un binario, generar un recurso, etc. Para que estas tareas se ejecuten en el orden correcto, Zig ofrece la función dependOn, la cual declara explícitamente dependencias entre los pasos.
¿Qué es un Build Step?
Un build step en Zig es una unidad de trabajo que el sistema de construcción ejecuta. Se representa mediante la estructura Build.Step y puede ser cualquier cosa: compilar un archivo .zig, enlazar un ejecutable, copiar archivos de recursos, etc. Cuando se crea un paso, Zig automáticamente lo registra en el árbol de dependencias, pero a veces necesitamos establecer una relación más explícita.
La función dependOn
dependOn es un método que se invoca en un paso para indicar que dicho paso debe esperar a que otro paso finalice antes de comenzar. La sintaxis es sencilla:
stepA.dependOn(&stepB);
Esto garantiza que stepB se ejecutará antes que stepA. Si el paso dependiente falla, el paso que lo llama también fallará.
¿Por qué usar dependOn?
- Control explícito del orden de ejecución.
- Evitar errores de compilación por dependencias no resueltas.
- Optimizar el tiempo de construcción al paralelizar pasos sin dependencias.
Sintaxis y ejemplos
Ejemplo 1: Compilar un ejecutable que depende de una librería
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
// 1. Crear un paso para compilar la librería
const lib = b.addStaticLibrary("myLib", "src/lib.zig");
lib.setBuildMode(.ReleaseSafe);
// 2. Crear un paso para compilar el binario principal
const exe = b.addExecutable("myApp", "src/main.zig");
exe.setBuildMode(.ReleaseSafe);
// 3. Añadir la librería como dependencia del ejecutable
// Aquí es donde usamos dependOn
exe.dependOn(&lib.step);
// 4. Indicar que el binario final debe ser instalado
exe.install();
}
**Explicación línea por línea**:
const std = @import("std");– Importa la biblioteca estándar de Zig, necesaria para acceder al tipoBuildy sus métodos.pub fn build(b: *std.Build) void {– Entrada estándar del fichero de construcción.const lib = b.addStaticLibrary(...);– Crea un paso que compilará una biblioteca estática llamadamyLibdesdesrc/lib.zig.lib.setBuildMode(.ReleaseSafe);– Define el modo de compilación.const exe = b.addExecutable(...);– Crea un paso que compilará un ejecutable llamadomyApp.exe.dependOn(&lib.step);– Declara que el paso de la biblioteca debe completarse antes de que el ejecutable comience a compilar.exe.install();– Indica que el binario debe copiarse al directorioinstalltras la construcción.}– Cierre de la función build.
Ejemplo 2: Generar código antes de compilar
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
// Paso 1: Generar un fichero .zig a partir de JSON
const genStep = b.addSystemCommand("python");
genStep.addArgs("generate_code.py");
// Paso 2: Compilar el módulo generado
const mod = b.addModule("generated", .{ .root_source_file = genStep.result_file });
// Paso 3: Compilar el programa principal
const exe = b.addExecutable("app", "src/main.zig");
exe.addModule("generated", mod);
// Paso 4: Declarar dependencias explícitas
exe.dependOn(&genStep.step);
// Paso 5: Instalar
exe.install();
}
**Detalles de cada línea**:
const genStep = b.addSystemCommand("python");– Crea un paso que ejecutará el intérprete de Python.genStep.addArgs("generate_code.py");– Añade el script Python que generará el ficherogenerated.zig.const mod = b.addModule("generated", .{ .root_source_file = genStep.result_file });– Crea un módulo Zig que se basa en el archivo generado por el paso anterior.exe.addModule("generated", mod);– Incluye el módulo generado en el ejecutable.exe.dependOn(&genStep.step);– Garantiza que el código generado esté disponible antes de compilar el ejecutable.exe.install();– Instala el binario después de la compilación.
Ejemplo 3: Dependencias entre tests
// build.zig
const std = @import("std");
pub fn build(b: *std.Build) void {
// Paso A: Compilar la librería de pruebas
const testLib = b.addStaticLibrary("testLib", "src/test_lib.zig");
// Paso B: Compilar el binario de prueba
const testExe = b.addTest("src/tests.zig");
// Paso C: Asegurarse de que la librería de prueba se compile primero
testExe.dependOn(&testLib.step);
// Paso D: Ejecutar la prueba
const runTest = b.addRunArtifact(testExe);
// Paso E: Agregar al objetivo default
b.defaultStep.dependOn(&runTest.step);
}
**Notas**:
- El método
addTestcrea un paso que compila un módulo de prueba. - Al declarar
testExe.dependOn(&testLib.step), Zig se asegura de que la librería de prueba esté lista antes de compilar el binario de prueba. - El paso
runTestejecuta el binario de prueba, y se añade como dependencia del paso por defecto.
