This Nix flake provides access to binary builds of Zig, including the latest nightlies. It also includes a setup hook, dependency fetcher, and packaging helper function, to make creating Nix packages for your Zig projects as seamless as possible.
Here's a simple example of a packaging a Zig project using a flake.nix:
{
inputs.zig.url = "github:silversquirl/zig-flake";
outputs = {zig, ...}: {
packages =
builtins.mapAttrs (system: zigPkgs: {
default = zigPkgs.default.makePackage {
pname = "<package name>";
version = "0.1.0";
src = ./.;
zigReleaseMode = "fast"; # or "safe" or "small"; only needed if you don't set a preferred release mode in your build.zig
#depsHash = "<fill this in from the error message>";
};
})
zig.packages;
};
}You can also create a devshell with a matching version of zls, using zig-flake's compatibility layer:
{
inputs = {
nixpkgs.url = "nixpkgs";
zig.url = "github:silversquirl/zig-flake/compat";
zls.url = "github:zigtools/zls";
zig.inputs.nixpkgs.follows = "nixpkgs";
zls.inputs.nixpkgs.follows = "nixpkgs";
zls.inputs.zig-overlay.follows = "zig";
};
outputs = {
nixpkgs,
zig,
zls,
...
}: let
forAllSystems = f: builtins.mapAttrs f nixpkgs.legacyPackages;
in {
devShells = forAllSystems (system: pkgs: {
default = pkgs.mkShellNoCC {
packages = [
pkgs.bash
zig.packages.${system}.nightly
zls.packages.${system}.zls
];
};
});
};
}There are a few other projects similar to this one, including @mitchellh's zig-overlay and @Cloudef's zig2nix. Zig is also packaged in nixpkgs, so for some projects you may not even need a flake at all.
Here is a feature comparison between these options:
| Feature | zig-flake | nixpkgs | zig-overlay | zig2nix |
|---|---|---|---|---|
| Binary packages | ✅ | ❌ | ✅ | ✅ |
| Source packages | ❌ | ✅ | ❌ | ✅ |
| Setup hook | ✅ | ✅ | ❌ | ✅ |
| Dependency fetcher | ✅ | ☑️1 | ❌ | ☑️2 |
| Packaging helper function3 | ✅ | ❌ | ❌ | ✅ |
| Flake templates | ✅ | ❌ | ❌ | |
| Languages used by the flake | Nix, Bash | Nix, Bash | Nix | Nix, Bash, Zig |
| Dependencies (excluding nixpkgs) | none | N/A | flake-utils5, flake-compat | flake-utils5 |
| Flake closure size (excluding nixpkgs)6 | 54KiB | N/A | 1.8MiB | 306KiB |
| Compatible with nixpkgs package names | ✅ | ✅ | ❌ | ❌ |
| Compatible with zig-overlay package names | ☑️7 | ❌ | ✅ | ❌ |
The most widely used flake for Zig is @mitchellh's zig-overlay. This flake uses a different package naming scheme than zig-flake (whose naming scheme is based on nixpkgs).
In order to allow flakes that depend on zig-overlay to easily switch to zig-flake, and to allow using follows to override dependencies' uses of zig-overlay,
zig-flake provides a compatibility layer that exposes all its packages with additional names, matching the zig-overlay naming scheme.
To use it, simply use the compat branch:
{
inputs = {
zig.url = "github:silversquirl/zig-overlay/compat";
other-flake.url = "...";
other-flake.inputs.zig-overlay.follows = "zig";
};
# ...
}Footnotes
-
the dependency fetcher provided by nixpkgs requires extra care to avoid refetching dependencies every time you change a source file ↩
-
zig2nix requires generating a Nix file based on your build.zig.zon. zig-flake and nixpkgs simply require keeping a single hash up to date ↩
-
automatically fetches dependencies and installs the setup hook, just to save a bit of boilerplate ↩
-
the flake templates provided by zig2nix already have a skeleton Zig project in them, as generated by
zig init. While this sounds like a great idea on the surface, it actually causes two problems:- Experienced Zig users typically do not use the default
zig inittemplate, as it's more of a tutorial than anything. zig initrandomly generates a package fingerprint based on the package name. Hardcoding this into a Nix flake template is a serious issue, as it means all projects generated by that template will use the same fingerprint.
- Experienced Zig users typically do not use the default
-
flake-utils provides helper functions for creating Nix flakes. However, these functions are overcomplicated, and the same result can be trivially achieved using
builtins.mapAttrs, as shown in the examples above, so it doesn't really serve any purpose. Because of this, most Nix veterans I've spoken to recommend against the use of flake-utils. ↩ ↩2 -
calculated using
nix path-info --closure-size $(nix flake archive --json | jq -r 'recurse(.inputs? // empty | del(.nixpkgs)[]) | .path') | awk '{total += $2}; END {print total}' | numfmt --to=iec-i --suffix=B↩ -
only when using the compatibility layer ↩