En Zig, @import es la única forma de incorporar código de otros archivos o paquetes dentro de tu proyecto. Esta directiva es análoga a la inclusión de encabezados en C, pero con la ventaja de ser estática y compilada en tiempo de construcción. A continuación se explica paso a paso cómo usarla para librerías externas, cómo configurarlo en build.zig y cuáles son las buenas prácticas.
1. Comprendiendo la directiva @import
@import("path/to/module.zig") busca el archivo module.zig en la ruta relativa a la ubicación del archivo que la invoca. El compilador devuelve el paquete resultante, que puede contener funciones, estructuras y constantes. El paquete se usa con la sintaxis de punto.
- El archivo importado debe ser válido en el momento de la compilación.
- La ruta puede ser relativa o absoluta, pero lo habitual es mantenerla relativa al proyecto.
- Si el archivo no existe, el compilador abortará con un error claro.
Ejemplo básico
// main.zig
const std = @import("std");
pub fn main() void {
// Importamos el módulo "mimodulo" ubicado en la misma carpeta
const mod = @import("mimodulo.zig");
// Usamos la función exportada por mimodulo
mod.sayHello();
}
// mimodulo.zig
pub fn sayHello() void {
std.debug.print("Hola desde mimodulo!\n", .{});
}
En el código anterior, mimodulo.zig debe estar en el mismo directorio que main.zig. Si lo movemos a lib/mimodulo.zig, la importación cambiaría a @import("lib/mimodulo.zig").
2. Importando la biblioteca estándar
El lenguaje Zig incluye la biblioteca estándar, accesible simplemente con @import("std"). Esta es la forma más común de usar funcionalidades del lenguaje, como la impresión en consola o la gestión de memoria.
Ejemplo: impresión con std.debug.print
// main.zig
const std = @import("std");
pub fn main() void {
std.debug.print("Hola, Zig!\n", .{});
}
Nota: el segundo argumento de print es una tupla con los valores que se interpolarán en la cadena.
3. Importando librerías externas vía build.zig
Cuando trabajas con dependencias externas, Zig utiliza su sistema de construcción interno. El archivo build.zig es el punto de entrada para declarar y compilar las librerías.
3.1. Añadiendo una dependencia con Git
Supongamos que quieres usar la librería zbuild, disponible en GitHub. Primero, añade el repositorio como submódulo o descarga manualmente, pero Zig permite usar el gestor de dependencias con fetch.
// build.zig
const Builder = @import("std").build.Builder;
const Step = @import("std").build.Step;
const std = @import("std");
pub fn build(b: *Builder) void {
const mode = b.standardReleaseOptions();
// Crea el ejecutable
const exe = b.addExecutable("demo", "src/main.zig");
exe.setBuildMode(mode);
// Añade la dependencia
const zbuild_dep = b.dependency("zbuild", .{
.path = "deps/zbuild",
});
// Enlaza la dependencia con el ejecutable
exe.root_module.addImport("zbuild", zbuild_dep.module("zbuild"));
// Añade la ruta al directorio de dependencias
exe.linkSystemLibrary("c");
// Compila
exe.install();
}
En este ejemplo:
b.dependencydescarga la librería en la carpetadeps/zbuild.addImporthace que@import("zbuild")funcione dentro demain.zig.- El módulo
zbuilddebe existir dentro de la raíz del repositorio descargado.
3.2. Uso de la dependencia en el código
// src/main.zig
const std = @import("std");
const zbuild = @import("zbuild");
pub fn main() !void {
// Supongamos que zbuild tiene una función llamada "initialize"
try zbuild.initialize(.{ .optimize = true });
std.debug.print("Dependencia zbuild cargada correctamente.\n", .{});
}
El compilador busca la función initialize dentro del paquete zbuild, gracias a la configuración de build.zig.
4. Gestionando múltiples dependencias
Cuando el proyecto crece, es útil organizar las dependencias en una carpeta deps y referenciarlas en build.zig. Zig permite crear múltiples dependency y agregar sus módulos al ejecutable.
Ejemplo con dos dependencias
// build.zig
const Builder = @import("std").build.Builder;
const std = @import("std");
pub fn build(b: *Builder) void {
const exe = b.addExecutable("app", "src/main.zig");
// Dependencia 1
const depA = b.dependency("modA", .{ .path = "deps/modA" });
exe.root_module.addImport("modA", depA.module("modA"));
// Dependencia 2
const depB = b.dependency("modB", .{ .path = "deps/modB" });
exe.root_module.addImport("modB", depB.module("modB"));
exe.install();
}
En src/main.zig puedes entonces usar:
// src/main.zig
const modA = @import("modA");
const modB = @import("modB");
// ...uso de modA y modB
5. Buenas prácticas y errores comunes
- No usar
@importpara rutas dinámicas. Zig requiere rutas estáticas; cualquier lógica condicional debe manejarse enbuild.zig. - Evita nombres conflictivos. Si dos módulos exportan la misma función, el nombre completo del paquete evita colisiones.
- Mantén las dependencias actualizadas. Zig no tiene un gestor de paquetes incorporado; actualiza manualmente los submódulos.
- Documenta tu
build.zig. Los comentarios facilitan la incorporación de nuevos miembros al equipo.
Errores típicos
- Ruta incorrecta. El compilador falla con “No such file or directory”. Verifica la estructura de carpetas.
- Olvidar
addImport. Importar el paquete sin enlazarlo al ejecutable
