Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use local package with nested local dependency #20508

Closed
jeffbdavenport opened this issue Jul 5, 2024 · 6 comments
Closed

Cannot use local package with nested local dependency #20508

jeffbdavenport opened this issue Jul 5, 2024 · 6 comments
Labels
bug Observed behavior contradicts documented or intended behavior

Comments

@jeffbdavenport
Copy link

jeffbdavenport commented Jul 5, 2024

Zig Version

0.13.0

Steps to Reproduce and Observed Behavior

I am trying to figure out how to build an exe with a locally created zig package that depends on another local package. I've been trying to figure out how to do this for a couple years now. Still have never figured it out. Before I resorted to using Gyro because zigmod does not support installing local packages (It's still broken). Now Gyro has been archived so I am left with nothing but using zon, which feels practically impossible.

The only relevant official documentation I've been able to find is here https://github.com/ziglang/zig/blob/master/doc/build.zig.zon.md which does not mention anything about nested dependencies.

I have a game engine library that I have built myself called dungeon_weld This depends on another package called SDL. I had to modify the SDL package because it was not being maintained, so this is also a local package which I am storing inside the folder dungeon_weld/libs/SDL.zig

If I run zig build inside the dungeon_weld package, it completes and there are no issues. But if I run the command in my game folder, I get this output:

Zolark@DESKTOP MINGW64 /c/projects/zig/tower_of_embers
$ zig build
debug: failed to determine terminal size; using conservative guess 80x25
install
mq install tower_of_embers
   mq zig build-lib tower_of_embers Debug native 1 errors
src\main.zig:1:20: error: no module named 'dungeon_weld' available within module root
const DW = @import("dungeon_weld");
                   ^~~~~~~~~~~~~~
referenced by:
    main: src\main.zig:17:9
    callMain: C:\Users\Jeff\bin\lib\std\start.zig:524:32
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
error: the following command failed with 1 compilation errors:
C:\Users\Jeff\bin\zig.exe build-lib -ODebug -Mroot=C:\projects\zig\tower_of_embers\src\main.zig --cache-dir C:\projects\zig\tower_of_embers\.zig-cache --global-cache-dir C:\Users\Jeff\AppData\Local\zig --name tower_of_embers -static --listen=-
install
mq install tower_of_embers
   mq zig build-exe tower_of_embers Debug native 1 errors
C:\projects\zig\dungeon_weld\src\main.zig:2:25: error: no module named 'SDL' available within module dungeon_weld
pub const SDL = @import("SDL");
                        ^~~~~
referenced by:
    SDL: C:\projects\zig\dungeon_weld\src\display\Window.zig:2:17
    display.Window: C:\projects\zig\dungeon_weld\src\display\Window.zig:23:6
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
error: the following command failed with 1 compilation errors:
C:\Users\Jeff\bin\zig.exe build-exe -ODebug -I C:\Users\Jeff\include -L C:\Users\Jeff\lib --dep dungeon_weld -Mroot=C:\projects\zig\tower_of_embers\src\main.zig -ODebug -Mdungeon_weld=C:\projects\zig\dungeon_weld\src\main.zig -lc --cache-dir C:\projects\zig\tower_of_embers\.zig-cache --global-cache-dir C:\Users\Jeff\AppData\Local\zig --name tower_of_embers --listen=-
Build Summary: 0/5 steps succeeded; 2 failed (disable with --summary none)
install transitive failure
tq install tower_of_embers transitive failure
x  mq zig build-lib tower_of_embers Debug native 1 errors
mq install tower_of_embers transitive failure
   mq zig build-exe tower_of_embers Debug native 1 errors
error: the following build command failed with exit code 1:
C:\projects\zig\tower_of_embers\.zig-cache\o\99bd3824459fa2420644015e4a2abf4b\build.exe C:\Users\Jeff\bin\zig.exe C:\projects\zig\tower_of_embers C:\projects\zig\tower_of_embers\.zig-cache C:\Users\Jeff\AppData\Local\zig --seed 0x3055124c -Zc68aef10fdb0300e

I have a build.zig.zon in all 3 folders. One in SDL folder, one in dungeon_weld folder, and one in the game. Here is the one for the game. I assume that the dependency SDL being listed in the build.zig.zon and build.zig inside the dungeon_weld package is sufficient, so I left it out in the game folder. However, I have tried including it anyways, and I get the same error:

.{
        .dungeon_weld = .{
            .path = "../dungeon_weld",
        },
    },

    .paths = .{
        "build.zig",
        "build.zig.zon",
        "src",
    },
}

Here is the build file for the game:

const std = @import("std");

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

    const optimize = b.standardOptimizeOption(.{});

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

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

    exe.addIncludePath(b.path("../../../Users/User/include"));
    exe.addLibraryPath(b.path("../../../Users/User/lib"));
    exe.linkLibC();

    const package = b.dependency("dungeon_weld", .{
        .target = target,
        .optimize = optimize,
    });
    const module = package.module("dungeon_weld");
    exe.root_module.addImport("dungeon_weld", module);

    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 = b.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 = b.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);
}

Expected Behavior

It should finish building with zig build

@jeffbdavenport jeffbdavenport added the bug Observed behavior contradicts documented or intended behavior label Jul 5, 2024
@jeffbdavenport jeffbdavenport changed the title Cannot used package with nested dependency? Cannot use local package with nested local dependency? Jul 5, 2024
@jeffbdavenport jeffbdavenport changed the title Cannot use local package with nested local dependency? Cannot use local package with nested local dependency Jul 5, 2024
@ianprime0509
Copy link
Contributor

ianprime0509 commented Jul 5, 2024

The first error,

mq install tower_of_embers
   mq zig build-lib tower_of_embers Debug native 1 errors
src\main.zig:1:20: error: no module named 'dungeon_weld' available within module root
const DW = @import("dungeon_weld");
                   ^~~~~~~~~~~~~~

is because you're missing lib.root_module.addImport("dungeon_weld", module); in the game's build.zig. You added the import for exe, but lib is a separate compilation, so it also needs this import to be specified.

The second error,

C:\projects\zig\dungeon_weld\src\main.zig:2:25: error: no module named 'SDL' available within module dungeon_weld
pub const SDL = @import("SDL");
                        ^~~~~

is likely a similar issue within dungeon_weld's build.zig (the SDL import needs to be added to the dungeon_weld module).

One of the Zig communities would be a good place to get more support on getting this working.

@BratishkaErik
Copy link
Contributor

You need to add this part:

    // Really is a "exe.root_module.addIncludePath"
    exe.addIncludePath(b.path("../../../Users/User/include"));
    exe.addLibraryPath(b.path("../../../Users/User/lib"));
    // Really is a "exe.root_module.link_libc = true"
    exe.linkLibC();
    // ...
    exe.root_module.addImport("dungeon_weld", module);

To lib and exe_unit_tests too, because they contain their own root_module which is not shared with exe. This can be quite repetitve, so people usually move this to the separate function, like this:

fn addDependencies(compile: *std.Build.Step.Compile, dep_module: *std.Build.Module) void {
    compile.addIncludePath(b.path("../../../Users/User/include"));
    compile.addLibraryPath(b.path("../../../Users/User/lib"));
    compile.linkLibC();
    compile.root_module.addImport("dungeon_weld", dep_module);
}

// pub fn build...
addDependencies(lib, module);
addDependencies(exe, module);
addDependencies(exe_unit_tests, module);

@BratishkaErik
Copy link
Contributor

BratishkaErik commented Jul 5, 2024

BTW this PR #20388 adds new way to create compile steps out of existing root module, so your code could be much more simpler with new API:

const std = @import("std");

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

    const optimize = b.standardOptimizeOption(.{});
    
    const package = b.dependency("dungeon_weld", .{
        .target = target,
        .optimize = optimize,
    });

    const mod = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .link_libc = true,
    });
    mod.addIncludePath(b.path("../../../Users/User/include"));
    mod.addLibraryPath(b.path("../../../Users/User/lib"));
    mod.addImport("dungeon_weld", package.module("dungeon_weld"));
    

    const lib = b.addLibrary(.{
        .name = "tower_of_embers",
        .root_module = mod,
        .linkage = .static,
    });
    b.installArtifact(lib);

    const exe = b.addExecutable2(.{
        .name = "tower_of_embers",
        .root_module = mod,
    });
    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.addTest2(.{
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/root.zig"),
            .target = target,
            .optimize = optimize,
        }),
    });

    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

    const exe_unit_tests = b.addTest2(.{
        .root_module = mod,
    });

    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);
}

Does this explanation makes sense to you?

@jeffbdavenport
Copy link
Author

jeffbdavenport commented Jul 5, 2024

@BratishkaErik & @ianprime0509 I appreciate the help. I would like to figure out how to do this with the stable release of 0.13.0

After adding the module to the lib, the dungeon_weld package is working now, however the SDL one is still throwing two errors. I tried figuring out what is missing but I'm struggling.

This is the error I get:

Zolark@DESKTOP MINGW64 /c/projects/zig/tower_of_embers
$ zig build
debug: failed to determine terminal size; using conservative guess 80x25
install
└─ install tower_of_embers
   └─ zig build-lib tower_of_embers Debug native 1 errors
C:\projects\zig\dungeon_weld\src\main.zig:2:25: error: no module named 'SDL' available within module dungeon_weld
pub const SDL = @import("SDL");
                        ^~~~~
referenced by:
    SDL: C:\projects\zig\dungeon_weld\src\display\Window.zig:2:17
    display.Window: C:\projects\zig\dungeon_weld\src\display\Window.zig:23:6
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
error: the following command failed with 1 compilation errors:
C:\Users\Jeff\bin\zig.exe build-lib -ODebug -I C:\Users\Jeff\include -L C:\Users\Jeff\lib --dep dungeon_weld -Mroot=C:\projects\zig\tower_of_embers\src\main.zig -ODebug -Mdungeon_weld=C:\projects\zig\dungeon_weld\src\main.zig -lc --cache-dir C:\projects\zig\tower_of_embers\.zig-cache --global-cache-dir C:\Users\Jeff\AppData\Local\zig --name tower_of_embers -static --listen=-
install
└─ install tower_of_embers
   └─ zig build-exe tower_of_embers Debug native 1 errors
C:\projects\zig\dungeon_weld\src\main.zig:2:25: error: no module named 'SDL' available within module dungeon_weld
pub const SDL = @import("SDL");
                        ^~~~~
referenced by:
    SDL: C:\projects\zig\dungeon_weld\src\display\Window.zig:2:17
    display.Window: C:\projects\zig\dungeon_weld\src\display\Window.zig:23:6
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
error: the following command failed with 1 compilation errors:
C:\Users\Jeff\bin\zig.exe build-exe -ODebug -I C:\Users\Jeff\include -L C:\Users\Jeff\lib --dep dungeon_weld -Mroot=C:\projects\zig\tower_of_embers\src\main.zig -ODebug -Mdungeon_weld=C:\projects\zig\dungeon_weld\src\main.zig -lc --cache-dir C:\projects\zig\tower_of_embers\.zig-cache --global-cache-dir C:\Users\Jeff\AppData\Local\zig --name tower_of_embers --listen=-
Build Summary: 0/5 steps succeeded; 2 failed (disable with --summary none)
install transitive failure
├─ install tower_of_embers transitive failure
│  └─ zig build-lib tower_of_embers Debug native 1 errors
└─ install tower_of_embers transitive failure
   └─ zig build-exe tower_of_embers Debug native 1 errors
error: the following build command failed with exit code 1:
C:\projects\zig\tower_of_embers\.zig-cache\o\20e57e2d81089738d14d7b56c52e0a5b\build.exe C:\Users\Jeff\bin\zig.exe C:\projects\zig\tower_of_embers C:\projects\zig\tower_of_embers\.zig-cache C:\Users\Jeff\AppData\Local\zig --seed 0x4f5adb4a -Z690b83e87e1e7730

Zolark@DESKTOP-PNFM9GM MINGW64 /c/projects/zig/tower_of_embers
$ zig build
C:\projects\zig\tower_of_embers\build.zig:23:18: error: no field or member function named 'addLibrary' in 'Build'
    const lib = b.addLibrary(.{
                ~^~~~~~~~~~~
C:\Users\Jeff\bin\lib\std\Build.zig:1:1: note: struct declared here
const std = @import("std.zig");
^~~~~
referenced by:
    runBuild__anon_8952: C:\Users\Jeff\bin\lib\std\Build.zig:2116:27
    main: C:\Users\Jeff\bin\lib\compiler\build_runner.zig:301:29
    re

Here is the current build.zig for the game:

const std = @import("std");

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

    const optimize = b.standardOptimizeOption(.{});

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

    const package = b.dependency("dungeon_weld", .{
        .target = target,
        .optimize = optimize,
    });

    const module = package.module("dungeon_weld");
    addDependencies(b, lib, module);
    b.installArtifact(lib);

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


    addDependencies(b, exe, module);

    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 = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });
    addDependencies(b, lib_unit_tests, module);

    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

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

    addDependencies(b, exe_unit_tests, module);

    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);
}

fn addDependencies(b: *std.Build, compile: *std.Build.Step.Compile, dep_module: *std.Build.Module) void {
    compile.addIncludePath(b.path("../../../Users/Jeff/include"));
    compile.addLibraryPath(b.path("../../../Users/Jeff/lib"));
    compile.linkLibC();
    compile.root_module.addImport("dungeon_weld", dep_module);
}

Here is the build file for the dungeon_weld package:

const std = @import("std");

pub fn build(b: *std.Build) void {

    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const lib = b.addStaticLibrary(.{ .name = "dungeon_weld", .root_source_file = b.path("src/main.zig"), .optimize = optimize, .target = target });
    lib.linkSystemLibrary("SDL2");
    lib.linkSystemLibrary("SDL2_image");
    lib.linkSystemLibrary("SDL2main");

    lib.linkSystemLibrary("c");

    _ = b.addModule("dungeon_weld", .{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const package = b.dependency("SDL", .{
        .target = target,
        .optimize = optimize,
    });
    const module = package.module("SDL");
    addDependencies(b, lib, module);

    b.installArtifact(lib);

    const run_cmd = b.addRunArtifact(lib);

    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 = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });
    addDependencies(b, lib_unit_tests, module);

    const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

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

    addDependencies(b, exe_unit_tests, module);
    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);
}

fn addDependencies(b: *std.Build, compile: *std.Build.Step.Compile, dep_module: *std.Build.Module) void {
    compile.addIncludePath(b.path("../../../Users/Jeff/include"));
    compile.addLibraryPath(b.path("../../../Users/Jeff/lib"));
    compile.linkLibC();
    compile.root_module.addImport("SDL", dep_module);
}

@jeffbdavenport jeffbdavenport reopened this Jul 5, 2024
@BratishkaErik
Copy link
Contributor

Here is the build file for the dungeon_weld package:

    _ = b.addModule("dungeon_weld", .{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const package = b.dependency("SDL", .{
        .target = target,
        .optimize = optimize,
    });
    const module = package.module("SDL");
    addDependencies(b, lib, module);

Here is your problem. Main build.zig uses the module that you export using b.addModule, but you don't link or import anything to it (even discards instead) so it complains that it can't find SDL nodule. Just assign this module to some variable and call addImport ("SDL", module) on it.

@jeffbdavenport
Copy link
Author

@BratishkaErik That fixed the issue. Interesting. I am confused by the redundancy. Why does the import needed to added to both the module, as well as the lib?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior
Projects
None yet
Development

No branches or pull requests

3 participants