zig icon indicating copy to clipboard operation
zig copied to clipboard

Proposal: add `zig_version` field to build.zig.zon

Open marler8997 opened this issue 7 months ago • 4 comments

This issue proposes the field zig_version be added to build.zig.zon.

zig_version would specify the latest zig version that the project has been tested to work on. If a project goes to the effort of supporting multiple zig versions, it can indicate backward compatibility with the existing minimum_zig_version field. This provides a mechanism for projects to report compatibility with multiple versions of zig, which is useful for both users and future tooling.

In practice, I expect most projects to only use zig_version. minimum_zig_version would be most useful for projects that have many other projects depending on them, where the effort to support multiple versions might be justified. For this reason I additionally propose that zig_version be a REQUIRED field for all projects moving forward and minimum_zig_version be kept as OPTIONAL.

P.S. the zig_version would not exclude compatibility with future zig versions, but, would serve as an indicator that you're in "uncharted waters" for that package

marler8997 avatar May 25 '25 03:05 marler8997

while this could provide some great dx in the meantime i think its worth pointing out that it will not be necessary post-1.0 and minimum_zig_version would go back to the one providing much more value.

are you envisioning a warning printed during zig build ?

are you envisioning it treating master vs tagged releases any different?

nektro avatar May 25 '25 09:05 nektro

Once the language hits 1.0, Zig may still bump its version to reflect changes beyond just the language itself, like updates to the stdlib or tooling. If not, then we might eventually want a new field like toolchain_version or minimum_toolchain_version?

Regarding warnings: I can imagine cases where this version info could help Zig guide users when something isn't working as expected, but I'd need to explore the implementation to say for sure. That said, the biggest DX improvements I had in mind come from making this new field required, which are:

  • No more wasting time figuring out which Zig version a project requires. I curse every minute of my life wasted doing this.
  • Forgetting to update the version when you make breaking changes with the old version is no longer possible.
  • Tooling like ZLS, zig fmt, editors, etc., could derive which version of zig to use for specific files/projects.

An alternative solution to get the same benefits would be to make minimum_zig_version required, but that forces projects supporting multiple versions to advertise the oldest one when they’d probably rather highlight the latest. I find it's always useful to specify the latest known working version, but only sometimes useful to specify an older compatibility version.

I haven't been able to come up with a use case that shows why we'd need to treat dev/release versions differently, so let me know if you think of any.

marler8997 avatar May 26 '25 03:05 marler8997

if .zig_version is mean to be the maximum version the project works with and .minimum_zig_version is the minimum version the project works with, wouldn't it be more consistent to use .maximum_zig_version instead of just .zig_version?

VisenDev avatar May 28 '25 20:05 VisenDev

i interpreted .zig_version not to be the maximum it works with, moreso the maximum its been tested with by the author. forwards compatibility is highly likely but it can be good to note the latest known-good version should that ever not be the case and .minimum_zig_version needing a bump

nektro avatar May 28 '25 21:05 nektro

I interpret zig_version to mean “zig language specification version” (sort of like cargo’s rust “edition”. So, maybe a ziglang_version could make sense at that point. Might that make sense?

It then becomes zig’s job to support transpiling/compiling older versions and communicating to its user base whenever new versions of zig are deprecating older zig language specification versions.

Just a thought. I might be thinking about it differently than others.

jimkring avatar Jul 15 '25 01:07 jimkring

I like the proposal of zig_version as that helps tooling. I see the benefit of having a field that can directly tell a user which zig version is recommended to use with said library.

But to me it looks like the optionality of minimum_zig_version and zig_version should be flipped, my reasoning for saying this is that minimum_zig_version is "stricter" in the sense that an application using zig 0.13 will not be able to ever use a library with minimum version 0.14. While it will be much less certain if your project that uses 0.13 can use a library with version 0.14, or when you jump to 0.15 on your project if the library will continue working as intended.

To me the "certainty" that minimum_zig_version provides is much greater than the certainty zig_version does.

nunokaeru avatar Oct 26 '25 11:10 nunokaeru

Interesting insight. I hadn't thought through this variation but now that I have, it seems fine making either one required. Both seem to encourage slightly different behavior, it's unclear to me whether one is better? I think the important thing is that at least one of them becomes required.

marler8997 avatar Oct 27 '25 01:10 marler8997

Some inspiration from other languages:

  • npm: version range, not enforced (warning by default), optional (https://docs.npmjs.com/cli/v7/configuring-npm/package-json#engines)

    {
      "engines": {
        "node": ">=0.10.3 <15"
      }
    }
    
  • Python (pyproject.toml): version range, enforcement depends on package manager, optional (https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#python-requires)

    [project]
    requires-python = ">=3.8"
    # or requires-python = ">=3.12, <3.13"
    
  • Rust: minimum version, enforced, optional (https://doc.rust-lang.org/cargo/reference/rust-version.html)

    [package]
    rust-version = "1.56"
    
  • Go: minimum version, enforced, optional (https://go.dev/doc/modules/gomod-ref#go)

    module foo
    
    go 1.14
    

linusg avatar Oct 27 '25 13:10 linusg

I think this proposal needs to clarify what it means by "required". The field is present? The field is present and syntactically valid? The version is actually enforced any time zig interacts with the package in any way?

linusg avatar Oct 27 '25 13:10 linusg

Present? Yes. Syntactically Valid? Yes.

The enforcement question has led me back to my original proposal; make zig_version required rather than minimum_zig_version.

zig_version states "this version works" without claiming anything about other versions whereas minimum_zig_version excludes versions below a threshold. Both require the project to maintain a working version, but minimum_zig_version additionally requires maintaining an exclusion range. Maintaining a range of versions that "doesn't work" is more difficult than maintaining one that does, as the latter would be tested/verified throughout development with tooling. IMO maintaining a range of excluded versions is likely to become incorrect over time and I'd rather have the metadata unspecified rather than be incorrect. An incorrect range prevents usage with older versions that actually work, but using a project that has not specified a range but doesn't work is no worse off.

marler8997 avatar Oct 27 '25 16:10 marler8997

Hoping not to throw more oil into the fire but I want to raise another question. Usually when thinking about versioning of packages being used there’s two different trains of thought:

  1. I’m writing a library. In this case one usually wants to be permissive, as in most likely you want to define only a minimum version of zig.

This use case prefers being permissive because it allows library A to be a dependency of library B and it allows C to depend on a different version of A . This can be quite common for dependencies that are widespread (for example: serde and tokyo in Rust).

Without the permissiveness the writer of the application would be stuck on whichever zig version library A defines and upgrading a non trivial amount of dependencies could become very challenging. Int he case of unmaintained libraries, one could become stuck on an old zig required version if library B is unmaintaned and depends on an “old” version of A.

  1. I’m writing an application. In this case, usually it’s preferred to configure my project to pin all of my dependencies to certain versions, including the compiler version.

This is usually done so everyone working on the same project has the exact same versions of each dependency.

Being able to bump zig without having to bump each dependency can be very advantageous as new versions of libraries come with their own risks (bugs, breaking changes etc).

I’m not sure which current ecosystem does it best but I think looking at some of the problems faced by those ecosystems could lead to a better proposal. Around the 8.30 mark in this talk about UV a python package manager https://youtu.be/gSKTfG1GXYQ?si=Xl8Qn1xx1m6ADogP they go into some details of the problems they faced when dealing with projects that have dependencies of dependencies some of them interconnected and on different versions.

nunokaeru avatar Oct 28 '25 01:10 nunokaeru