Build system question about what’s idiomatic/the happy path.
At TigerBeetle, we have a bunch of sourcecode under the ./src
folder. There multiple entry points (pub fn main
s) among the source files — there’s:
src/tigerbeetle/main.zig
for the main binary./src/unit_tests.zig
for unit-tests,./src/fuzz_tests.zig
for fuzznig,./src/scripts/main.zig
for various CI helpers (implemented in Zig of course)- and also a bunch of completely wiled things here and there like
src/clients/c/tb_client_header.zig
which I am not even fully aware about myself
The way this works under Zig 0.11
is that, for all those entry points, we set .main_pkg_path = "./src"
, and then happily @import("../stdx.zig")
or what not.
My understanding is that under Zig 0.12
main_pkg_path
is gone: if ./foo/bar.zig
is the root file of the module, then all code has to reside under ./foo
subfolder.
What’s the best source code layout in this world? One thing we can do (and probably will do at least just for migration) is to say that non-entry-point stuff in src
is a separate module, and then in various files with main do
const baz = @import("tigerbetle").bar.baz;
instead of the current
const baz = @import("../bar/baz.zig");
But that doesn’t seem like a proper long-term solution:
- philosophically, we don’t really have good library level interfaces yet, and would rather treat everything like “one pile of code”, rather than introducing libary/binary internal boundaries.
- practically, it would be a bit confusing if some code would be able to import file paths, and other code would have to use dotted access.
- additionally, for dotted access to work we’d have to manually add
pub const
reexports everywhere, which also feels like needless work in this context, where we dont’ really care about API boundaries.
So, what’s the happy path here? What’s the right mental model to use in this case?