Declare a target as unsupported in build.zig

I’m trying to package the npcap SDK in the zig build system. npcap is a packet capture library for windows, and it only makes sense to use it on windows.

The npcap-sdk looks like this:

Lib
├── ARM64
│   ├── Packet.lib
│   └── wpcap.lib
├── Packet.lib
├── wpcap.lib
└── x64
    ├── Packet.lib
    └── wpcap.lib
Include
├── Packet32.h
├── pcap
│   ├── bluetooth.h
│   ├── bpf.h
│   ├── can_socketcan.h
│   ├── compiler-tests.h
│   ├── dlt.h
│   ├── funcattrs.h
│   ├── ipnet.h
│   ├── namedb.h
│   ├── nflog.h
│   ├── pcap.h
│   ├── pcap-inttypes.h
│   ├── sll.h
│   ├── socket.h
│   ├── usb.h
│   └── vlan.h
├── pcap-bpf.h
├── pcap.h
└── pcap-namedb.h

So naturally I have made some build logic to link the correct libraries:

    const npcap_sdk = b.dependency("npcap_sdk", .{ .target = target, .optimize = optimize });

    const npcap = b.addModule("npcap", .{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    const packet_lib_path = switch (target.result.os.tag) {
        .windows => switch (target.result.cpu.arch) {
            .aarch64 => npcap_sdk.path("Lib/ARM64/Packet.lib"),
            .x86_64 => npcap_sdk.path("Lib/x64/Packet.lib"),
            .x86 => npcap_sdk.path("Lib/Packet.lib"),
            else => return error.UnsupportedTarget,
        },
        else => return error.UnsupportedTarget,
    };
    const wpcap_lib_path = switch (target.result.os.tag) {
        .windows => switch (target.result.cpu.arch) {
            .aarch64 => npcap_sdk.path("Lib/ARM64/wpcap.lib"),
            .x86_64 => npcap_sdk.path("Lib/x64/wpcap.lib"),
            .x86 => npcap_sdk.path("Lib/wpcap.lib"),
            else => return error.UnsupportedTarget,
        },
        else => return error.UnsupportedTarget,
    };

    npcap.addObjectFile(packet_lib_path);
    npcap.addObjectFile(wpcap_lib_path);
    npcap.addIncludePath(npcap_sdk.path("Include/"));

But this has the unfortunate outcome that I can no longer run zig build -h on linux:

$ zig build -h
error: UnsupportedTarget
/home/jeff/repos/npcap-zig/build.zig:22:17: 0x14a13a9 in build (build)
        else => return error.UnsupportedTarget,

Without the ability to run zig build -h, its harder for the user to discover what build options there are. How do I fix this?

Maybe you could use a b.addFail step instead of returning error.UnsupportedTarget somehow?

3 Likes

I’ve had a similar issue when trying to run scoop’s doc and fmt steps on Linux CI/CD runners.

I solved it by returning either a public Darwin or a private Linux module from an if/else block:

If you’d still like to let Linux users know that their OS isn’t supported you can std.log.err your message.

In general, when it comes to handling failing cases you shouldn’t reach for errors, but rather consider using either b.addFail, std.log.err, or @panic/std.debug.panic.

UPD: I’ve added failing case handling to the Doc:

2 Likes

I tried to add b.addFail but I still haven’t gotten as far as I want.


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

    const target_supported = switch (target.result.os.tag) {
        .windows => switch (target.result.cpu.arch) {
            .aarch64 => true,
            .x86_64 => true,
            .x86 => true,
            else => false,
        },
        else => false,
    };
    if (!target_supported) {
        b.default_step.dependOn(&b.addFail("unsupported target").step);
        return;
    }

    // rest of the build script...
    // ...

}

Now I get a nice “unsupported target” but zig build -h is still not going to show the full list of supported steps.

Don’t return early, that’s preventing build from constructing the rest of the build graph.

3 Likes

Also, make the actual build step(s) that need a supported target depend on the Build.Step.Fail step when the target is unsupported.

For example, if zig build test also needs to have a supported target, you want that to fail, too. With your current setup, only zig build or zig build install will fail (since the default step is install).

5 Likes