Nix is a tool for package management and system configuration that can help developers build a project in a reproducible and reliable manner, without messing up versions during upgrades.
Much like the mina repository, you can use Nix to
handle the dependencies required across the codebase, including npm scripts.
When should I use Nix? If you cannot build the codebase locally (due to untrusty package manager, faulty versioning, or unavailable libraries), it is a good idea to try the Nix build instead. This can happen especially if you're using a Mac–and even more likely–with non-Intel chips.
The following command will install Nix on your machine.
sh <(curl -L https://nixos.org/nix/install) --daemonIf you're unsure about your Nix setup, the assistant will guide you towards a
clean installation. It will involve backing up your old /etc/X and /etc/X.backup-before-nix for X = {bash.bashrc, bashrc, zshrc}, and finally
uninstalling and reinstalling Nix from scratch.
warning for macOS users: macOS updates will often break your nix installation. To prevent that, you can add the following to your
~/.bashrcor~/.zshrc:# avoid macOS updates to destroy nix if [ -e '/nix/var/nix/profiles/default/etc/profile.d/>nix-daemon.sh' ]; then source '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' fi
After installing, the current shell won't be a Nix shell. To create one, open a new shell and type
nix-shell -p nix-info --run "nix-info -m"That should output some basic information about the configuration parameters for Nix.
Mina is packaged using Nix Flakes,
which are an experimental feature of Nix. However, compatibility with
pre-flake Nix is provided. If you wish to contribute the Nix
expressions in this repository, or want to get some convenience
features and speed improvements, it is advisable to enable flakes. For
this, you'll want to make sure you're running recent Nix (⩾2.5) and
have enabled the relevant experimental features, either in
/etc/nix/nix.conf or (recommended) in ~/.config/nix/nix.conf (meaning to add
experimental-features = nix-command flakes in that file):
mkdir -p "${XDG_CONFIG_HOME-${HOME}/.config}/nix"
echo 'experimental-features = nix-command flakes' > "${XDG_CONFIG_HOME-${HOME}/.config}/nix/nix.conf"Verify your flake support is working by running:
nix flake metadata github:nixos/nixpkgsStart by cloning the repository. Optionally, you can install dependencies with
npm i, but Nix should take care of all the packages.
git clone --recurse-submodules git@github.com:o1-labs/o1js.git
cd o1js
# npm installFrom a new shell, go to {REPO_PATH}/o1js and from there execute ./pin.sh to
update the submodules and add the flakes entries. Then, you can open a Nix shell
with all the dependencies required executing nix develop o1js#default.
./pin.sh
nix develop o1js#defaultOn macos the first time you run this command, you can expect it to take hours (or even a full day) to complete, due to the lack of cached builds.
Then, you will observe that the current devshell becomes a Nix shell with the right
configuration for o1js and mina.
From within the shell, you can build o1js and update the bindings.
npm run build
npm run build:update-bindingsIf you need to update the underlying mina code, you can also do so with Nix,
but from the corresponding subdirectory. In particular, you should build Mina
from the o1js subdirectory from a Nix shell. That means,
cd ./src/mina
./nix/pin.sh
nix develop minaUsing Nix can take up a lot of disk space if not optimized. Every time you run nix develop {SOMETHING}, Nix will create new generations taking gigabytes of data instead of replacing the old ones. This can soon become a problem in your hard disk if you don't handle it carefully. Here are a few indications that can help with this.
Nix has a garbage collector that is not used by default after every run. Instead, artifacts get accumulated in your disk unless configured otherwise.
This is why we recomend auto-optimise-store = true (you will be prompted to accept this). You can also run nix-store --optimize retroactively.
If you still need to free up space you can run nix-store --gc, unfortunately this can slow down futurue nix builds by forcing you to rebuild dependencies.
This can be mitigated with direnv and nix-direnv which can create garbage collector roots,
keeping one gc-root to the latest build of the dev shell so that nix-store --gc won't remove it.
You can also create a gc root any time you run nix build (until you remove ./result) so running nix build o1js#bindings before nix-store --gc may also help.
We suggest a few settings in flake.nix.
You will be prompted to accept or reject these the first time you use nix in this repo.
You can also use --accept-flake-config to accept all of them.
max-jobs = auto
For some reason the default is 1.
auto-optimize-store = true;
When building slightly different versions of the same repo your nix store can fill up with coppies of the same files.
This saves space by replacing them with symlinks.
substituters = ...
trusted-public-keys = ...
These make sure you are using the mina-nix-cache which will save time by downloading any derivations already available.
Anything built in CI is added to this nix-cache, so it should make a big difference in build times.
Errors while using Nix have been reported. This section collects a set of common errors and proposes fixes for them.
DISCLAIMER!
The proposed solutions might not work universally, and could vary depending on your local environment.
This section should be read as a starting roadmap, and engineers are highly encouraged to add any new error found
and possible fixes to improve the helpfulness of this document.When trying to update the bindings for o1js in MacOS, Nix might fail at
compiling the export_test_vectors with the following error log:
error: linking with `cc` failed: exit status: 1
= note: ld: library not found for -liconv
collect2: error: ld returned 1 exit status
error: could not compile `export_test_vectors` (bin "export_test_vectors") due to previous errorThat is because this library is not symlinked into /opt/homebrew since macOS
already provides this software and installing another version could cause
problems.
Install libiconv with
brew install libiconvand update your ~/.zshrc with the following lines
# libiconv config
export PATH="/opt/homebrew/opt/libiconv/bin:$PATH"
export LDFLAGS="-L/opt/homebrew/opt/libiconv/lib"
export CPPFLAGS="-I/opt/homebrew/opt/libiconv/include"
export LIBRARY_PATH="/opt/homebrew/opt/libiconv/lib:$LIBRARY_PATH"Alternatively, try this change in the src/mina/flake.nix file:
- devShellPackages = with pkgs; [ rosetta-cli wasm-pack nodejs binaryen ];
+ devShellPackages = with pkgs; [ rosetta-cli wasm-pack nodejs binaryen cargo libiconv];
The rust compiler and/or Wasm-pack might not be correctly setup in the Nix shell.
Error: wasm32-unknown-unknown target not found in sysroot: "/nix/store/w30zw23kmgks77d870i502a3185hjycv-rust"
Used rustc from the following path: "/nix/store/wcm8caqd6g7bcbddpyxan1jzj3apkmxy-rustup-1.26.0/bin/rustc"
It looks like Rustup is not being used. For non-Rustup setups, the wasm32-unknown-unknown target needs to be installed manually. See https://rustwasm.github.io/wasm-pack/book/prerequisites/non-rustup-setups.html on how to do this.
Caused by: wasm32-unknown-unknown target not found in sysroot: "/nix/store/w30zw23kmgks77d870i502a3185hjycv-rust"This is caused because the Rust compiler in Nix does not have access to the
corresponding wasm32-unknown-unknown target. Let {RUSTDIR} be the directory
of the Rust location inside Nix, as shown in the error code; e.g.
/nix/store/wcm8caqd6g7bcbddpyxan1jzj3apkmxy-rustup-1.26.0/bin, then you can
check the version of the compiler used by typing:
{RUSTDIR}/rustc --versionWhich will reply with something like
rustc 1.82.0 (f6e511eec 2024-10-15)Then the Wasm target can be automatically installed using
{RUSTDIR}/rustup target add wasm32-unknown-unknownAlternatively, this can be done manually downloading the right version of the target with
wget https://static.rust-lang.org/dist/rust-std-x.xx.x-wasm32-unknown-unknown.tar.gzwhere x.xx.x corresponds to the version of rustc (in the example, 1.82.0).
Once unpacked, you should see a similar structure:
rust-std-1.82.0-wasm32-unknown-unknown
├── components
├── install.sh
├── rust-installer-version
└── rust-std-wasm32-unknown-unknown
├── lib
│ └── rustlib
│ └── wasm32-unknown-unknownFinally, the wasm32-unknown-unknown folder must be moved into the
./lib/rustlib/ directory in the sysroot like so:
Let {SYSROOT} be the directory of the Rust in Nix shown in the error code;
e.g. /nix/store/w30zw23kmgks77d870i502a3185hjycv-rust, then the Wasm target
can be automatically installed downloading it from
mv rust-std-1.82.0-wasm32-unknown-unknown/rust-std-wasm32-unknown-unknown/lib/rustlib/wasm32-unknown-unknown {SYSROOT}/lib/rustlib/wasm32-unknown-unknown/error: "/nix/store/w30zw23kmgks77d870i502a3185hjycv-rust/lib/rustlib/src/rust/Cargo.lock"
does not exist, unable to build with the standard library, try:
rustup component add rust-src --toolchain nixInstall cargo on your host machine. If doing so does not solve the problem, it
is very likely that the whole Nix setup has gone wrong and it is very advisable
to install it from scratch.
When several clones of the repository are present in the system and both have
used Nix (or if it has been moved from one location to another), Nix might cache
an old path, breaking builds. For example, typing nix develop mina
would complain and produce the following error:
error: resolving Git reference 'master': revspec 'master' not foundThen, the error message would still contain old directories.
Rerun pin.sh and src/mina/nix/pin.sh.
On MacOS, nix may ignore changes to files when nix commands are run and reuse the flake cached in its registry. Running commands like nix develop o1js and nix run o1js#update-bindings will reuse the cached version of the flake. As a result:
- The devshell could be missing newly added dependencies.
- Builds executed directly with
nix runcould be generated from old source files.
There are two ways to ensure Nix recognizes flake changes:
- Rerun
pin.shto force an update to the registry, then run your command. - Reference the flake by its directory path rather than its registry name. This forces Nix to use the current contents of the directory:
nix develop .'?submodules=1#default'