Best way to pin Zig version today?

I want to write a tiny program in Zig today, such that, without any maintenance, I could come back to it in five years, and still be able to compile & run it. As Zig isn’t stable yet, this means I need to pin a specific version of Zig compiler.

What’s the best way to do that? I could use various Zig version managers, but I can’t be 100% sure that they themselves would be around 5 years down the line.

I could use shell.nix with a pinned version of nixpkgs. For that, I am pretty sure it will be there many years down the line, but that sounds like “you wanted a banana, you got yourself a banana, a gorilla holding the banana, and half of the rest of the jungle”.

I guess I could manually download specific Zig version from the website. Does Zig guarantee that download URLs are stable even for per 1.0 Zig versions? If I go that way, what’s the canonical download script to copy paste?

4 Likes

From my experience the download urls are pretty stable, but I wouldn’t bet on it. Who knows what could happen within 5 years.

The safest way to guarantee that it still works in 5 years would be to package a copy of the compiler with the source code. It is just 40 MB (per supported platform) after all.

3 Likes

If that program is so important for you wouldn’t it be better to adjust it after each Zig release (if needed), either manually or using zig fmt?

Hello,
it is for stable version 0.11.0 if version 0.11.1
come this will be the last for 0.11
this code is for linux

rm -r $HOME/.zig

#wget https://zigbin.io/master/x86_64-linux.tar.xz
#tar -xf x86_64-linux.tar.xz
#mv zig-linux-x86_64* $HOME/.zig
#rm x86_64-linux*

wget https://ziglang.org/download/0.11.0/zig-linux-x86_64-0.11.0.tar.xz
tar -xf zig-linux-x86_64-0.11.0.tar.xz
mv zig-linux-x86_64-0.11.0 $HOME/.zig
rm zig-linux-x86_64-0.11.0*

don’t forget to export .profil
export PATH=/home/soleil/.zig:$PATH

I use this wrapper script (as ./zig) in all my projects to pin the version of zig last used to successfully build it. ./build.zig.version and ./zig are then checked in and ./zig is used to build. This allows me to have some projects really up-to-date and others possibly lagging quite a bit.

#!/bin/bash
set -e

ARCH=$(uname -m)

BASEDIR="$(cd "$(dirname "$0")" && pwd)"
ZIGDIR=$BASEDIR/.cache/zig
VERSION=$(< build.zig.version)
ZIGVER="zig-linux-$ARCH-$VERSION"
ZIG=$ZIGDIR/$ZIGVER/zig

if [ "$1" == "update" ] ; then
    curl -L --silent https://ziglang.org/download/index.json | jq -r '.master | .version' > build.zig.version
    NEWVERSION=$(< build.zig.version)

    if [ "$VERSION" != "$NEWVERSION" ] ; then
        echo zig updated to $NEWVERSION
        exit 0
    fi
    echo zig version $VERSION is up-to-date
    exit 0
fi
    
(
    mkdir -p "$ZIGDIR"
    cd "$ZIGDIR"
    TARBALL="https://ziglang.org/builds/$ZIGVER.tar.xz"

    if [ ! -d "$ZIGVER" ] ; then
        curl "$TARBALL" | tar -xJ
    fi
)

exec $ZIG "$@"
5 Likes

I whipped up a new project I’m calling “anyzig” which does something very similar to this script: GitHub - marler8997/anyzig

This is a binary tool that leverages the Zig fetch implementation from the Zig repo itself in order to fetch Zig into the global cache.

It’s meant to replace the ‘zig’ program in your path and serve as a sort of “universal zig command-line tool” that will work with any project/version.

It’s very new and I’m still playing around with it to find the best set of commands but so far seems really nice. I think this will deprecate zigup for me.

6 Likes

Download urls bitrot for nightly builds, but are stable for releases. zig2nix has cachix cache for zig builds but that’s also unfortunately only 5GB in size as I don’t have a paid plan. However zig2nix also offers git build, so if you point to certain zig2nix commit hash you’ll be sure to always get zig version the README says the git build points to (built from source).

If you have a local nix cache (or on a remote disk) then using bitrotting urls can be fine too.

I use a convention - i put a .zig-version file in the root of the project with the version I’m developing with. The file has the version number like (0.13.0, for instance). I’m making the assumption that finding previous versions of zig stable releases will always be easy to do for many years to come.

This question is confusing to me. I feel like you are making strange assumptions that would be better to make explicitly for discussion.

For instance, “I could use various Zig version managers” - this seems to imply that you won’t be able to find a zig 0.13.0 binary that runs on whatever computer you have in 5 years? Why on Earth would that be the case? Why would you even want a version manager if you’re pinning to a version? What does version managers have anything to do with this topic?

What exactly are you worried about being different in 5 years? ziglang.org is down? The URL is different? How is that even a problem?

I’m so confused.

Edit: nixpkgs?? huh???

I need a problem statement to make heads or tails of this.

Let me try to be more specific! I have a repository github.com/matklad/stuff. Ten years from now, I want to run:

$ git clone github.com/matklad/stuff && cd stuff
$ magic-command-from-readme

And have that give me a working build. I don’t know what OS I will be using ten years from now, I don’t know what tools are available on that OS. And I want to minimize the amount of installation/downloading that the user needs to do manually, and I especially want to remove manual installation of non-current versions of software. In other words, while adding “this requires Zig 0.13 to build” would be enough for a motivated reader with some free time, I want to minimize time wasted on getting software to build.

4 Likes

Good desire!

The only two languages I know of that are remotely ready for this feature are C and Angular.

C is very stable: an “in the lane” posix C program written 25 - 30 years ago will compile today with whatever compiler you have (including zig), with high odds of no changes.

Google has invested in support for angular; each version of angular contains notes on how to upgrade from the prior version; some automated, some not. So, assuming angular is still here in ten years, one could iterate from version angular.ancient to angular.current.

It takes time to reach that level of maturity - either calendar time (C) or FTE/man-months (angular).

The any OS requirement may steer you away from a compiled “machine code” language; it is more feasible in a byte-code language - TypeScript, JavaScript, Python, etc, where the interpreter acts as a shield against the architectural differences. Just think, 10 years ago, the Apple ARM architecture did not exist…AI/CUDA was not a thing, etc.

1 Like

A. You can compress your entire rootfs (Probability of working 99%)
B. You can use --store flag on nix (Probability of working 80%)
C. You can store all the required binaries in tarball (Probability of working 40%, if your dep is only static linked zig then 99%)

B method howto:

nix develop --store /tmp/store
# cleanup your main store
nix-collect-garbage -d
# test without internet access
nix run nixpkgs#bubblewrap -- \
   --unshare-net --dev-bind / / \
   -- nix develop --store /tmp/store
bash-5.2$ zig version
0.14.0-dev.3026+c225b780e

compress the /tmp/store for archival

Now whether your build depends on internet, or build.zig.zon has links to remote urls is another thing. You may have to archive your zig build cache as well.

3 Likes

Even for C you need to freeze your compiler and sysroot. gcc and clang break compilation sometimes, and recently it has increased more as they have started to turn things that used to be warnings into compilation errors, or becoming more strict in general.

Please let me know in advance if you want to turn this off, as I am still using it: ziglang/Dockerfile at main - ziglings/ziglang - Codeberg.org

Maybe the magic-command-from-readme could be some kind of portable executable that contains a wasm interpreter and starts the zig bootstrapping from wasm process and then continues with using zig to build zig, caching the intermediary products and then calls zig build.

I think it would at least be interesting to know if with the non-llvm backend the overall time for that is significantly lower and it also could be a fun project to try to get that time lower. (although a lot of the Zig focus is on things that will result in getting that time lower anyway)

I guess having a low time for that would be dependent on the architecture until they all get a native fast backend, but generally I would expect that to improve over time.
That command also could take arbitrary shortcuts when they are available like downloading a zig executable if it is reachable / there is internet.

I don’t really think that there is a way to get something that allows you to switch to a newer Zig version without doing any kind of maintenance, even if it is just specifying the new version, or running a script/subcommand to update it.
And it seems like all the approaches somewhat rely on outsourcing the maintenance to someone or doing it yourself.

Thanks for the feedback. No plans to remove zigup and I’m guessing there’s many others that would agree with your sentiment.

I’m also still in the exploratory stage for anyzig so if you want to give it a try and let me know if it works for your use case and/or if there are any use cases/features you’d like to make it better that would be appreciated :slight_smile:

1 Like