Ejemplo de uso de una librería: argonaut
Vamos a usar una librería para añadir una funcionalidad muy común cuando creamos herramientas de línea de comandos: parsear argumentos.
En https://zigistry.dev/ puedes buscar librerías de todo tipo. De ahí he elegido una que me ha parecido intuitiva para este propósito:
Se llama argonaut: https://codeberg.org/OhMyDitzzy/argonaut.
La descripción de la librería a fecha de diciembre de 2025 es la siguiente:
Resumen
Un parser de argumentos de línea de comandos flexible y potente para Zig, inspirado en la librería argparse de Go. Ofrece una API clara e intuitiva para construir aplicaciones CLI complejas, con soporte para subcomandos, varios tipos de argumentos, validación y más.
Características
- Tipos de argumentos múltiples: flags, contadores, cadenas, enteros, flotantes, ficheros y listas
- Subcomandos: permite construir herramientas CLI con comandos anidados (como git)
- Argumentos posicionales: compatibilidad con argumentos posicionales junto a flags con nombre
- Validación: funciones de validación personalizadas para argumentos
- Valores por defecto: asignación de valores por defecto a argumentos opcionales
- Argumentos tipo selector: restringe los valores posibles a un conjunto predefinido
- Ayuda automática: generación de ayuda integrada con formato personalizable
- Tipado seguro: manejo de argumentos totalmente type-safe
- Diseño modular: separación clara de responsabilidades para facilitar el mantenimiento
Instalación
Añade la dependencia en tu build.zig.zon ejecutando el siguiente comando:
zig fetch --save=argonaut
https://codeberg.org/OhMyDitzzy/argonaut/archive/master.tar.gz
Luego, en tu build.zig:
|
exe.root_module.addImport( "argonaut", b.dependency("argonaut", .{ .target = target, .optimize = optimize }).module("argonaut")); |
Una vez que hemos leído la descripción de la librería vamos a crear nuestro programa que llamaremos argdemo:
mkdir argdemo;
cd argdemo;
zig init --minimal
Zig creará una configuración mínima. Inmediatamente después, modificamos los ficheros build.zig.zon y build.zig.
Como hemos visto del README.md de la librería ejecutamos:
zig fetch --save=argonaut https://codeberg.org/OhMyDitzzy/argonaut/archive/master.tar.gz
Este comando bajará la librería y modificará el fichero build.zig.zon
Ficheros de configuración y el programa
build.zig.zon
|
.{ .name = .argdemo, .version = "0.0.1", .dependencies = .{ .argonaut = .{ .url = "https://codeberg.org/…", .hash = "...", }, }, .minimum_zig_version = "0.15.2", .paths = .{ "build.zig", "build.zig.zon", "src", }, .fingerprint = <aquí zig genera un fingerprint>, } |
Zig fetch anotará como dependencia la librería pero nosotros necesitamos poner los .paths de los ficheros.
build.zig
|
const std = @import("std"); pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const exe = b.addExecutable(.{ .name = "argdemo", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, }), }); exe.root_module.addImport("argonaut", b.dependency("argonaut", .{ .target = target, .optimize = optimize, }).module("argonaut")); b.installArtifact(exe); const run_step = b.step("run", "Run the app"); const run_cmd = b.addRunArtifact(exe); if (b.args) |args| { run_cmd.addArgs(args); } run_step.dependOn(&run_cmd.step); run_cmd.step.dependOn(b.getInstallStep()); } |
Después de modificar estos ficheros creamos el archivo de código fuente del propio programa src/main.zig:
src/main.zig
|
const std = @import("std"); const print = std.debug.print; // Seguimos las instrucciones del repositorio de argonaut const argsparse = @import("argonaut"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); // Create a parser with a program name and description const parser = try argsparse.newParser( allocator, "Argdemo", "Aplicación de prueba", ); defer parser.deinit(); var name_opts = argsparse.Options{ .required = true, .help = "Tu nombre", }; const s_name = try parser.string( "n", "name", &name_opts, ); // creamos una función para validar la edad const fn_validate_age = struct { // *const fn (args: []const []const u8) anyerror!void; fn _(args: []const []const u8) !void { if (args.len == 0 or args.len > 1) return; const n_age = std.fmt.parseInt( i64, args[0], 10, ) catch return error.InvalidNumber; if (n_age < 18) return error.AgeTooLow else if (n_age > 120) return error.AgeTooHigh else return; } }._; var age_opts = argsparse.Options{ .required = false, .help = "Tu edad como número. Solo se acepta entre 18 y 120", .default_int = 33, .validate = fn_validate_age, }; const n_age = try parser.int( "a", "age", &age_opts, ); const args = try std.process.argsAlloc(allocator); defer std.process.argsFree(allocator, args); _ = parser.parse(args) catch { const usage_text = try parser.usage(null); defer allocator.free(usage_text); std.debug.print("{s}", .{usage_text}); std.process.exit(1); }; print("Hola: {s}, tu edad: {d} \n", .{ s_name.*, n_age.*, }); } |
El uso de la librería es sencillo si seguimos las instrucciones de la propia página del repositorio. Importamos la librería igual que hacemos habitualmente con std.
Copiamos el código tal y como viene explicado en el repositorio para un uso básico de argonaut:
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); const allocator = gpa.allocator(); // Create a parser with a program name and description const parser = try argsparse.newParser( allocator, "Argdemo", "Aplicación de prueba", ); defer parser.deinit(); |
La única parte más “complicada” es si queremos crear una función de validación (muy parecido a lo que hemos visto en los capítulos anteriores:
|
// creamos una función para validar la edad const fn_validate_age = struct { // *const fn (args: []const []const u8) anyerror!void; fn _(args: []const []const u8) !void { // ... }._; var age_opts = argsparse.Options{ .validate = fn_validate_age }; |
Cuando ejecutamos el programa obtenemos:
|
$ zig build && zig-out/bin/argdemo --name Ziguana --age 140 |
|
usage: Argdemo [-a|--age <integer>] -n|--name "<value>" [-h|--help] Aplicación de prueba Arguments: -a --age Tu edad como número. Solo se acepta entre 18 y 120. Default: 33 -n --name Tu nombre -h --help Print help information |