naersk

repository·master·Indexed 21 days ago

https://github.com/nix-community/naersk

A Nix library for reproducible, sandboxed builds of Rust projects. Naersk integrates the Rust build process into the Nix ecosystem by parsing Cargo.lock files to turn Rust code into Nix derivations, providing a buildPackage function that handles dependency downloads and compilation without requiring Import From Derivation (IFD).

Tokens
6.3K
Snippets
10
Records
11
Agent score
27%

What's inside naersk

  1. What is Naersk?

    master

    Naersk is a Nix library designed to build Rust projects within the Nix ecosystem. It provides a buildPackage function that parses your Cargo.lock file, downloads all necessary dependencies, and compiles your application. This process leverages Nix's sandboxing and caching capabilities, effectively acting as cargo build but fully integrated with Nix.

    Key features:

    • Nix Integration: Turns Rust code into Nix derivations.
    • No IFD: Parsing happens directly inside Nix code, making it compatible with Hydra.
    • Sandboxed Builds: Utilizes Nix's caching and isolation for reproducible builds.
  2. How to use Naersk's buildPackage

    master

    The primary way to use Naersk is by calling naersk.buildPackage and providing the src argument, which points to the directory containing your Cargo.lock and source code.

    Basic usage in a Nix expression:

    naersk.buildPackage {
      src = ./.;
    }
  3. Configure a custom rust-toolchain in Niv

    master

    To use a custom rust-toolchain file with Niv, add the mozilla/nixpkgs-mozilla source and use rustChannelOf to define your toolchain. Pass this toolchain to Naersk via the cargo and rustc arguments.

    Note: Replace the empty sha256 with the actual hash from the error message after running nix-build.

    let
      sources = import ./nix/sources.nix;
      nixpkgs-mozilla = import sources.nixpkgs-mozilla;
    
      pkgs = import sources.nixpkgs {
        overlays = [
          nixpkgs-mozilla
        ];
      };
    
      toolchain = (pkgs.rustChannelOf {
        rustToolchain = ./rust-toolchain;
        sha256 = "";
        # ^ After you run `nix-build`, replace this with the actual
        #   hash from the error message
      }).rust;
    
      naersk = pkgs.callPackage sources.naersk {
        cargo = toolchain;
        rustc = toolchain;
      };
    in
      naersk.buildPackage ./
  4. Setup Naersk using Niv

    master

    To use Naersk with Niv, initialize and add the source:

    $ niv init
    $ niv add nix-community/naersk

    Then, create a default.nix file next to your Cargo.toml and Cargo.lock:

    let
      pkgs = import <nixpkgs> {};
      sources = import ./nix/sources.nix;
      naersk = pkgs.callPackage sources.naersk {};
    in
      naersk.buildPackage ./
    $ niv init
    $ niv add nix-community/naersk
  5. Configure a custom rust-toolchain in a Nix Flake

    master

    By default, Naersk uses the Rust compiler version provided by nixpkgs and ignores any rust-toolchain file in your project. To use a specific toolchain defined in a rust-toolchain file, you must use the nixpkgs-mozilla overlay and pass the resulting toolchain to Naersk's cargo and rustc arguments.

    Note: You must provide the correct sha256 hash for the toolchain. You can obtain this by running nix build and replacing the empty string with the hash provided in the error message.

    {
      inputs = {
        flake-utils.url = "github:numtide/flake-utils";
        naersk.url = "github:nix-community/naersk";
    
        nixpkgs-mozilla = {
          url = "github:mozilla/nixpkgs-mozilla";
          flake = false;
        };
      };
    
      outputs = { flake-utils, naersk, nixpkgs, nixpkgs-mozilla, ... }: 
        flake-utils.lib.eachDefaultSystem (system: 
          let
            pkgs = (import nixpkgs) {
              inherit system;
              overlays = [
                (import nixpkgs-mozilla)
              ];
            };
    
            toolchain = (pkgs.rustChannelOf {
              rustToolchain = ./rust-toolchain;
              sha256 = "";
              # ^ After you run `nix build`, replace this with the actual
              #   hash from the error message
            }).rust;
    
            naersk' = pkgs.callPackage naersk {
              cargo = toolchain;
              rustc = toolchain;
            };
          in {
            packages.default = naersk'.buildPackage {
              src = ./.;
            };
    
            devShell = pkgs.mkShell {
              nativeBuildInputs = [ toolchain ];
            };
          }
        );
    }
  6. Setup Naersk using Nix Flakes

    master

    You can quickly initialize a project with Naersk using the following commands:

    $ nix flake init -t github:nix-community/naersk
    $ nix flake lock

    Alternatively, you can manually define a flake.nix in your repository. The following example sets up a default package for nix build & nix run and an optional devShell for development.

    $ nix flake init -t github:nix-community/naersk
    $ nix flake lock
  7. Fix CMakeCache.txt errors in naersk builds

    master

    If your build fails with a CMake error indicating that the CMakeCache.txt directory is different from where it was created, you can resolve this by cleaning up stale cache files. Use the preBuild attribute in naersk.buildPackage to find and remove all CMakeCache.txt files before the build starts.

    naersk.buildPackage {
      # ...
    
      preBuild = ''
        find \
            -name CMakeCache.txt \
            -exec rm {} \;
      '';
    }
  8. Build a specific Rust example with naersk.buildPackage

    master

    To build only a specific Rust example instead of the entire crate, use the overrideMain attribute in naersk.buildPackage. You can inject --example <name> into the cargo_build_options environment variable within the preConfigure phase.

    naersk.buildPackage {
      pname = "your-example-name";
      src = ./.;
    
      overrideMain = old: {
        preConfigure = ''
          cargo_build_options="$cargo_build_options --example your-example-name"
        '';
      };
    }
  9. Run multiple binaries in a single workspace

    master

    In a multi-crate workspace setup, Naersk allows you to define and run separate binaries from different crates within the same repository. You can target a specific binary using the # syntax with nix run.

    For a workspace containing crates like bar and foo, use the following commands to execute their respective binaries:

    $ nix run .#bar
    Hello, Bar!
    
    $ nix run .#foo
    Hello, Foo!
  10. Use `buildPackage` to build Rust applications

    master

    Naersk provides the buildPackage function to create Nix derivations for Rust projects. It takes an attribute set describing the application's source, dependencies, and build configuration. Most options not recognized by Naersk are passed through to mkDerivation.

    naersk.buildPackage {
      # Assuming there's `Cargo.toml` right in this directory:
      src = ./.;
    
      someOption = "yass";
      someOtherOption = false;
      CARGO_ENVIRONMENTAL_VARIABLE = "test";
    }
  11. Reference `buildPackage` configuration options

    master

    The following table lists the primary configuration options for buildPackage. Note that many cargo-related options (like cargoBuildOptions, cargoTestOptions, etc.) expect a function that modifies the default value rather than a raw list or string.

    | Attribute | Description |
    | - | - |
    | `name` | The name of the derivation. |
    | `version` | The version of the derivation. |
    | `src` | Used by `naersk` as source input to the derivation. When `root` is not set, `src` is also used to discover the `Cargo.toml` and `Cargo.lock`. |
    | `root` | Used by `naersk` to read the `Cargo.toml` and `Cargo.lock` files. May be different from `src`. When `src` is not set, `root` is (indirectly) used as `src`. |
    | `gitAllRefs` | Whether to fetch all refs while fetching Git dependencies. Requires Nix 2.4+. Default: `false` |
    | `gitSubmodules` | Whether to fetch submodules while fetching Git dependencies. Requires Nix 2.4+. Default: `false` |
    | `additionalCargoLock` | Additional cargo lock used to specify crates required for build |
    | `cratesDownloadUrl` | Url for downloading crates from an alternative source Default: `"https://static.crates.io/crates"` |
    | `cargoBuild` | The command to use for the build. The argument must be a function modifying the default value. <br/> Default: `''cargo $cargo_options build $cargo_build_options >> $cargo_build_output_json''` |
    | `cargoBuildOptions` | Options passed to cargo build, i.e. `cargo build <OPTS>`. These options can be accessed during the build through the environment variable `cargo_build_options`. <br/> Note: naersk relies on the `--out-dir out` option and the `--message-format` option. The `$cargo_message_format` variable is set based on the cargo version.<br/> Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces. <br/> The argument must be a function modifying the default value. <br/> Default: `[ "$cargo_release" ''-j "$NIX_BUILD_CORES"'' "--message-format=$cargo_message_format" ]` |
    | `remapPathPrefix` | When `true`, rustc remaps the (`/nix/store`) source paths to `/sources` to reduce the number of dependencies in the closure. Default: `true` |
    | `cargoTestCommands` | The commands to run in the `checkPhase`. Do not forget to set [`doCheck`](https://nixos.org/nixpkgs/manual/#ssec-check-phase). The argument must be a function modifying the default value. <br/> Default: `[ ''cargo $cargo_options test $cargo_test_options'' ]` |
    | `cargoTestOptions` | Options passed to cargo test, i.e. `cargo test <OPTS>`. These options can be accessed during the build through the environment variable `cargo_test_options`. <br/> Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces. <br/> The argument must be a function modifying the default value. <br/> Default: `[ "$cargo_release" ''-j "$NIX_BUILD_CORES"'' ]` |
    | `cargoClippyOptions` | Options passed to cargo clippy, i.e. `cargo clippy -- <OPTS>`. These options can be accessed during the build through the environment variable `cargo_clippy_options`. <br /> Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces. <br /> The argument must be a function modifying the default value. <br/> Default: `[ "-D warnings" ]` |
    | `cargoFmtOptions` | Options passed to cargo fmt, i.e. `cargo fmt -- <OPTS>`. These options can be accessed during the build through the environment variable `cargo_fmt_options`. <br /> Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces. <br/> The argument must be a function modifying the default value. <br/> Default: `[ "--check" ]` |
    | `nativeBuildInputs` | Extra `nativeBuildInputs` to all derivations. Default: `[]` |
    | `buildInputs` | Extra `buildInputs` to all derivations. Default: `[]` |
    | `cargoOptions` | Options passed to all cargo commands, i.e. `cargo <OPTS> ...`. These options can be accessed during the build through the environment variable `cargo_options`. <br/> Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces. <br/> The argument must be a function modifying the default value. <br/> Default: `[ ]` |
    | `doDoc` | When true, `cargo doc` is run and a new output `doc` is generated. Default: `false` |
    | `cargoDocCommands` | The commands to run in the `docPhase`. Do not forget to set `doDoc`. The argument must be a function modifying the default value. <br/> Default: `[ ''cargo $cargo_options doc $cargo_doc_options'' ]` |
    | `cargoDocOptions` | Options passed to cargo doc, i.e. `cargo doc <OPTS>`. These options can be accessed during the build through the environment variable `cargo_doc_options`. <br/> Note: these values are not (shell) escaped, meaning that you can use environment variables but must be careful when introducing e.g. spaces. <br/> The argument must be a function modifying the default value. <br/> Default: `[ "--offline" "$cargo_release" ''-j "$NIX_BUILD_CORES"'' ]` |
    | `release` | When true, all cargo builds are run with `--release`. The environment variable `cargo_release` is set to `--release` if (and only if) this option is set. Default: `true` |
    | `override` | An override for all derivations involved in the build. Default: `(x: x)` |
    | `overrideMain` | An override for the top-level (last, main) derivation. If both `override` and `overrideMain` are specified, _both_ will be applied to the top-level derivation. Default: `(x: x)` |
    | `singleStep` | When true, no intermediary (dependency-only) build is run. Enabling `singleStep` greatly reduces the incrementality of the builds. Default: `false` |
    | `copyBins` | When true, the resulting binaries are copied to `$out/bin`. <br/> Note: this relies on cargo's `--message-format` argument, set in the default `cargoBuildOptions`. Default: `true` |
    | `copyLibs` | When true, the resulting binaries are copied to `$out/lib`. <br/> Note: this relies on cargo's `--message-format` argument, set in the default `cargoBuildOptions`. Default: `false` |
    | `copyBinsFilter` | A [`jq`](https://stedolan.github.io/jq) filter for selecting which build artifacts to release. This is run on cargo's [`--message-format`](https://doc.rust-lang.org/cargo/reference/external-tools.html#json-messages) JSON output. <br/> The value is written to the `cargo_bins_jq_filter` variable. Default: `''select(.reason == "compiler-artifact" and .executable != null and .profile.test == false)''` |
    | `copyLibsFilter` | A [`jq`](https://stedolan.github.io/jq) filter for selecting which build artifacts to release. This is run on cargo's [`--message-format`](https://doc.rust-lang.org/cargo/reference/external-tools.html#json-messages) JSON output. <br/> The value is written to the `cargo_libs_jq_filter` variable. Default: `''select(.reason == "compiler-artifact" and ((.target.kind | contains(["staticlib"])) or (.target.kind | contains(["cdylib"]))) and .filenames != null and .profile.test == false)''` |
    | `copyDocsToSeparateOutput` | When true, the documentation is generated in a different output, `doc`. Default: `true` |
    | `doDocFail` | When true, the build fails if the documentation step fails; otherwise the failure is ignored. Default: `false` |
    | `removeReferencesToSrcFromDocs` | When true, references to the nix store are removed from the generated documentation. Default: `true` |
    | `compressTarget` | When true, the build output of intermediary builds is compressed with [`Zstandard`](https://facebook.github.io/zstd/). This reduces the size of closures. Default: `true` |
    | `copyTarget` | When true, the `target/` directory is copied to `$out`. Default: `false` |
    | `postInstall` | Optional hook to run after the compilation is done; inside this script, `$out/bin` contains compiled Rust binaries. Useful if your application needs e.g. custom environment variables, in which case you can simply run `wrapProgram $out/bin/your-app-name` in here. Default: `false` |
    | `usePureFromTOML` | Whether to use the `fromTOML` built-in or not. When set to `false` the python package `remarshal` is used instead (in a derivation) and the JSON output is read with `builtins.fromJSON`. This is a workaround for old versions of Nix. May be used safely from Nix 2.3 onwards where all bugs in `builtins.fromTOML` seem to have been fixed. Default: `true` |
    | `mode` | What to do when building the derivation. Either `build`, `check`, `test`, `fmt` or `clippy`. <br\> When set to something other than `build`, no binaries are generated. Default: `