#Conceptual questions about the build system

1 messages · Page 1 of 1 (latest)

limber wren
#

TL;DR - Newbie confused about Modules vs. Libraries, interacting with them in the build system and subsequent usage in code. Looking for insights into how more experienced folks are approaching it.

Been playing with zig over the weekend and have been having a grand old time with it. Managed to get a basic SDL workflow up and running and have even drawn some circles!

During my travels I ran into a couple of things with the build system that have me scratching my head. These issues aren't so much implementation questions so much as me trying to adopt the mindset of what these specific pieces are trying to do and when to use them.

When you create a new project you get root.zig and main.zig and in the build system, the following occurs

    const lib = b.addStaticLibrary(.{
        .name = "learning",
        // In this case the main source file is merely a path, however, in more
        // complicated build scripts, this could be a generated file.
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    });

    // This declares intent for the library to be installed into the standard
    // location when the user invokes the "install" step (the default step when
    // running `zig build`).
    b.installArtifact(lib);

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

    // This declares intent for the executable to be installed into the
    // standard location when the user invokes the "install" step (the default
    // step when running `zig build`).
    b.installArtifact(exe);

I understand what all of these steps are doing on paper but its not incredibly clear WHY these are being done.
A: Because the root static library is redundant from the start not even imported into main
B: Its not clear how to import that other than @import("root.zig") which doesn't need the static library anyways.

So when is it considered "best practice" to go with the static lib approach? Should this be the default? It doesn't help that I also get error: unable to add module 'learning': already exists as 'root.zig' when trying to test how to actually import said static library.

Next up we have modules! Which added another layer of confusion.

See the following code:

    const cpu_lib = b.addModule("cpu", .{
        .root_source_file = b.path("src/lib/cpu.zig"),
    });

    exe.root_module.addImport("cpu", cpu_lib);

This is another way of bringing in code it seems. Which one should I choose in what scenarios? This has me scratching my head, more so when compounded with the previous point.

My final point of confusion. Needing to pass things to either exe or exe.root_module there are functions with the same name that exists under both types of *Compile and *Module but require different arguments and (I'm assuming) likely do different things.

This did lead to some headaches in trying to make code available to exe especially when trying to include SDL
For example:

    const sdl_include_path = .{ .cwd_relative = "/opt/homebrew/Cellar/sdl2/2.32.0/include/SDL2/" };
    const sdl_link_path = .{ .cwd_relative = "/opt/homebrew/Cellar/sdl2/2.32.0/lib/" };
    exe.root_module.addIncludePath(sdl_include_path);
    exe.root_module.addLibraryPath(sdl_link_path);

    exe.root_module.linkSystemLibrary("SDL2", .{});

(Ignore the hardcoded paths...I'm lazy)

Just looking for some more experienced insights into these issues and what the general mindset around this stuff is.

Thanks in advance!

toxic knot
#

modules are just zig code you import, libraries are compiled binaries that export symbols to be used from a program that links it. modules should be your default for zig->zig every single time, libraries are entirely unnecessary and force you to use C types to cross the "boundary" between the library and your application. it really only exists in the form it does here to demonstrate how it can be done, not that it should

#

things existing on both exe and exe.root_module are for legacy reasons, many options used to only exist on compile steps (exe, lib, obj) but now exist on modules, the functions on the exe were kept but (generally) deprecated, you should probably usually use the one on the module

#

they make take slightly different arguments but that should just be because one is using a newer API, they shouldn't functionally be different

limber wren
toxic knot
#

yes that's generally how it goes

limber wren
toxic knot
toxic knot
limber wren
#

(my understanding was that currently there's no way to map a full directory without using enumeration)

toxic knot
#

how'd you get that error exactly?

limber wren
#

when I was experimenting with trying to link the root static lib

    const lib = b.addStaticLibrary(.{
        .name = "learning",
        ...
    });

    b.installArtifact(lib);

    const exe = b.addExecutable(.{
        .name = "learning",
        ...
    });

    exe.linkLibrary(lib);
    exe.root_module.addImport("learning", lib.root_module);

...
#

then in main add const learning = @import(learning);

Fails on build

#

Originally I tried just linkLibrary but that didn't seem to make it available (which in hindsight is because as you said, needing to bring in as a c lib) so I added the root module import which seemed to make the lib available from an LSP PoV but would then cause the error to be output

toxic knot
#

can you run zig build --verbose? and send the output? I'm actually entirely sure I don't think I've seen that error

limber wren
#
/opt/homebrew/Cellar/zig/0.13.0/bin/zig build-lib -ODebug -Mroot=/Users/user/dev/zig/learning/src/root.zig --cache-dir /Users/user/dev/zig/learning/.zig-cache --global-cache-dir /Users/user/.cache/zig --name learning -static --listen=-
/opt/homebrew/Cellar/zig/0.13.0/bin/zig build-exe /Users/user/dev/zig/learning/.zig-cache/o/20283c98b40c8fba6430b8f7314cbe63/liblearning.a -ODebug -I /Users/user/dev/zig/learning/.zig-cache/o/544790c738d38eb183fa637997b2e9c3 --dep learning -Mroot=/Users/user/dev/zig/learning/src/main.zig -ODebug -Mlearning=/Users/user/dev/zig/learning/src/root.zig -ODebug -Mlearning=/Users/user/dev/zig/learning/src/root.zig --cache-dir /Users/user/dev/zig/learning/.zig-cache --global-cache-dir /Users/user/.cache/zig --name learning --listen=-
install
└─ install learning
   └─ zig build-exe learning Debug native failure
error: error: unable to add module 'learning': already exists as 'root.zig'

error: the following command exited with error code 1:
/opt/homebrew/Cellar/zig/0.13.0/bin/zig build-exe /Users/user/dev/zig/learning/.zig-cache/o/20283c98b40c8fba6430b8f7314cbe63/liblearning.a -ODebug -I /Users/user/dev/zig/learning/.zig-cache/o/544790c738d38eb183fa637997b2e9c3 --dep learning -Mroot=/Users/user/dev/zig/learning/src/main.zig -ODebug -Mlearning=/Users/user/dev/zig/learning/src/root.zig -ODebug -Mlearning=/Users/user/dev/zig/learning/src/root.zig --cache-dir /Users/user/dev/zig/learning/.zig-cache --global-cache-dir /Users/user/.cache/zig --name learning --listen=-
Build Summary: 3/6 steps succeeded; 1 failed (disable with --summary none)
install transitive failure
└─ install learning transitive failure
   └─ zig build-exe learning Debug native failure
error: the following build command failed with exit code 1:
/Users/user/dev/zig/learning/.zig-cache/o/d045ad9f64d46fae1347974a5d0d55c8/build /opt/homebrew/Cellar/zig/0.13.0/bin/zig /Users/user/dev/zig/learning /Users/user/dev/zig/learning/.zig-cache /Users/user/.cache/zig --seed 0xbc32aad8 -Ze44e65246f6a8147 --verbose
toxic knot
#

do you have that addImport twice? that's what it looks like

limber wren
#

I thought that too, but I haven't added it twice, unless something is calling it under the hood?