Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to import zig module from another module?

Tags:

import

build

zig

Assuming following folder structure:

src/
   lib.zig
   module_a/
      file_a.zig
      file_a_test.zig
   module_b/
      file_b.zig
      file_b_test.zig
   tools/
      tools.zig
      tools_test.zig

How should I structure my build.zig in order to be somehow able to use:

const tools = @import("tools")

in my two other modules: module_a and module_b?

I also want to be able to run the tests somehow, so they don't break, for example in this fassion:

zig test src/module_a/file_a_test.zig

This is NOT an application, I don't have a main.zig file. I can have a lib.zig file though somewhere under src directory if it's needed.

Tried to look for a simple answer on Reddit and on StackOverflow, but couldn't find any. All the solutions use either an old std.build.Pkg system, or b.addModule but with a main.zig build target.

like image 813
Piotr Tutak Avatar asked Nov 01 '25 11:11

Piotr Tutak


1 Answers

Ok, so eventually I was able to figure this one out, but there could be some kind of a tutorial about this, because this was a trial and error.

So I've managed to add a main testing file to my file structure and it now looks like this:

src/
   lib.zig
   lib_test.zig
   module_a/
      file_a.zig
      file_a_test.zig
   module_b/
      file_b.zig
      file_b_test.zig
   tools/
      tools.zig
      tools_test.zig

The content of lib_test.zig is as follows:

const std = @import("std");

test {
    _ = @import("module_a/file_a_test.zig");
    _ = @import("module_b/file_b_test.zig");
    _ = @import("tools/tools_test.zig");
}

test "my custom lib test" {
    try std.testing.assert(1 == 1)
}

And my content of build.zig is like this:

const std = @import("std");

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

    const tools = b.addModule("tools", .{ .source_file = .{ .path = "src/tools/tools.zig" } });
    const module_a = b.addModule("module-a", .{ .source_file = .{ .path = "src/module_a/file_a.zig" } });
    const module_b = b.addModule("module-b", .{ .source_file = .{ .path = "src/module_b/file_b.zig" } });
    
    const unit_tests = b.addTest(.{
        .root_source_file = .{ .path = "src/lib_test.zig" },
        .target = target,
        .optimize = optimize,
    });
    unit_tests.addModule("tools", tools);
    unit_tests.addModule("module-a", module_a);
    unit_tests.addModule("module-b", module_b);
    
    const run_unit_tests = b.addRunArtifact(unit_tests);

    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_unit_tests.step);
}

So we have to create our tools module by addModule, and then when adding another modules to the build "namespace" we have to provide all the dependencies that those modules (i.e. .zig files) use, we do that by providing them to unit_tests, because unit tests are in fact "ran".

We can gather all the tests into a single file with a special test syntax.

After that to run the tests we do:

zig build test

The tests are ran every time there is a change in the code, not every time we invoke the command.

like image 152
Piotr Tutak Avatar answered Nov 03 '25 10:11

Piotr Tutak