Skip to content

build.zig fails to compile due to deduplicated lazy dependency #21771

@dermetfan

Description

@dermetfan

Zig Version

0.14.0-dev.1952+9f84f7f92

Steps to Reproduce and Observed Behavior

If two dependencies depend on the same package,
but one does so lazily and the other one does not,
the build.zig of the latter fails to compile
if it does not use lazyDependency()
(which it should not need to use as the dependency is not lazy).

Graphically:

         A
        / \
       B   C
(eager) \ / (lazy)
         D

B fails to compile with:

thread 889721 panic: dependency 'b.zqlite' is marked as lazy in build.zig.zon which means it must use the lazyDependency function instead
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/Build.zig:2095:32: 0x1414dd5 in dependency__anon_10241 (build)
                std.debug.panic("dependency '{s}{s}' is marked as lazy in build.zig.zon which means it must use the lazyDependency function instead", .{ b.dep_prefix, name });
                               ^
/foo/zig-issue-lazy-dep/b/build.zig:17:39: 0x150b433 in build (build)
                .module = b.dependency("zqlite", options).module("zqlite"),
                                      ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/Build.zig:2295:44: 0x149e020 in runBuild__anon_61135 (build)
        .error_union => try build_zig.build(b),
                                           ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/Build.zig:2275:29: 0x145a447 in dependencyInner__anon_55211 (build)
        sub_builder.runBuild(bz) catch @panic("unhandled error");
                            ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/Build.zig:2097:35: 0x1414e40 in dependency__anon_10241 (build)
            return dependencyInner(b, name, pkg.build_root, if (@hasDecl(pkg, "build_zig")) pkg.build_zig else null, pkg_hash, pkg.deps, args);
                                  ^
/foo/zig-issue-lazy-dep/build.zig:14:39: 0x1414909 in build (build)
                .module = b.dependency("b", options).module("b"),
                                      ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/Build.zig:2295:44: 0x13f9c10 in runBuild__anon_4961 (build)
        .error_union => try build_zig.build(b),
                                           ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/compiler/build_runner.zig:335:29: 0x13f4725 in main (build)
        try builder.runBuild(root);
                            ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/start.zig:621:37: 0x13cf202 in posixCallMainAndExit (build)
            const result = root.main() catch |err| {
                                    ^
/nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib/std/start.zig:250:5: 0x13ceddf in _start (build)
    asm volatile (switch (native_arch) {
    ^
???:?:?: 0x0 in ??? (???)
error: the following build command crashed:
/foo/zig-issue-lazy-dep/.zig-cache/o/fb9a870f009dd40dcc1101049c53e9fd/build /nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/bin/zig /nix/store/ypa88d8507lmbqlm6f66s1q9qpzvxlc8-zig-0.14.0-dev.1952+9f84f7f92/lib /foo/zig-issue-lazy-dep /foo/zig-issue-lazy-dep/.zig-cache ~/.cache/zig --seed 0x27cf3f35 -Z5b8c9b2ff9d97b7d

My guess is that the build system marks the deduplicated dependency as lazy even though it is only lazy for C, not B.

In more complex dependency graphs this seems to happen about half the time I run zig build which leads me to conclude that it's related to dependency traversal order. However in this small example, I'm unable to find a --seed that works around the issue.

So without knowing any internals of the build system, I guess that this is what happens:

  1. The dependency graph is traversed, leading to two entries for D: One lazy (from C), one eager (from B).
  2. The eager one is dropped during deduplication because laziness is not taken into account for equality, so now the build system thinks all instances of D are lazy.
  3. B's build.zig is compiled given the lazy D in @import("@dependencies").

I prepared a repository so you can reproduce easily by running zig build: https://github.com/dermetfan/zig-issue-lazy-dep

Expected Behavior

It should not be necessary to use lazyDependency() instead of dependency() as the dependency is not lazy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugObserved behavior contradicts documented or intended behaviorzig build systemstd.Build, the build runner, `zig build` subcommand, package management

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions