Linkar Biblioteca C em Zig — Resolver Problemas de Linkagem

Linkar Biblioteca C em Zig — Resolver Problemas de Linkagem

A interoperabilidade com C é uma das grandes forças do Zig. Quando a linkagem com bibliotecas C falha, este guia ajuda a diagnosticar e resolver.

Erro: “undefined symbol”

Causa: O linker não encontra a implementação de uma função C.

error: undefined symbol: 'sqlite3_open'

Soluções:

// No build.zig — adicionar a biblioteca
exe.linkSystemLibrary("sqlite3");
exe.linkLibC(); // Necessário para qualquer código C

// Se a biblioteca está em local não padrão:
exe.addLibraryPath(.{ .cwd_relative = "/usr/local/lib" });
exe.addIncludePath(.{ .cwd_relative = "/usr/local/include" });
# Verificar se a biblioteca está instalada
# Linux
ldconfig -p | grep sqlite3
pkg-config --libs sqlite3

# macOS
brew list sqlite3

Erro: “library not found”

Causa: A biblioteca não está instalada ou o caminho está errado.

# Instalar a biblioteca faltante
# Ubuntu/Debian
sudo apt install libsqlite3-dev

# Fedora
sudo dnf install sqlite-devel

# macOS
brew install sqlite3

# Verificar o caminho
pkg-config --cflags --libs sqlite3
// Se usando pkg-config:
exe.linkSystemLibrary("sqlite3");
// Zig usa pkg-config automaticamente quando disponível

Erro: “@cImport falha”

Causa: Headers C não encontrados ou com erros de parsing.

// PROBLEMA: header não encontrado
const c = @cImport(@cInclude("minha_lib.h")); // Falha

// SOLUÇÃO 1: Adicionar caminho do include no build.zig
exe.addIncludePath(b.path("include"));
exe.addIncludePath(.{ .cwd_relative = "/usr/local/include" });

// SOLUÇÃO 2: Usar caminho completo
const c = @cImport(@cInclude("/usr/include/sqlite3.h"));
// No build.zig — configuração completa
const exe = b.addExecutable(.{
    .name = "app",
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});

// Headers
exe.addIncludePath(b.path("vendor/include"));

// Bibliotecas
exe.addLibraryPath(b.path("vendor/lib"));
exe.linkSystemLibrary("minha_lib");
exe.linkLibC();

Erro: “incompatible types from @cImport”

Causa: Tipos C não mapeiam diretamente para tipos Zig.

const c = @cImport(@cInclude("lib.h"));

// PROBLEMA: tipos C são traduzidos diferentemente
// char* em C vira [*c]u8 em Zig

// SOLUÇÃO: Cast explícito
const resultado = c.funcao_c();
const zig_string: [*:0]const u8 = resultado; // Se terminado em null
const slice = std.mem.span(zig_string); // Converter para slice

Compilando Código C junto com Zig

// No build.zig — compilar arquivos .c como parte do projeto
exe.addCSourceFiles(.{
    .files = &.{
        "src/lib.c",
        "src/utils.c",
    },
    .flags = &.{
        "-Wall",
        "-Wextra",
        "-std=c11",
    },
});

// Incluir diretórios de headers
exe.addIncludePath(b.path("src"));
exe.linkLibC();

Linkando Biblioteca Estática (.a / .lib)

// No build.zig
exe.addObjectFile(b.path("vendor/libminha.a"));

// Ou adicionar o diretório e nome
exe.addLibraryPath(b.path("vendor/lib"));
exe.linkSystemLibrary("minha"); // procura libminha.a

Linkando Biblioteca Dinâmica (.so / .dylib / .dll)

// No build.zig
exe.linkSystemLibrary("curl"); // procura libcurl.so

// Especificar que é dinâmica
exe.linkSystemLibrary2("curl", .{ .preferred_link_mode = .dynamic });

// Para rpath (Linux)
exe.addRPath(.{ .cwd_relative = "/opt/lib" });

Problemas com Ponteiros C

const c = @cImport(@cInclude("lib.h"));

// Ponteiros C ([*c]T) são "opcionais" em Zig
// Precisam ser verificados antes de usar
const ptr: ?*c.struct_data = c.get_data();
if (ptr) |p| {
    // Usar p com segurança
    std.debug.print("valor: {d}\n", .{p.*.campo});
} else {
    std.debug.print("Ponteiro null retornado\n", .{});
}

Problemas com Callbacks C

const c = @cImport(@cInclude("lib.h"));

// Callback de Zig para C precisa de callconv(.C)
fn meuCallback(dados: ?*anyopaque) callconv(.C) void {
    if (dados) |d| {
        const valor: *i32 = @ptrCast(@alignCast(d));
        std.debug.print("Callback: {d}\n", .{valor.*});
    }
}

pub fn main() void {
    var x: i32 = 42;
    c.registrar_callback(meuCallback, &x);
}

Diagnóstico de Linkagem

# Ver símbolos de uma biblioteca
nm -D /usr/lib/libsqlite3.so | grep sqlite3_open

# Ver dependências de um binário
ldd ./zig-out/bin/meu-app

# Compilação verbose para ver comandos do linker
zig build --verbose

# Verificar pkg-config
pkg-config --cflags --libs openssl

Checklist de Linkagem

  1. Verifique se a biblioteca está instalada (-dev ou -devel package)
  2. Adicione exe.linkLibC() no build.zig
  3. Adicione exe.linkSystemLibrary("nome")
  4. Adicione caminhos de include se necessário
  5. Para cross-compilation, inclua os fontes C ou use bibliotecas estáticas
  6. Teste com --verbose para ver os comandos do linker

Veja Também

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.