"undefined symbol" – can't link to the system's libxml2 on macOS

I’m stuck and there’s some topics around this but nothing seems to be exactly what I’m looking for.

I have some code that calls libxml2 but I get the following error when I run zig build test

error: undefined symbol: _xmlDocGetRootElement
    note: referenced by /Users/j/src/imview/zig-cache/o/caa190fadd9b39d80f33e95105432b63/test.o:_adm.test.
open xml document
error: undefined symbol: _xmlReadMemory
    note: referenced by /Users/j/src/imview/zig-cache/o/caa190fadd9b39d80f33e95105432b63/test.o:_adm.test.
open xml document

My test is something like:

const std = @import("std");
const xml = @cImport({
    @cInclude("libxml2/libxml/parser.h");
    @cInclude("libxml2/libxml/tree.h");
});

test "open xml document" {
    const buffer: [*:0]const u8 = "<x>a</x>";
    const doc: xml.xmlDocPtr = xml.xmlReadMemory(buffer, 8, null, "utf-8", 0);
    const root: ?xml.xmlNodePtr = xml.xmlDocGetRootElement(doc);
    std.debug.print("{any}", .{root});
    try std.testing.expect(root != null);
}

And my build.zig looks like this:

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});

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

    const exe = b.addExecutable(.{
        .name = "imview",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    exe.linkSystemLibrary("xml2");
    exe.linkLibC();
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);

(continues...)

It seems like it’s either not finding libxml2 or otherwise the linking is failing but I’m not sure.

Hello @iluvcapra Welcome to ziggit :slight_smile:

You need to add a test target to your build.zig that also links to libxml2 and libc.

    const tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    tests.linkSystemLibrary("xml2");
    tests.linkLibC();
    const run_tests = b.addRunArtifact(tests);

    const test_step = b.step("test", "Run tests");
    test_step.dependOn(&run_tests.step);
1 Like

Yep that’s what I was missing, thanks!

1 Like