I want to create a complex lib

Here’s a quick example of a project setup that you could reference to get started:

If we assume the following directory structure:

  • .
    • library/
      • add.zig
      • multiply.zig
      • library.zig
      • build.zig
      • build.zig.zon
    • program/
      • program.zig
      • build.zig
      • build.zig.zon

We want the package named library to export two modules named add and multiply, as well as a convenience module library that re-exports both add and multiply.

// library/add.zig
pub fn addInt(a: i32, b: i32) i32 {
    return a + b;
}
pub fn addFloat(a: f32, b: f32) f32 {
    return a + b;
}
// library/multiply.zig
pub fn multiplyInt(a: i32, b: i32) i32 {
    return a * b;
}
pub fn multiplyFloat(a: f32, b: f32) f32 {
    return a * b;
}
// library/library.zig
pub const add = @import("add");
pub const multiply = @import("multiply");

To export these modules, we need to set up the library package’s build scripts as follows:

// library/build.zig
const std = @import("std");

pub fn build(b: *std.Build) void {
    //  Note:
    // 'b.createModule()' creates a private module.
    // 'b.addModule()' creates a public module that can be imported by other build scripts.

    // Smaller modules that can be imported individually:
    const add_mod = b.addModule("add", .{
        .root_source_file = .{ .path = "add.zig" },
    });
    const multiply_mod = b.addModule("multiply", .{
        .root_source_file = .{ .path = "multiply.zig" },
    });

    // One big module that imports and re-exports the smaller modules:
    const library_mod = b.addModule("library", .{
        .root_source_file = .{ .path = "library.zig" },
        .imports = &.{
            .{ .name = "add", .module = add_mod },
            .{ .name = "multiply", .module = multiply_mod },
        },
    });
    _ = library_mod;
}
// library/build.zig.zon
.{
    .name = "library",
    .version = "0.0.0",
    .dependencies = .{},
    .paths = .{
        "",
    },
}

Now we have everything we need to be able to add library as a dependency.

For our program package which builds an executable, we would like to use the modules exported by the library package like this:

// program/program.zig
const std = @import("std");
const add = @import("add");
const multiply = @import("multiply");

pub fn main() void {
    std.debug.print("{d}\n", .{add.addInt(1, 2)});
    std.debug.print("{d}\n", .{multiply.multiplyFloat(3.3, 4.4)});
}

To add the library package as a dependency, we first add it to program/build.zig.zon:

// program/build.zig.zon
.{
    .name = "program",
    .version = "0.0.0",
    .dependencies = .{
        .library = .{
            .path = "../library",
        },
    },
    .paths = .{
        "",
    },
}

(Side note: .path here is used for relative packages on disk. If you want to fetch a package over the net (for example, from a public git repo), you use the .url and .hash fields. You can run the zig fetch command like zig fetch https://example.com/library.tar.gz --save=library to add these fields automatically. And for more general documentation on build.zig.zon, refer to the output from running zig init or check out the docs in the ziglang repo.)

Finally, update program/build.zig to resolve the dependency and import the modules:

// program/build.zig
const std = @import("std");

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

    const exe = b.addExecutable(.{
        .name = "program",
        .root_source_file = .{ .path = "program.zig" },
        .target = target,
        .optimize = optimize,
    });

    // Resolve the 'library' dependency.
    const library_dep = b.dependency("library", .{});

    // Import the smaller 'add' and 'multiply' modules exported by the library.
    exe.root_module.addImport("add", library_dep.module("add"));
    exe.root_module.addImport("multiply", library_dep.module("multiply"));

    // But we could also import the larger module if we prefer.
    // In this case we would need to update the imports in 'program.zig'
    // to '@import("library")' directly.
    //exe.root_module.addImport("library", library_dep.module("library"));

    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

I hope this is enough as an example to get you started converting some of your source files into a reusable library :smiley:

21 Likes