¿Cómo usar @import para librerías externas?

¿Cómo usar @import para librerías externas?

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.dependency descarga la librería en la carpeta deps/zbuild.
  • addImport hace que @import("zbuild") funcione dentro de main.zig.
  • El módulo zbuild debe 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 @import para rutas dinámicas. Zig requiere rutas estáticas; cualquier lógica condicional debe manejarse en build.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

Comments

No comments yet. Why don’t you start the discussion?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *