Default or implicit `build.zig`

I watched Zig Build System Basics yesterday and had some scattered thoughts about the build system.

First off, I think the build system has improved greatly since I picked up Zig in 0.11.0, and I think it’s heading in the right direction. However, I can’t help but complain about the boilerplate needed to set up a new project. I don’t use zig init because I don’t like all the comments and superfluous examples it puts in the generated files. It’s great for someone just getting started, but for someone who’s done it dozens of times it seems like it’s almost faster to just write it from scratch by hand each time than to use it and remove/rename the generated content. Lately, I haven’t been writing a build.zig and instead just putting all my logic into a single file and calling zig run myfile.zig or zig build-exe on it. However, the second I need a dependency, I write a build.zig.

I actually think a minimal zig init would be great: it wouldn’t add any comments to any of the generated files; it would add only the minimal subset of project setup (a build.zig that builds a single executable). I think it would also be nice to have another flag where we could specify whether we wanted to create a library (i.e. a .so or .a/.dll or .lib), a module, or an executable.

Most of my build.zigs look nearly identical (aside from some variable names). It’s not until I get much further downstream that I need to reach into the toolbox (addSystemCommand, linkSystemLibrary, etc.). In my experience, many projects I’ve seen on GitHub and elsewhere look nearly identical as well. It’s not until the package provides cross-platform behavior not found in the build system that the build.zig begins to change.

So, I was thinking: what if zig build could detect if build.zig.zon was present but build.zig was absent, and provide a default build.zig implementation based on some conventions. For example, if src/main.zig exists, it’s built into an executable and given the name retrieved from the name field in the build.zig.zon. Similarly, if src/root.zig exists, it’s built into a module that’s automatically added to the exe’s imports. Additionally, the default build script could parse the dependencies out of the build.zig.zon and add them as imports to the modules as well.

I feel like this would work for the vast majority of Zig users that are either just starting out or users that are building simple applications and tools that don’t need complex build logic. When a user does need more complex build logic, or they want to stray from the main.zig/root.zig convention, they can provide their own build.zig and it would function as it does now.

This idea is obviously not novel, and closely resembles Cargo for Rust: you don’t need a build.rs unless you need more complex build logic. However, my experience with Cargo and build.rs is that it’s more of a hook into the build system than the build system itself. Users could use zig build-exe directly, but I think zig build is more natural and human-friendly, whereas zig build-exe is intended to be wrapped by a higher-level script/application.

Anyways, that’s about all I have. Just some random thoughts. I’m not petitioning for a change or anything, but I would like to know what others think (except maybe some improvements/additions to zig init, that would be cool).

2 Likes

Until we have a more permanent solution there’s a workaround where you find the init folder in your zig install and modify these files.
Running zig init simply copies them over so changing them one time instead of in every project has been a great time saver.

3 Likes
3 Likes

Agreed, the current zig init is too noisy. Instead of demonstrating and explaining all sorts of build system and language features it should just create a minimal ‘Hello World’:

  • src/main.zig => just print ‘Hello World!’
  • build.zig => just build main.zig into an exe
  • build.zig.zon => just the minimal info required for an exe

…or maybe put that under a cmdline arg, like zig init --minimal.

…eventually it would be nice if zig init supports user-provided templates, e.g. ‘initialize a sokol/raylib/godot project’, but that might go too far :wink:

2 Likes

The core repo is probably not the right place for it, but this would be a great community effort. Maybe a ziginit tool that has a repository of good starters that people can add templates.

1 Like

While it doesn’t go that far, tensorush’s liza is the tool I use now. Auto generates the build steps that I want every one of my projects to have anyway (check, cov, etc)

7 Likes

How about zig init --verbose for a noisy build.zig while by default zig init creates a minimal version?

1 Like

If you’ve discovered a template that fits your usual project, then save it somewhere and copy it. (In my case I made a template.zip that just unpack where I want the project to be and edit the things that need to differ (which you have to do anyway no matter what templating mechanism you use). No need for Zig to follow what happens to work for any given person’s typical projects.

2 Likes

I also find it’s kind of hard to have a default template that do everything you want. Some might say a default zig init should mimic the build-exe other more things or versatile things like integrating C by building it or linking it.

In the end all of this is just to reflect the terrible fact not every project is the same and there is kind of an infinite balance of things possible to do with the build system.

I’m personally fine with the current state of zig init even if it’s a little bit to verbose but in the end if I want to start a new project, I usually just copy paste things from github I made or other made as inspiration.

I just discovers that tool liza but in the end we can’t really find a solution that will make everyone happy. I like this ideas of having community base starter tool or even something more simple like community base zig github repo as a more niche starter pack.

Again everybody need is different. It’s not really feasible to satisfied every usecase in a starter template.

3 Likes

I don’t think the point is to fit every usecase. The point is to provide some well known starting points that people can reach for. I would expect people to divert from the templates pretty quickly as they build out and need more from the build system.

I know I learn from seeing how other people do things. It is a big help to see how other build.zig files do things as I continue to learn the system. Having a repo that you can point people to as examples would be a help.

The problem with this is that only you have the template. This is fine if you have a certain way you like to do things. What we are discussing is how new users could discover these. Having a Zip on one machine isn’t very discoverable.

I’m glad someone went ahead and did this, kudos @tensorush.

I just use a script, it’s called, uh. it’s called ziggit, y’know. zig. git.

It’s in Python so I don’t want to show it off. But it gets the job done.

Something like liza is the right solution for this particular papercut IMHO. Although it would be cool if Zig did grow a “default build.zig”, I don’t think it should have a complex apparatus for getting things up and running. That’s a better role for community tooling, there’s more room for a variety of approaches, and getting out of various local optima in the process.

I’m likely to stick with ziggit though. It does everything I need it to, and nothing I don’t.

4 Likes

I’ve changed the default template based on my real-world experience interacting with newcomers to the language.

The new template sets up 1 module and 1 executable. No more mention of C interop in the template. This should serve the most common use cases and also hint at the idea that if you’re making a library you should consider having tools for whatever you’re doing (eg syntax checker CLI for a langauge parser) and if you’re making an executable, you should have the core functionality be available as code that can be embedded directly by consumers.

And I’ve also added a strip flag to generate files without comments.

Here you can read a bit of the rationale:

10 Likes