How to make my dependency lazy & fetch it only when it's needed?

The way you’re meant to use lazy dependencies is by doing something like the following:

pub fn build(b: *std.Build) void {
    // ...
    if (b.lazyDependency("datetime", .{
        // ...
    }) |time_dep| {
        exe.root_module.addImport("datetime", time_dep.module("datetime"));
    }
}

The way the build system works is that the moment your code calls b.lazyDependency(), you signal to the build system that you need this dependency. In the code above, if the dependency has already been fetched and is available, control flow enters the if body. But if the dependency has not yet been fetched, when you return from your build function the build system will fetch the dependency and then restart the build process again from the beginning (meaning it will call build again, but this time control flow will enter the if body). So like @Southporter said, in a successful build, b.lazyDependency() will always resolve to a non-null value, it’s just that it might take multiple calls to build before it finally does.

If your dependency is only needed for specific targets or when specific options are passed to the build, you need to guard the call to b.lazyDependency() so that it is not reached under those circumstances, i.e.:

pub fn build(b: *std.Build) void {
    // ...
    const use_datetime = b.option(bool, "use_datetime", "build using the datetime dependency") orelse false;

    if (use_datetime) {
        if (b.lazyDependency("datetime", .{
            // ...
        }) |time_dep| {
            exe.root_module.addImport("datetime", time_dep.module("datetime"));
        }
    }
}

Just for the record so there’s no confusion, you probably meant b.lazyDependency() (not lazyModule) which returns ?*std.Build.Dependency, which is a normal *std.Build.Dependency when unwrapped.

6 Likes