Crear un proyecto: zig init

Crear un proyecto: zig init

Para crear la estructura de un proyecto o también llamado paquete (package) - , creamos un directorio, nos situamos dentro y tecleamos simplemente zig init:


zig init 


O, si queremos una versión más minimalista de la configuración:


zig init  --minimal 


Zig creará la estructura del proyecto. Si usamos la versión no mínima, veremos que se han generado los siguientes ficheros. Puedes usar el comando tree si estás en la shell para ver recursivamente los ficheros:

$ tree

├── build.zig

├── build.zig.zon

└── src

    ├── main.zig

    └── root.zig

build.zig.zon

Todos estos archivos generados son ficheros zig, excepto build.zig.zon. Si lo abres seguro que te recuerda a los ficheros JSON (JavaScript Object Notation), pero en realidad es un concepto parecido: ZON (Zig Object Notation) - es una notación propia de Zig. Consiste en sintaxis declarativa inspirada en structs y si lo abres te darás cuenta de que tiene mucho en común con ellos:

build.zig.zon

.{

    .name = .nombre_del_paquete,

    // Esta es una [Versión Semántica](https://semver.org/).

    .version = "0.0.0",

    // Junto con el nombre, representa

    // un identificador globalmente único del paquete.

    .fingerprint = 0x…, 

    // Cambiar esto tiene implicaciones de seguridad y confianza.

    // Indica la versión mínima de Zig que este paquete considera soportada.

    .minimum_zig_version = "0.15.2",

    // Este campo es opcional.

    // Cada dependencia debe proporcionar unq `url`

    // y un `hash`, o bien un `path`.

    // `zig build --fetch` se puede usar para

    // descargar todas las dependencias

    // de un paquete, de forma recursiva.

    // Una vez descargadas, `zig build` ya no necesita conexión a internet.

    .dependencies = .{

        // dependencias

    },

    // Especifica el conjunto de archivos y directorios

    // incluidos en este paquete.

    // Solo los archivos y carpetas listados aquí se incluyen en el `hash`

    // que se calcula para el paquete.

    .paths = .{

        "build.zig",

        "build.zig.zon",

        "src",

        // Por ejemplo...

        //"LICENSE",

        //"README.md",

    },

}

Estos ficheros generados por zig init se pueden hacer a mano, siempre que sigamos unas pautas de formatos.

build.zig.zon contiene una estructura donde declaramos los metadatos del package.  Estos datos son leídos por Zig como datos tipados en tiempo de compilación.

El primer dato es el nombre del paquete y tiene la peculiaridad de tener un . (punto) delante el nombre. El nombre del paquete zig init lo crea a partir del nombre del directorio que hemos creado previamente para el paquete. Si lo haces a mano recuerda sustituir los espacios por _ (guiones bajos). Tampoco deberías poner caracteres no alfanuméricos en el nombre y además tienen que ser sin tildes.

En el campo .dependencies pondrás las dependencias externas del proyecto en el caso de que existan y en el caso de que no uses ninguna lo puedes dejar vacío. Probablemente llegues a usar alguna dependencia de todas maneras.

En el campo .paths se pondrán todos los ficheros y directorios que queremos incluir en el paquete.

Si no hubieras visto structs de Zig previamente, pensarías - vaya JSON más raro y ¿para qué lo habrán hecho así? Y es lo que le pasa a mucha gente que a diferencia de ti empieza por el Zig Build System en vez de por aprender el lenguaje primero.

src

En cuanto al código fuente generado, hay dos ficheros:

Esto quiere decir que si nuestro ejecutable no va a tener una parte de librería que puedan usar otros paquetes podemos quitar root.zig y si hacemos una librería que no va a tener un ejecutable propio podemos quitar main.zig. Básicamente root.zig sería un hub para exponer las funcionalidades tipo librería a otros paquetes.

build.zig

El fichero build.zig contiene las instrucciones para compilar el proyecto. Zig no ejecuta directamente este fichero cuando lanzamos zig build: lo usa para crear un grafo (una estructura de datos) que usa para definir las características y los pasos de compilación.

Por eso precisamente, lo más importante de este fichero es la función build:

fn build

 // necesitamos esta función para poder construir el paquete

 pub fn build(b: *std.Build) void {

Esta función no ejecuta la compilación, sino que muta el objeto que se le pasa como parámetro. Ese parámetro b es el builder - un struct especial con métodos para configurar la compilación paso a paso.

Dentro de esta función build si creamos el proyecto con la versión no mínima veremos que hay varios comandos - llamadas a los métodos del builder.

target: plataforma para la que compilamos

Se define el target: la plataforma para la cual se compila el ejecutable. Por defecto se compila para tu máquina actual.

  const target = b.standardTargetOptions(.{});

Yo, por ejemplo, uso linux, pero si quisiera compilar un ejecutable para windows podría escribir lo siguiente:

  

  const target = b.standardTargetOptions(.{ 

    .default_target = .{

        .cpu_arch = .x86_64,

        .os_tag = .windows,

    } 

  });

optimize: nivel de optimización

Aquí definimos las opciones del nivel de optimización. Por defecto ese nivel es Debug.

  const optimize = b.standardOptimizeOption(.{});

Si queremos, por ejemplo, crear un ReleaseSmall escribimos:

  const optimize = b.standardOptimizeOption(.{

        .preferred_optimize_mode = .ReleaseSmall,

    });

el ejecutable

Definimos el ejecutable que se va a crear, usando las especificaciones previas

  const exe = b.addExecutable(.{

        .name = "nombre_paquete",

        .root_module = b.createModule(.{

          .root_source_file = b.path("src/main.zig"),

          .target = target,

          .optimize = optimize,

        }),

    });

Declaramos que el exe será instalado. Por defecto se usará el subdirectorio zig-out pero se puede pasar --prefix o -p como argumento para usar otra ruta.

  b.installArtifact(exe);

Pasos de construcción

Zig Build System funciona con pasos. Cada uno de esos pasos representa una tarea. Por defecto zig init ha creado un paso llamado run_step. Este paso compila y ejecuta:

  const run_step = b.step("run", "Run the app");

  const run_cmd = b.addRunArtifact(exe);

  run_step.dependOn(&run_cmd.step);

  run_cmd.step.dependOn(b.getInstallStep());

Cuando ejecutas zig build run, Zig sigue la cadena de dependencias: instala ese ejecutable y lo ejecuta.

Los tests

  const exe_tests = b.addTest(.{

    .root_module = exe.root_module,

  });

  const run_exe_tests = b.addRunArtifact(exe_tests);

  const test_step = b.step("test", "Run tests");

  test_step.dependOn(&run_exe_tests.step);

Esto busca y ejecuta los bloques test en el código.

Compilar programas en Zig
Ejemplo de uso de una librería: argonaut
© 2025 Zen of Zig