A workaround to build Zig projects without direct network connection

  ·   3 min read

Motivation

Starting from Zig 0.11.0, a new feature called build.zig.zon is introduced. It’s basically a package management system, that allows developer to define dependencies of projects. When running zig build command, it automatically reads build.zig.zon file, and download a package from remote URL, extracts package to local path, then set references of build path for zig compiler.

I copied the file from zls as an example. We can see it depends on three packages, two from Github archive and one from Gist. Ideally when I run zig build, they should be downloaded and used.

.{
    .name = "zls",
    .version = "0.11.0",

    .dependencies = .{
        .known_folders = .{
            .url = "https://github.com/ziglibs/known-folders/archive/fa75e1bc672952efa0cf06160bbd942b47f6d59b.tar.gz",
            .hash = "122048992ca58a78318b6eba4f65c692564be5af3b30fbef50cd4abeda981b2e7fa5",
        },
        .diffz = .{
            .url = "https://github.com/ziglibs/diffz/archive/90353d401c59e2ca5ed0abe5444c29ad3d7489aa.tar.gz",
            .hash = "122089a8247a693cad53beb161bde6c30f71376cd4298798d45b32740c3581405864",
        },
        .binned_allocator = .{
            .url = "https://gist.github.com/antlilja/8372900fcc09e38d7b0b6bbaddad3904/archive/6c3321e0969ff2463f8335da5601986cf2108690.tar.gz",
            .hash = "1220363c7e27b2d3f39de6ff6e90f9537a0634199860fea237a55ddb1e1717f5d6a5",
        },
    },
}

I said “ideally”, yes. Unfortunately, the package can’t be compiled correctly in my local machine, because my network environment can’t stably connect to https://github.com. I usually use an HTTP proxy to access the contents. It does not work for Zig because zig build does not honor HTTP proxy at all, by the time I use it. In this case, a project using build.zig.zon can’t be built, but always stuck with an error like below:

Fetch Packages [3/3] binned_allocator...
error: ConnectionTimedOut

I’m reporting this to zig community, but before we have a fix, I need an approach to allow me download the dependencies, so I can build projects locally.

Cache is our friend

Zig build uses $HOME/.cache/zig to store source code of dependencies. The files downloaded from remote servers are all here. Here’s how to locate a package:

  1. The package should be put folder under $HOME/.cache/zig/p/<hash>/.
  2. The hash value can be found from .hash field in build.zig.zon.
  3. The root folder of package is the path to source code.

So, all I need is to download the package manually, extract it to the folder we need, and do the build. Let’s take binned_allocator as an example. It can be done in four steps below. We can also do this for the other two packages. Then I can successfully build zls locally.

# Step 1: Create folder structure. The name of folder is the value of
# .hash field in build.zig.zon.

PACKAGE_FOLDER=$HOME/.cache/zig/p/1220363c7e27b2d3f39de6ff6e90f9537a0634199860fea237a55ddb1e1717f5d6a5
mkdir -p $PACKAGE_FOLDER

cd $PACKAGE_FOLDER

# Step 2: Download package locally.
export https_proxy=http://127.0.0.1:8080/ # Replace it with proxy you use
wget https://gist.github.com/antlilja/8372900fcc09e38d7b0b6bbaddad3904/archive/6c3321e0969ff2463f8335da5601986cf2108690.tar.gz

# Step 3: Etract package
## Note that Gist adds a in-package folder with name of commit ID. Let's move
## the true content to root folder binned_allocator.zig and build.zig.
tar xfz 6c3321e0969ff2463f8335da5601986cf2108690.tar.gz
mv 8372900fcc09e38d7b0b6bbaddad3904-6c3321e0969ff2463f8335da5601986cf2108690/* .

# Step 4: safely remote downloads
rmdir 8372900fcc09e38d7b0b6bbaddad3904-6c3321e0969ff2463f8335da5601986cf2108690
rm -f 6c3321e0969ff2463f8335da5601986cf2108690.tar.gz

Conclusion

This is surely not a final solution. A correct fix is to ask zig build support HTTP proxy environment variable. However, we may have to live with it for a while, given Zig just only adds HTTP client recently, since v0.11. Zig is still young but growing fast. I will expect we fix it soon.