Can I use packages inside build.zig?

My simple try seems not working.

Is this just a missing part or there is some reason explained somewhere?

I am hoping package can be used in build.zig, as that will allow many repetitive things be sharable when writing build.zig.

Maybe, this can help somehow.

In my sample product, I’ve practiced this.

see following links please.

host project

target package project

Best regards.

Thanks.

I have just tried. Seems if use the internet package rather than local pacakge, it will not work.

In target package, If expected method is published, you should be able to use it from the internet package.
Or else that means you’ll have to fork target package repository (adding method to build.zig of target package) …

PS

Understanding myself of internet package is used url and hash in build.zig.zon of host projet.

Yes, your understanding is correct.

essentially I tried have build.zig.zon

.{
    .name = "build_use_package",
    // This is a [Semantic Version](https://semver.org/).
    // In a future version of Zig it will be used for package deduplication.
    .version = "0.0.0",

    // This field is optional.
    // This is currently advisory only; Zig does not yet do anything
    // with this value.
    //.minimum_zig_version = "0.11.0",

    // This field is optional.
    // Each dependency must either provide a `url` and `hash`, or a `path`.
    // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
    // Once all dependencies are fetched, `zig build` no longer requires
    // Internet connectivity.
    .dependencies = .{
        .zcmd = .{
            .url = "https://github.com/liyu1981/zcmd.zig/archive/refs/tags/v0.2.0.tar.gz",
            .hash = "1220bb5963c28e563ed010e5d622611ec0cb711ba8c6644ab44a22955957b1b8fe1a",
        },
    },
    .paths = .{
        // This makes *all* files, recursively, included in this package. It is generally
        // better to explicitly list the files and directories instead, to insure that
        // fetching from tarballs, file system paths, and version control all result
        // in the same contents hash.
        "",
        // For example...
        //"build.zig",
        //"build.zig.zon",
        //"src",
        //"LICENSE",
        //"README.md",
    },
}

and build.zig

const std = @import("std");
const zcmd = @import("zcmd");

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

    const lib = b.addStaticLibrary(.{
        .name = "build_use_package",
        .root_source_file = .{ .path = "src/root.zig" },
        .target = target,
        .optimize = optimize,
    });

    b.installArtifact(lib);

    const exe = b.addExecutable(.{
        .name = "build_use_package",
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });

    // do something with zcmd like
    const result = try zcmd.run(.{
        .allocator = std.heap.page_allocator,
        .commands = &[_][]const []const u8{
            &.{ "uname", "-a" },
        },
    });
    defer result.deinit();
    // next do something with result.stdout like extract part of the OS's info

    b.installArtifact(exe);
    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

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

    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

    const exe_unit_tests = b.addTest(.{
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });

    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);

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

when zig build, it will not work, which is understandable, as zig runtime itself is not knowing where zcmd is (as no b.depency and exe.addModule step)

so I am currently add my mod as submodules in local, but I am wishing the url and hash way can also be supported somehow in zig

I’ve done this.

When you import a dependency in a build.zig file, you will not import the dependency’s module (ie the root file, usually src/main.zig) but rather their build.zig.

For example this is how my static file generator works: in your website’s project you import zine and from that you will be able to call public functions from its build file:

My blog:

Zine’s implementation of addWebsite:

In another part of my static website generator I wanted to use a package at buildtime, so to make it work I just made sure to import in the dependency’s build.zig the decls that I wanted to use at build time:

This is the build.zig that belongs to the frontmatter package:

As you can see I’m importing into it decls from frontmatter.zig, and this is how I use the exposed symbols in another build script (it’s called markdown.zig but gets imported and used by Zine’s main build.zig script):

I asked Andrew if this was the intended way and he confirmed it was. The reason why the package is not normally fully available at build time is because any code that depends on build-time artifacts will not be usable, since while evaluating the build script the build has yet to happen. So only fully self-contained code can be used at build time.

4 Likes

You must import zcmd into build function as dev dependency module.

thanks @kristoff. With your example, I have figured out this. I plan to write a note to better summary this. :slight_smile:

update: my summary is posted here: how to use your fav pkg in build.zig - Zig NEWS, thank you all.