Linking to compiled static library provided by dependency

I am trying to depend on npcap https://npcap.com/

which provides an sdk with only headers in it (the user is expected to install npcap themselves) Npcap: Windows Packet Capture Library & Driver

I want to create a zig package for it so I can depend on it like a regular zig dependency.

Can someone point me to an existing example library or documentation that does something similar?

1 Like

Found this example, which is think is what I need:

I’ve gotten this far:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const upstream = b.dependency("npcap_sdk", .{});
    const lib = b.addStaticLibrary(.{
        .name = "npcap",
        .target = b.standardTargetOptions(.{}),
        .optimize = b.standardOptimizeOption(.{}),
    });
    lib.installHeadersDirectory(upstream.path("include"), "", .{});
    b.installArtifact(lib);
}


but I think I need to add the pre-compiled DLLs from the SDK somewhere?

jeff@jeff-debian:~/repos/npcap-zig$ zig build
install
└─ install npcap
   └─ zig build-lib npcap Debug native failure
error: the linker needs one or more objects to link
Build Summary: 0/3 steps succeeded; 1 failed
install transitive failure
└─ install npcap transitive failure
   └─ zig build-lib npcap Debug native failure

well this builds but I think I should probably attempt a full build of npcap instead of relying on its published sdk?

const std = @import("std");

pub fn build(b: *std.Build) void {
    const upstream = b.dependency("npcap_sdk", .{});
    const lib = b.addStaticLibrary(.{
        .name = "npcap",
        .target = b.standardTargetOptions(.{}),
        .optimize = b.standardOptimizeOption(.{}),
    });
    lib.addObjectFile(upstream.path("Lib/wpcap.lib"));
    lib.addObjectFile(upstream.path("Lib/Packet.lib"));
    lib.installHeadersDirectory(upstream.path("Include"), "", .{});
    b.installArtifact(lib);
}

I gave up on compiling npcap from source so i will just use the pre-compiled SDK (has some .libs and some headers).

Is there a way to include this .lib into my compiled executable? Also, I don’t know how to do this.

build.zig.zon

.{
    .name = "gatorcat",
    .version = "0.0.0",
    .minimum_zig_version = "0.13.0",
    .dependencies = .{
        .flags = .{
            .url = "https://github.com/n0s4/flags/archive/refs/tags/v0.10.0.tar.gz",
            .hash = "12200d3243c5919d6ae3254f991bdf95956f349ccd6d3463f9beb5454d300a0f1e64",
        },
        .npcap_sdk = .{
            .url = "https://npcap.com/dist/npcap-sdk-1.13.zip",
            .hash = "12206001b370bb70f9dc47c846df6ad82725e4491650472dc7037c5e027792ba207e",
        },
    },
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        "LICENSE",
        "example",
    },
}


build zig

// windows npcap dependency
    const npcap_sdk = b.dependency("npcap_sdk", .{
        .target = target,
        .optimize = optimize,
    });
    const lib = b.addStaticLibrary(.{
        .name = "npcap",
        .target = target,
        .optimize = optimize,
    });
    lib.addObjectFile(upstream_sdk.path("Lib/wpcap.lib"));
    lib.addObjectFile(upstream_sdk.path("Lib/Packet.lib"));
    lib.installHeadersDirectory(upstream_sdk.path("Include"), "", .{});
    b.installArtifact(lib);

Ok i think I’m pretty close with this, zls is now giving me autocomplete

// CLI tool
    const cli_tool = b.addExecutable(.{
        .name = "gatorcat",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    cli_tool.root_module.addImport("gatorcat", gatorcat_module);

    // CLI tool dependencies
    const flags = b.dependency("flags", .{
        .target = target,
        .optimize = optimize,
    });
    cli_tool.root_module.addImport("flags", flags.module("flags"));
    b.installArtifact(cli_tool);

    const npcap_sdk = b.dependency("npcap_sdk", .{
        .target = target,
        .optimize = optimize,
    });
    cli_tool.addObjectFile(npcap_sdk.path("Lib/wpcap.lib"));
    cli_tool.addObjectFile(npcap_sdk.path("Lib/Packet.lib"));
    cli_tool.addIncludePath(npcap_sdk.path("Include"));

const npcap = @cImport({
    @cInclude("pcap/pcap.h");
});

pub const WindowsRawSocket = struct {

    pub fn init() WindowsRawSocket {
        npcap.
    }
};

got everything working, but forgot to link libc, and I will have to refactor this later to make it a conditional dependency to only occur on windows. Not sure how to do that, but that is a separate issue.

// CLI tool
  const cli_tool = b.addExecutable(.{
      .name = "gatorcat",
      .root_source_file = b.path("src/main.zig"),
      .target = target,
      .optimize = optimize,
  });
  cli_tool.root_module.addImport("gatorcat", gatorcat_module);

  // CLI tool dependencies
  const flags = b.dependency("flags", .{
      .target = target,
      .optimize = optimize,
  });
  cli_tool.root_module.addImport("flags", flags.module("flags"));
  b.installArtifact(cli_tool);
  cli_tool.addObjectFile(npcap_sdk.path("Lib/wpcap.lib"));
  cli_tool.addObjectFile(npcap_sdk.path("Lib/Packet.lib"));
  cli_tool.addIncludePath(npcap_sdk.path("Include"));
  cli_tool.linkLibC();

1 Like

nevermind, its not actually linking yet

error: lld-link: undefined symbol: pcap_open
    note: referenced by /home/jeff/repos/gatorcat/src/nic.zig:388
    note:               /home/jeff/repos/gatorcat/.zig-cache/o/0fb452cb5eb5abf34acdbe0b3ac8c9c5/gatorcat.exe.obj:(nic.WindowsRawSocket.init)

I was close, my target was x86_64 so I needed to link against the 64-bit versions of the DLLs.

here is the full solution, for a project that is depending on pre-compiled DLLs. Note that it should eventually contain logic to select the right DLL’s based on the target architecture.

build.zig.zon

.{
    .name = "gatorcat",
    .version = "0.0.0",
    .minimum_zig_version = "0.13.0",
    .dependencies = .{
        .flags = .{
            .url = "https://github.com/n0s4/flags/archive/refs/tags/v0.10.0.tar.gz",
            .hash = "12200d3243c5919d6ae3254f991bdf95956f349ccd6d3463f9beb5454d300a0f1e64",
        },
        .npcap_sdk = .{
            .url = "https://npcap.com/dist/npcap-sdk-1.13.zip",
            .hash = "12206001b370bb70f9dc47c846df6ad82725e4491650472dc7037c5e027792ba207e",
        },
    },
    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
        "LICENSE",
        "example",
    },
}

build.zig

// windows dependency
    const npcap_sdk = b.dependency("npcap_sdk", .{
        .target = target,
        .optimize = optimize,
    });
// CLI tool dependencies
    const flags = b.dependency("flags", .{
        .target = target,
        .optimize = optimize,
    });
    cli_tool.root_module.addImport("flags", flags.module("flags"));
    b.installArtifact(cli_tool);
    cli_tool.addObjectFile(npcap_sdk.path("Lib/x64/wpcap.lib"));
    cli_tool.addObjectFile(npcap_sdk.path("Lib/x64/Packet.lib"));
    cli_tool.addIncludePath(npcap_sdk.path("Include"));
    cli_tool.linkLibC();

1 Like