Build.zig and old linux joke

Do you remember old joke about linux?

  • Linux is an operating system where absolutely everything can be done using the command line.
  • And you will still be forced to do everything through the command line!!!

My questions -

  • Is there any chance to extend build.zig.zon for standard use cases (declarative way) and use build.zig for hard staff?
  • Or we will be forced to do everything through build.zig?

I think that would go against the zig zen:

 * Only one obvious way to do things.
5 Likes

I don’t get it, can you explain the joke?

2 Likes

It might be farfetched, but I feel like this is a comparison of usability. Even a basic build.zig might be somewhat overwhelming in contrast to zon which also has a familiar layout. So GUI is a straightforward zon file that everybody can read right away. And CLI is a build.zig, where sometimes you might have to figure out where to start first :melting_face:.

I would say it’s a great idea; it might really cut the learning curve.

1 Like

Well if the fundamental problem is that the build.zig API is difficult to use, then the solution should be to rethink the API, instead of adding a second, less powerful API in the form of the zon file.

Adding a new API is just going to make it more difficult when people notice they do need the build.zig. And note that even something as simple as linking OpenGL requires code to branch on the platform which would not be expressible in zon.

2 Likes

the advertized benefit often becames an obstacle

1 Like

now i am working on number of zig projects and basically i fight with the build system

Zig has a lot of small separated projects/libs and on current stage developers need simple possibiliy to

  • use “foreign” packages
  • “export” own packages

I am talking about straight forward cases where build.zig.zon may looks like tree of steps,dependencies,modules, packages, libs etc (JSON or YAML style) and it will be imported/processed some way by build.zig

And sure more advanced cases requred full power of build.zig

I wasn’t thinking of another API but rather just the basic generation of build.zig for builds. Let’s say you have absolutely no reason to use the build.zig file in a very tiny project—the default build.zig from init does it all. So why clutter the workdir with a useless file you do not need to touch that only needs more space and maintenance time? If the build system could generate that file for you as it does during init, it would save an uncountable amount of bandwidth in the long run since there is no reason to commit build.zig updates, no time wasted on maintaining unusable code, etc.

2 Likes

Personally I think if your needs are so simple that you don’t need the build zig then zig run file.zig is the tool for you and when that isn’t enough anymore, then using a build.zig is fine with me.

I think there could be subtle things about that boundary and maybe changing little details about that could make the transition from one to the other better, but overall I would tend to agree with @IntegratedQuantum that it is probably more of a problem of either changing the build api (however I currently couldn’t say in which ways) or finding ways to explain it better to people who are unfamiliar with it.


It seems to me like people are too used to getting handed “magical” configuration interfaces where they can follow some tutorial that tells them:

  • first you turn this knob
  • then you put this string here
  • then you set this value to that setting
  • then you import this plugin from url bla
  • then you select "<your-feature-here>" from this dropdown
  • tada: here is your half broken half implemented game, that sort of does what you wanted, except the moment you want something slightly different, you have no idea what you would do to change it

I think these sorts of tutorials teach people a habit of wanting to follow a bunch of silly steps, over and over again, instead of understand and writing 20 lines of code once and be done with it and learning to be able to figure out stuff without needing a tutorial that specifically tells you how you accomplish this one particular thing.

Zig doesn’t want to do the many different silly configurations stuff, so reinventing features in the build.zig.zon doesn’t make sense, it would just end up reinventing the exisisting api.

I don’t understand, if you don’t need a build.zig then that is basically the “pristine tarball” strategy, where you just use the code without it having a build.zig. But what you write sounds to me like you want zig to behave as if the init-generated build.zig was present without you having one there, I think that would be against the zig zen in several ways:

  • Favor reading code over writing code. (how do I read what is just implied and may even change with zig versions)
  • Only one obvious way to do things. (now we have a weird default behavior)
  • Incremental improvements. (incrementally improving an invisible implied file seems awkward)
  • Avoid local maximums. (optimized the simple case, but slightly more complex case gets no benefit or is worse)
  • Reduce the amount one must remember. (need to remember there is a default file)
  • Focus on code rather than style. (there is one more file in my project, seems like a style issue to me)

Overall I think storage and networking bandwidth are a total non issue when you compare it to all these downsides that would give you code that implies too much and may even become difficult to run, because your loosing the explicit information of what should happen.

I think if bandwidth/storage is your concern, you could make a point about supporting fetching of packages from other protocols (for example content addressed protocols like some p2p networks or ipfs or similar things) so that those protocols can fetch from servers/nodes that are close to you, instead of half way around the world. And possibly use those also for de-duplication of redundant data.

But I think these storage concerns should be another discussion about possible improvements to package fetching and best practices that doesn’t have a huge impact on programmer workflow compared to what is already implemented.

I like the idea of content addressed online hosting of packages, but I am not sure about how these existing protocols work in practice, it is something that I find interesting but haven’t spend enough time trying out. I am also not super fond of things that rely on blockchain mechanisms, or bring a lot of complexity with them in the implementation.

4 Likes

This thread inspired me to brainstorm a little and I did come up with an idea:

There could be a “default” build.zig file. If you have only a build.zig.zon, then that default build.zig file would be used.

7 Likes

does it mean that build.zig.zon will include declarations of:

  • steps
  • packages
  • modules
  • etc

in addition to dependencies?

and default build.zig will “interpreter” it

Yep, that was my original sentiment. The zon file is evaluated when no build file is detected, and the build template is populated to place a temporary build file.

That (probably) would be a lot of overlapping with the build file. It makes more sense to pull this from code files. Step declaration would be too much if the default build file includes tests and other common steps.

Since build.zig.zon is a package description, and a package consists of modules and artifacts, it would be nice to have declarative definitions for package modules, package artifacts, and their imports.
EDIT: creating common steps for them, such as check, test, fuzz, build, run.

1 Like

sounds like this will blow zon files. modules and etc should not be present in the package abstraction. imagine you would see CLAP (rust) modules in the crate info. what use it would be? build conditionals—totally. but not modules

fuzz is not common, benchmark has better chances, but still not common.

I’ve actually assumed right along that there will be a declarative shorthand for doing common stuff in the build file, using Zon probably.

Centering the system around build.zig was the right move, because otherwise you’re always manipulating the build at some remove. “Declarative” build systems always grow toward Turing-completeness, it’s much better to start with not just a language, but the same language.

But the result is fairly verbose. It’s clearly possible to add a fully-declarative tree structure which handles the simpler stuff with minimal boilerplate, and hand that off to a parser which executes the appropriate methods.

I don’t see much of a reason to hurry along with that, though. Give the build system time to mature, then experiment with a syntax which tersely expresses the main operations we most frequently do:

.{ 
    .module = .{ 
        .name = "tubthumper",
        .root = "src/thump_tubs.zig",
        .imports = .{
             .washboard = .{
                .import = "scrape",
                .import = "rattle",
                .import = "roll",
        },
    .test_step = true,
}

Or whatever. It’s not hard to build this kind of thing on top of the build system we have, but I’d much rather do a bit of extra typing for awhile than get stuck with an endlessly-growing YAML-or-whatever monster of a build system.

5 Likes

i am especially pleased that even the mention of Zig Zen
did not stop the discussion :muscle:

I think that is because the zig zen points are just (important) guidelines that help people to focus in what direction the language should develop, but it is still difficult to interprete these rules and how they apply to all the different features and possibilities.

I think this discussion just shows how many perspectives there are and how tradeoffs are differently prioritized. My comment was of the sort “maybe we don’t need this feature”.
There are 2 different things being discussed here:

  1. whether the build.zig.zon should contain custom declarative configuration
  2. whether there should be default build.zig if you don’t have one

I am against 1., because I think it will result in reinventing what is already possible with zig code.

Another thing why I don’t like 1. is because it would lead towards more bloat in build.zig.zon files, the main purpose of those files is so that you can quickly determine the connections between packages, but if it also contained project specific configuration than it would slow down tooling that just wants to build a graph of dependencies and similar tooling.

I think if somebody ever figured out a declarative specification that actually is really nice (and everyone can experiment with this by implementing it in their test project within build.zig similar to what @mnemnion described) and then convinced everyone that this actually should be added, then zig could add this one specific way to specify things.

But I still think that you should have a separate build.zig.zon, maybe Zig could add zon-expressions to the language and just decide that if the build.zig is just one zon-expression it is a specific declarative description.

Or the build.zig.zon would be renamed to package.zon and you could have either a build.zig that contains code or you could have a build.zon that is a declarative description. Or a build.foo if the declarative description isn’t actually zon.

Anyways I think all these possibilities only make sense if somebody comes up with a declarative way that is a big benefit.


I thought a bit more about 2. and I think I would be open to having a default build.zig if it provides enough utilitarian value, basically if it is sufficient for a large number of simple projects, then I think it makes sense to add it.

However I still think it would make sense that you are required to have a build.zig.zon, ideally the default build.zig would never change what it is capable of, but that seems unlikely while it is still in development, so the build.zig.zon could get a field that indicates the zig/default_build_zig version.

I think if updating zig would just break packages that use the default build.zig there at least should be a trace somewhere that tells you under which version it worked.

2 Likes

Just to clarify, I agree with this, I don’t think any future shorthand way of declaring build dependencies should live in build.zig.zon. I do think Zon is the natural choice for expressing it, but it should go somewhere else.

1 Like

I don’t think hiding the build.zig file is fitting the Zig philosophy of “no hidden control flow”. The build.zig file doesn’t clutter the workdir, and since you don’t need to modify it, it doesn’t maintenance time neither.

It’s part of the process of building the project. When I open a new project from GitHub, I want to see the build.zig and evaluate the project at a high level.

I am against complexifying the build system to fix a non-existent problem. I prefer a straight forward approach with zero surprise or hidden knowledge. I am thinking about the new comers exploring the language, and therefore, learning the build system. Having the file generated and present all the time simplify the learning.

I think we can live with the few extra bytes it takes in the git repository. It saves me a couple of bytes in my head to not have to remember the file could/can/must?/should? be present…

On a side note. I am starting with Zig, it’s been only a couple of months. My first experience with the build system was: “that’s wonderful, I can understand everything! Everything in coded in Zig, the whole ecosystem is made in Zig!”.

I would be very sad to see the Zig code be transposed to a kindof DSL that we will have to learn instead of Zig, parsed and checked with zls…

Could the API be simplified? Probably… But I believe the discussion is taking a tangent from “I fight the build system”.

4 Likes