Fixing a build.zig file

Disclaimer, I don’t know any zig, I just want this thing to work and I hope someone can help.

There is the following library that sadly doesn’t come with compiled binaries:

They do however have a build.zig
file which seems to be for cross platform compilation. It’s dated 16 June 2022.

If I use zig build on this with zig 0.15.1 (correct me if my usage is wrong), then I get:

build.zig:6:21: error: root source file struct ‘std’ has no member named ‘build’
pub fn build(b: *std.build.Builder) !void {
~^~~~
/opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/std.zig:1:1: note: struct declared here
pub const ArrayHashMap = array_hash_map.ArrayHashMap;
^~~
referenced by:
runBuild__anon_21150: /opt/homebrew/Cellar/zig/0.15.1/lib/zig/std/Build.zig:2213:50
main: /opt/homebrew/Cellar/zig/0.15.1/lib/zig/compiler/build_runner.zig:366:29
4 reference(s) hidden; use ‘-freference-trace=6’ to see all references

I also tried zig 0.9.1 cause it’s a tagged version and it’s a few months from before 16 June 2022.

This however gives me:

thread 12279453 panic: Darwin is handled separately via std.zig.system.darwin module
Unable to dump stack trace: debug info stripped
zsh: abort /Users/doeke/Downloads/zig-macos-aarch64-0.9.1/./zig build

The build.zig file is only 71 lines long. Can someone be so friendly to fix it?

This should install the static library artifact in zig-out/lib/ on Zig 0.15.2:

const std = @import("std");

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

    const lib = b.addLibrary(.{
        .name = "mqtt-c",
        .root_module = b.createModule(.{
            .target = target,
            .optimize = optimize,
            .link_libc = true,
        }),
    });
    lib.addIncludePath(b.path("include"));
    lib.addCSourceFiles(.{ .files = &SOURCES });
    b.installArtifact(lib);
}

const SOURCES = .{
    "src/mqtt.c",
    "src/mqtt_pal.c",
};

Example Commands:

  • Compile for native target in Debug mode:

zig build
  • Compile for x86_64-windows target in ReleaseFast mode:

zig build -Dtarget=x86_64-windows -Doptimize=ReleaseFast

There’s been a ton of changes in the Zig build system API since 2022, but oth the build.zig file looks quite simple, just building a bunch a static libraries from C code.

Here’s an example from one of my projects what building a C static library looks like now:

I was beat to it, but here’s my working one anyway:

const std = @import("std");

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

    const windows = b.addLibrary(.{
        .name = "mqtt-c",
        .root_module = b.createModule(.{
            .target = target,
            .optimize = optimize,
        }),
    });
    includeCommon(b, windows);
    b.installArtifact(windows);
}

fn includeCommon(b: *std.Build, lib: *std.Build.Step.Compile) void {
    lib.addIncludePath(b.path("include"));

    lib.addCSourceFiles(.{
        .files = &.{
            "src/mqtt.c",
            "src/mqtt_pal.c",
        },
    });
    lib.linkLibC();
}

Direct port, with the removal of the different targets, you can specify them with -Dtarget=[target triple] instead. Also for optimisations -Doptimize=[Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] Debug is the default.

@tensorush s’ is more idiomatic, though it doesnt matter much for such a simple build script.

1 Like

@tensorush @vulpesx and floooh Thanks!

I got errors when using the created .a file related to:

___ubsan_handle_add_overflow
___ubsan_handle_float_cast_overflow
___ubsan_handle_out_of_bounds
___ubsan_handle_pointer_overflow
___ubsan_handle_shift_out_of_bounds
___ubsan_handle_sub_overflow
___ubsan_handle_type_mismatch_v1

This seems to work:

const std = @import("std");

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

    const lib = b.addLibrary(.{
        .name = "mqtt-c",
        .root_module = b.createModule(.{
            .target = target,
            .optimize = optimize,
            .link_libc = true,
        }),
    });
    lib.addIncludePath(b.path("include"));
    lib.addCSourceFiles(.{ 
        .files = &SOURCES,
        .flags = &.{
            "-fno-sanitize=undefined",
            "-fno-sanitize=float-cast-overflow",
            "-fno-sanitize=integer",
            "-fno-sanitize=alignment",
            "-fno-sanitize=shift",
            "-fno-sanitize=pointer-overflow",
            "-fno-sanitize=bounds",
        },
    });
    b.installArtifact(lib);
}

const SOURCES = .{
    "src/mqtt.c",
    "src/mqtt_pal.c",
};

I did use zig build -Dtarget=aarch64-macos.15.0 Else I got errors later on in Odin.

1 Like

Zig has a different (much stricter) default set of compilation options for C code than Clang, one thing it does for instance is automatically activating UBSAN in debug mode which then requires to link with the ubsan runtime library (when using Zig as linker this happens automatically).

To disable this behaviour it should be enough to build just with "-fno-sanitize=undefined" (that’s what I do when building C code to WASM via Zig but then use Emscripten as linker, and that seems to remove all dependencies on the ubsan runtime).

3 Likes

You can just set .sanitize_c = .off on the module instead of any manual C flags.

3 Likes

Thanks!

One more thing, I would like two export 2 files instead of one.
So one with name “mqtt” and with source, “src/mqtt.c”.
And one time with name “mqtt_pal” and with source, “src/mqtt_pal.c”.

Although this sounds simple, not knowing zig makes me really struggle with it.
Could someone help?

const std = @import("std");

pub fn build(b: *std.Build) !void {

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

    const lib = b.addLibrary(.{
        .name = "mqtt",
        .root_module = b.createModule(.{
            .target = target,
            .optimize = optimize,
            .link_libc = true,
            .sanitize_c = .off,
        }),
    });
    lib.addIncludePath(b.path("include"));
    lib.addCSourceFiles(.{ 
        .files = &.{
            "src/mqtt.c",
        },
    });
    b.installArtifact(lib);
}

just copy “mqtt” lib, change the name and the source file

1 Like