Repository navigation
Conversation
Add `flake.nix` with an overlay built on oxalica/rust-overlay, for Linux and macOS: * `kaniReleases.<version>` and `kaniReleases.latest`: Kani from its release bundle, with the `toolchain` link pointing at the exact nightly that release was built with. On Linux, the bundled binaries are patched with `autoPatchelfHook`, so they also run on NixOS. No `~/.kani`, rustup or `cargo kani setup` is involved. * `kaniPackages`: the toolchain, CBMC and Kissat for this checkout, read from `rust-toolchain.toml` and `kani-dependencies`, and a `nix develop` shell for `cargo build-dev`. A rustup shim provides the `RUSTUP_HOME`, `RUSTUP_TOOLCHAIN` and `cargo +<toolchain>` that the development build expects. `nix/versions.json` records each release's toolchain, CBMC, Kissat and bundle hashes. It is generated by `nix run .#update-versions`, which reads each release from its `kani-<version>` tag and takes bundle hashes from the digests GitHub publishes for release assets. `flake.lock` is excluded from the copyright check, like `Cargo.lock`.
Run `nix run .#update-versions` when a release is published, weekly in case a release event was missed, or by hand for a given version, and open a pull request with the updated `nix/versions.json`. Like the other update workflows, it only runs in model-checking/kani.
When `cbmc-update.yml` opens a CBMC upgrade pull request, also run `nix run .#update-versions -- --checkout`, so the new CBMC's source hash is recorded in `nix/versions.json` in the same pull request and `nix develop` keeps working on `main`. The new steps cannot block the CBMC upgrade: if they fail, `nix-versions-update.yml` records the hash at its next run. `update-versions --checkout` records only the CBMC and Kissat versions in `kani-dependencies`, and needs no git tags.
lalvesl
added a commit
to lalvesl/kani-nix-example-PR5098
that referenced
this pull request
Oct 30, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add a Nix flake: Kani releases, version selection and a development shell
First of all, thank you for building and maintaining Kani; it is a great and very helpful tool.
This PR solves the problems between Kani and Nix, for Linux and macOS users. With it, Kani works
with Nix out of the box: no
~/.kani, no rustup, nocargo kani setup, and no binary patchingwhen Kani runs. Users pick a Kani version, and Nix provides that exact release together with the
nightly toolchain it was built with:
Documentation:
nix/README.md.Maintenance: automated, and the data is generated
The only hand-written part is the Nix code in
nix/andflake.nix. Everything that changes withKani's releases and dependencies is either read straight from files Kani already maintains, or
generated and updated by CI:
rust-toolchain.toml)nix-versions-update.ymlrecords it innix/versions.jsonand opens a PRkani-dependencies)nix/versions.jsonis never edited by hand. It is generated bynix run .#update-versions,which reads each release from its
kani-<version>tag and takes bundle hashes from the SHA-256digests GitHub publishes for release assets, so nothing is downloaded.
instead of building the wrong version.
nixpkgsand rust-overlay inflake.lockkeep working if never updated; refreshingthem is optional.
Nix are not affected.
The problem today
Kani's support for NixOS lives in
src/os_hacks.rs. Aftercargo kani setupdownloads thebundle into
~/.kani, it patches the binaries withpatchelf, and finds the C++ standardlibrary with
nix-instantiate '<nixpkgs>'. This works on NixOS with channels, but:NIX_PATH, which flake-only setups do not have;project.
In #1298, it was suggested that "the most permanent solution" is proper Nix packaging. This PR
provides it, without changing the existing setup path.
How it works
kaniReleases.<version>.kaniis the official release bundle fromGitHub releases, the same file
cargo kani setupdownloads. It is installed in the Nix store,with its
toolchainlink pointing at the matching nightly from rust-overlay. Kani is notrebuilt.
rustc --versiondiffersfrom the
rustc-versionrecorded in the bundle.autoPatchelfHook, which rewrites only their dynamic linker and library search path. On macOSthey are used unchanged, because they already find the toolchain through
@loader_path/../toolchain/lib.kani-compiler/build.rsreadsRUSTUP_HOMEandRUSTUP_TOOLCHAIN, andkani-driverrunscargo +<toolchain>from a development checkout. Asmall shim provides both, so
cargo build-devworks innix developwithout rustup.release,
mainkeeps the released version inCargo.tomlwhile its toolchain moves on. Forexample,
mainsays 0.68.0 onnightly-2026-10-23, but the 0.68.0 release was built withnightly-2026-08-21.Files
flake.nix,flake.lockpackages,devShellsnix/overlay.nixkaniPackages(this checkout) andkaniReleases.<version>nix/pkgs/kani-bin.nixnix/pkgs/rustup-shim.nix,nix/pkgs/dev-shell.nixnix/pkgs/update-versions.{sh,nix},nix/versions.json.github/workflows/nix-versions-update.ymlnix/versions.jsonup to datescripts/ci/copyright-excludeflake.lock, likeCargo.lockTesting
Automated, in CI:
adapted from the tutorial. It has one shell per Kani version (
nix develop .#kani-latest,nix develop .#kani-0_67) and runscargo kaniin each, on x86_64 Linux, aarch64 Linux andaarch64 macOS. All 6 jobs pass:
run.
Deny.
Why Nix, briefly
For readers less familiar with Nix: it is a package manager that installs every package into its
own directory, identified by a hash of everything it was built from. For Kani, that means:
flake.lockpins the exact Kani release, nightly toolchain andCBMC. Everyone on the project, and its CI, gets the same files, checked against those hashes.
nix developgives a shell with Kani ready to use. There is noinstallation step and no
cargo kani setup.without conflicts, because nothing is installed globally (
~/.kani, rustup toolchains).Manual, on NixOS (x86_64):
nix flake checkpasses.nix develop,cargo build-devsucceeds, and./scripts/kaniverifies a sample harness.update-versionsis idempotent: rerunning it for a recorded release leavesversions.jsonbyte-for-byte unchanged.
Not tested: x86_64 macOS. GitHub no longer offers Intel macOS runners, and I have no access to
such a machine.
Alternative layout
If you would prefer the release catalog (
nix/versions.jsonand its workflow) outside thisrepository, it can move into a separate overlay repository, and this repository would keep only
the development shell. I am happy to split it that way.
Related: #1179, #1298, #2207, #4413
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.