# Suggested project layout for multiple entry point for Zig 0.12?

**URL:** <https://ziggit.dev/t/suggested-project-layout-for-multiple-entry-point-for-zig-0-12/4219>\
**Category:** Help\
**Tags:** build-system\
**Created:** [May 7, 2024, 2:06pm UTC](https://ziggit.dev/t/suggested-project-layout-for-multiple-entry-point-for-zig-0-12/4219 "2024-05-07T14:06:56Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![matklad](https://ziggit.dev/user_avatar/ziggit.dev/matklad/32/2462_2.png) [@matklad](https://ziggit.dev/u/matklad)\
**Post date:** [May 7, 2024, 2:06pm UTC](https://ziggit.dev/t/suggested-project-layout-for-multiple-entry-point-for-zig-0-12/4219/1 "2024-05-07T14:06:56Z")

</div>

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

```zig
const baz = @import("tigerbetle").bar.baz;

```

instead of the current

```zig
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?

---

<div class="post-metadata">

**Author:** ![matklad](https://ziggit.dev/user_avatar/ziggit.dev/matklad/32/2462_2.png) [@matklad](https://ziggit.dev/u/matklad)\
**Post date:** [May 7, 2024, 2:32pm UTC](https://ziggit.dev/t/suggested-project-layout-for-multiple-entry-point-for-zig-0-12/4219/2 "2024-05-07T14:32:15Z")

</div>

For the reference, I think this is the commit that removed this feature from the build system:

> <https://github.com/ziglang/zig/commit/c20ad51c621ba18d2c90cc96d1b550831dc5d7a3>
>
> This moves many settings from \`std.Build.Step.Compile\` and into
> \`std.Build.Modul…e\`, and then makes them transitive.
> 
> In other words, it adds support for exposing Zig modules in packages,
> which are configured in various ways, such as depending on other link
> objects, include paths, or even a different optimization mode.
> 
> Now, transitive dependencies will be included in the compilation, so you
> can, for example, make a Zig module depend on some C source code, and
> expose that Zig module in a package.
> 
> Currently, the compiler frontend autogenerates only one
> \`@import("builtin")\` module for the entire compilation, however, a
> future enhancement will be to make it honor the differences in modules,
> so that modules can be compiled with different optimization modes, code
> model, valgrind integration, or even target CPU feature set.
> 
> closes #14719

---

<div class="post-metadata">

**Author:** ![marler8997](https://ziggit.dev/user_avatar/ziggit.dev/marler8997/32/77_2.png) [@marler8997](https://ziggit.dev/u/marler8997)\
**Post date:** [May 7, 2024, 3:45pm UTC](https://ziggit.dev/t/suggested-project-layout-for-multiple-entry-point-for-zig-0-12/4219/3 "2024-05-07T15:45:38Z")

</div>

> - 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.

I’d also like to know others thoughts on this. My current understanding is you have 2 options, either bifurcate your universe between the root module and a library module like you suggested, meaning you’ll have to import via file path or dotted accessors depending on which context you’re in, or, have one universe by putting all your root module files directly in the root src directory and use file paths for everything. aka src/main\_unit\_tests.zig src/main\_fuzz\_tests.zig, src/main\_ci.zig.

---

<div class="post-metadata">

**Author:** ![castholm](https://ziggit.dev/user_avatar/ziggit.dev/castholm/32/1330_2.png) [@castholm](https://ziggit.dev/u/castholm)\
**Post date:** [May 9, 2024, 12:59am UTC](https://ziggit.dev/t/suggested-project-layout-for-multiple-entry-point-for-zig-0-12/4219/4 "2024-05-09T00:59:02Z")

</div>

I’ll preface this by saying that I haven’t personally worked on any projects even a fraction of the scale of TigerBeetle, so this is mostly me just theorycrafting and thinking out loud.

That said, if your project has multiple entry points, and you (at this current state) prefer to treat it as a pile of code so that you can move fast and not need to waste time worrying code organization or API boundaries, then the easiest solution is clearly to move all entry point source files as close to the project root as necessary for them to be able to reference all the files they need.

But long term, I get the feeling that the more “philosophically correct” project structure would be to break out all reusable files into one or more modules. Even though the “file exists in multiple modules” compile error is only relevant in the context of a single artifact (you are free to reference the same source file from multiple artifacts), I think it makes the most sense structure your project in such a way that each source file is only referenced by one module/artifact in your `build.zig` script.

In other words, two different artifacts/modules should not both reference the same file via relative path `@import`, even if they are built separately and never link with each other. The two exceptions to this rule would be unit test artifacts (`std.Build.addTest`), since those only test test declarations from the root module and not ones in imported modules, and the `build.zig` script itself, in case it needs to reference things like constants or enums.

So using a project like TigerBeetle as a concrete example, I’d probably start off by breaking out all non-entry point source files into a `tigerbeetle_core` module, structuring it as a tree of declarations just like how `std` is structured. All other modules and artifacts (the main program, fuzzers, CI scripts, etc.) that wish to import any files belonging to this module should only do so via declarations re-exported by this module (i.e. `@import("tigerbeetle_core").flags` instead of `@import("flags.zig")`).

The main `tigerbeetle` executable, which is mainly just responsible for parsing CLI arguments and kickstarting all the necessary processes, would in turn import and delegate the hard work to `tigerbeetle_core`.

`src/unit_tests.zig` appears to only consist of a single comptime block referencing various files with tests, so for unit tests I would actually delete this file and move this block to whichever file is the root source file for `tigerbeetle_core`, so that a `tigerbeetle_core_unit_tests` artifact can use that same source file as its entry point (looping back to one of the exceptions mentioned earlier).
