Linking system library needed by a static library

Hi, I have a static library written in rust that just exposes a rust lib with C-compatible interface that I use from zig. That static lib depends on libudev and in the build script i do link the executable against it.
So the problem is, in the build log below we can see, that the generated zig build-exe ... command doesn’t have -ludev arg anywhere even though there is exe.linkSystemLibrary("udev") in the build script. Now if i run zig build-exe ... -ludev manually it actually compiles and works as expected. Is this a bug in the build system or am I doing something wrong?

Here’s build.zig

const std = @import("std");

pub fn build(b: *std.Build) void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();
    defer _ = gpa.deinit();

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

    const cargo = b.addSystemCommand(&.{ "cargo", "build" });
    if (optimize != .Debug) {
        cargo.addArg("--release");
    }
    cargo.cwd = .{ .cwd_relative = "libnpoled" };

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

    exe.step.dependOn(&cargo.step);
    const cargo_optimize_subdir = if (optimize == .Debug) "debug" else "release";
    const obj_path = std.fmt.allocPrint(allocator, "libnpoled/target/{s}/", .{cargo_optimize_subdir}) catch @panic("Failed to allocate memory for obj path");
    defer allocator.free(obj_path);
    exe.addLibraryPath(.{ .cwd_relative = obj_path });
    exe.linkSystemLibrary2("npoledrust", .{ .preferred_link_mode = .static });
    exe.linkLibC();
    exe.linkSystemLibrary("gcc_s");
    exe.linkSystemLibrary("udev");
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

And output of zig build:

❯ zig build
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
install
└─ install npoled
   └─ zig build-exe npoled Debug native 16 errors
error: ld.lld: undefined symbol: udev_device_get_sysattr_value
    note: referenced by hid.c:187 (etc/hidapi/linux/hid.c:187)
    note:               679628f6e8944299-hid.o:(copy_udev_string) in archive /home/winlith/Projects/npoled/libnpoled/target/debug/libnpoledrust.a
[more errors like above]
error: the following command failed with 16 compilation errors:
/usr/bin/zig build-exe -search_paths_first_static -lnpoledrust -search_paths_first -lgcc_s -ODebug -L /home/winlith/Projects/npoled/libnpoled/target/debug -Mroot=/home/winlith/Projects/npoled/src/main.zig -lc --cache-dir /home/winlith/Projects/npoled/.zig-cache --global-cache-dir /home/winlith/.cache/zig --name npoled --listen=- 
Build Summary: 1/4 steps succeeded; 1 failed (disable with --summary none)
install transitive failure
└─ install npoled transitive failure
   └─ zig build-exe npoled Debug native 16 errors
error: the following build command failed with exit code 1:
/home/winlith/Projects/npoled/.zig-cache/o/1631138da6be2e4ec27482ff03273718/build /usr/bin/zig /home/winlith/Projects/npoled /home/winlith/Projects/npoled/.zig-cache /home/winlith/.cache/zig --seed 0x42e3bf9b -Z7afd30b847efe952
1 Like

Depending on where the library is located, you may need to add a library path, for example: exe.addIncludePath(.{ .cwd_relative = "./lib/" });

When running pkg-config --cflags --libs libudev do you get -ludev?
If not, and you are on debian, install libudev-dev.

I don’t think that’s the problem, my static lib path is added and it is found. The compiler clearly knows where libudev.so is located because it links when i run zig build-exe ... -ludev manually.

Yes, I do.

Turns out i just had to change exe.linkSystemLibrary("udev"); to exe.linkSystemLibrary("libudev"); and it works.

1 Like