← Volver al listado de tecnologías

Build System en Zig

Por: Artiko
zigbuildbuild.zigdependencias

Build System

Estructura de Proyecto

mi-proyecto/
├── build.zig           # Configuración de build
├── build.zig.zon       # Dependencias (Zig 0.11+)
├── src/
│   ├── main.zig        # Punto de entrada
│   ├── lib.zig         # Biblioteca
│   └── utils/
│       └── helpers.zig
└── tests/
    └── test_lib.zig

Build.zig Básico

const std = @import("std");

pub fn build(b: *std.Build) void {
    // Opciones de compilación
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Crear ejecutable
    const exe = b.addExecutable(.{
        .name = "mi-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Instalar el ejecutable
    b.installArtifact(exe);

    // Paso para ejecutar
    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());

    // Si hay argumentos de línea de comandos
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    // Crear step "run"
    const run_step = b.step("run", "Ejecutar la aplicación");
    run_step.dependOn(&run_cmd.step);

    // Tests
    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", "Ejecutar tests");
    test_step.dependOn(&run_unit_tests.step);
}

Compilar y Ejecutar

# Build
zig build

# Ejecutar
zig build run

# Tests
zig build test

# Con argumentos
zig build run -- arg1 arg2

# Release
zig build -Doptimize=ReleaseFast

# Cross-compile
zig build -Dtarget=x86_64-linux-gnu
zig build -Dtarget=aarch64-macos
zig build -Dtarget=x86_64-windows-gnu

Build con Biblioteca

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Crear biblioteca estática
    const lib = b.addStaticLibrary(.{
        .name = "mi-lib",
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Crear biblioteca compartida
    const shared_lib = b.addSharedLibrary(.{
        .name = "mi-lib",
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Instalar bibliotecas
    b.installArtifact(lib);
    b.installArtifact(shared_lib);

    // Ejecutable que usa la biblioteca
    const exe = b.addExecutable(.{
        .name = "mi-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Linkear biblioteca
    exe.linkLibrary(lib);

    b.installArtifact(exe);
}

Dependencias con build.zig.zon

// build.zig.zon
.{
    .name = "mi-proyecto",
    .version = "0.1.0",
    .dependencies = .{
        .@"zig-network" = .{
            .url = "https://github.com/example/zig-network/archive/refs/tags/v0.1.0.tar.gz",
            .hash = "1234567890abcdef...",
        },
        .local_dep = .{
            .path = "../otra-biblioteca",
        },
    },
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
    },
}
// build.zig con dependencias
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Obtener dependencia
    const network_dep = b.dependency("zig-network", .{
        .target = target,
        .optimize = optimize,
    });

    const exe = b.addExecutable(.{
        .name = "mi-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Agregar módulo de dependencia
    exe.root_module.addImport("network", network_dep.module("network"));

    b.installArtifact(exe);
}

Opciones Personalizadas

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Opción booleana
    const enable_logging = b.option(
        bool,
        "logging",
        "Habilitar logging detallado",
    ) orelse false;

    // Opción string
    const config_path = b.option(
        []const u8,
        "config",
        "Ruta al archivo de configuración",
    ) orelse "config.json";

    const exe = b.addExecutable(.{
        .name = "mi-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Pasar opciones como defines
    const options = b.addOptions();
    options.addOption(bool, "enable_logging", enable_logging);
    options.addOption([]const u8, "config_path", config_path);

    exe.root_module.addOptions("config", options);

    b.installArtifact(exe);
}
// src/main.zig - usar opciones
const std = @import("std");
const config = @import("config");

pub fn main() void {
    if (config.enable_logging) {
        std.debug.print("Logging habilitado\n", .{});
    }
    std.debug.print("Config: {s}\n", .{config.config_path});
}

Linkear con C

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "mi-app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Linkear libc
    exe.linkLibC();

    // Linkear biblioteca del sistema
    exe.linkSystemLibrary("m");      // libm
    exe.linkSystemLibrary("pthread"); // pthread
    exe.linkSystemLibrary("ssl");     // openssl

    // Agregar rutas de include
    exe.addIncludePath(b.path("include"));
    exe.addIncludePath(.{ .cwd_relative = "/usr/local/include" });

    // Agregar rutas de bibliotecas
    exe.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" });

    // Compilar archivo C
    exe.addCSourceFile(.{
        .file = b.path("src/helper.c"),
        .flags = &.{ "-Wall", "-O2" },
    });

    b.installArtifact(exe);
}

Testing Avanzado

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Tests unitarios
    const unit_tests = b.addTest(.{
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Tests de integración
    const integration_tests = b.addTest(.{
        .root_source_file = b.path("tests/integration.zig"),
        .target = target,
        .optimize = optimize,
    });

    const run_unit_tests = b.addRunArtifact(unit_tests);
    const run_integration_tests = b.addRunArtifact(integration_tests);

    // Step para todos los tests
    const test_step = b.step("test", "Ejecutar todos los tests");
    test_step.dependOn(&run_unit_tests.step);
    test_step.dependOn(&run_integration_tests.step);

    // Step solo para tests unitarios
    const unit_test_step = b.step("test-unit", "Solo tests unitarios");
    unit_test_step.dependOn(&run_unit_tests.step);

    // Step solo para integración
    const int_test_step = b.step("test-integration", "Solo tests de integración");
    int_test_step.dependOn(&run_integration_tests.step);
}

Ejemplo Completo

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Biblioteca
    const lib = b.addStaticLibrary(.{
        .name = "milib",
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    });

    // Ejecutable principal
    const exe = b.addExecutable(.{
        .name = "miapp",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    exe.linkLibrary(lib);
    b.installArtifact(exe);

    // Run
    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", "Ejecutar");
    run_step.dependOn(&run_cmd.step);

    // Tests
    const lib_tests = b.addTest(.{
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    });

    const test_step = b.step("test", "Tests");
    test_step.dependOn(&b.addRunArtifact(lib_tests).step);

    // Documentación
    const docs = b.addStaticLibrary(.{
        .name = "milib",
        .root_source_file = b.path("src/lib.zig"),
        .target = target,
        .optimize = optimize,
    });

    const install_docs = b.addInstallDirectory(.{
        .source_dir = docs.getEmittedDocs(),
        .install_dir = .prefix,
        .install_subdir = "docs",
    });

    const docs_step = b.step("docs", "Generar documentación");
    docs_step.dependOn(&install_docs.step);
}

Comandos Útiles

# Ver opciones disponibles
zig build --help

# Listar todos los steps
zig build --help

# Build con opciones
zig build -Doptimize=ReleaseFast -Dlogging=true

# Limpiar
rm -rf zig-out .zig-cache

# Formatear código
zig fmt src/

# Obtener hash de dependencia
zig fetch https://github.com/example/lib/archive/v1.0.tar.gz

Ejercicios

  1. Crea un proyecto con biblioteca y ejecutable separados
  2. Agrega una dependencia externa y úsala en tu código
  3. Configura cross-compilation para Windows desde Linux

Resumen