crane

repository·master·Indexed 23 days ago

https://github.com/ipetkov/crane

A Nix library designed to build Cargo (Rust) projects. It provides automatic source fetching from Cargo.lock, incremental dependency builds, and seamless vendoring of Git and registry-based dependencies. It includes built-in support for tools like clippy, rustfmt, cargo-audit, and cargo-nextest, as well as specialized functions for WASM builds via Trunk and cross-compilation for Windows and musl.

Tokens
31.3K
Snippets
73
Records
151
Agent score
81%

What's inside crane

  1. Overview of Crane features

    master

    Crane is a Nix library designed for building Cargo (Rust) projects. It provides several key capabilities for Nix-based Rust development:

    • Automatic Source Fetching: Uses your Cargo.lock file to automatically fetch dependencies.
    • Incremental Builds: Builds workspace dependencies once and reuses artifacts, allowing for fast linting, building, and testing of local changes.
    • Automatic Vendoring: Handles dependency vendoring in a Nix-compatible way. It supports Git dependencies out-of-the-box and can be configured to support alternative cargo registries.
    • Tool Support: Provides built-in support for various Rust and web tools, including:
      • clippy (linting)
      • rustfmt (formatting)
      • cargo-doc (documentation generation)
      • cargo-audit (security auditing)
      • cargo-deny (dependency analysis)
      • cargo-llvm-cov (coverage)
      • cargo-nextest (test runner)
      • cargo-tarpaulin (coverage)
      • trunk (WASM web development)
  2. Explore Crane configuration examples

    master
    The examples/ directory in the Crane repository provides various templates and configurations for complex Rust build scenarios. You can use these as starting points for specific project requirements such as cross-compilation, custom toolchains, or specialized linking.
  3. How to override function behavior using overrideScope

    master

    Crane is instantiated via pkgs.lib.newScope, which provides the .overrideScope method. This allows you to replace or modify internal definitions, similar to how overlays work in nixpkgs.

    When you override a core function (like mkCargoDerivation), the changes automatically propagate to any higher-level functions built on top of it (such as buildPackage or cargoBuild).

    Warning: Stability guarantees (SemVer) only apply to the documented API. Overriding internal functions that are not part of the public API is powerful but potentially brittle, as these internal details may change without notice.

    let
      craneLib = (inputs.crane.mkLib pkgs).overrideScope (final: prev: {
        # Example: Overriding mkCargoDerivation to set a default CARGO_PROFILE
        mkCargoDerivation = args: prev.mkCargoDerivation ({
          CARGO_PROFILE = "bench";
        } // args);
      });
    in
    {
        foo = craneLib.buildPackage {
          src = craneLib.cleanCargoSource ./foo;
        };
    }
  4. Avoid mixing [package] and [workspace] in top-level Cargo.toml

    master

    Defining both [package] and [workspace] in the top-level Cargo.toml can cause dependency caching issues. When both are present, cargo defaults to operating only on that specific package unless the --workspace flag is passed. This can cause subsequent derivations using -p another-crate to fail to find cached dependencies.

    Recommendation:

    • If the workspace contains multiple crates: Define only [workspace] in the top-level Cargo.toml.
    • If the workspace contains a single crate: You may define [package].
  5. How Crane's composition model works

    master

    Crane is built on the principle of composing cargo invocations to maximize caching efficiency and flexibility. It uses a two-step build pattern to prevent cache invalidation in CI and local development:

    1. Dependency Transformation: The source is first transformed so that only the dependencies listed in Cargo.toml and Cargo.lock are built. The crate's actual source code is excluded. This ensures that changes to the crate's own source files do not invalidate the derivation for the dependency build.
    2. Real Source Build: A second derivation is built using the actual source files. This step imports the artifacts generated from the first step, allowing for fast incremental builds.

    This pattern is extensible and can be applied to any sequence of commands, such as running lints, performing code coverage analysis, or generating types.

  6. Crane compatibility and versioning policy

    master

    When using Crane, be aware of the following versioning guidelines:

    • Master Branch: Breaking changes can occur on the master branch at any time. It is highly recommended to use a versioning strategy like Nix flakes or niv to pin your dependencies.
    • Tagged Releases: Periodic releases follow Semantic Versioning (SemVer) and changes are documented in the CHANGELOG.md.
    • Nixpkgs Compatibility: The test suite is validated against the latest stable nixpkgs release and nixpkgs-unstable. Breakages on these channels are treated as bugs.
  7. Compare `.override` vs `.overrideAttrs`

    master

    When customizing a crane derivation, choose between these two nixpkgs techniques based on your goal:

    1. Use .override when you want to change the parameters/inputs of the package function (e.g., enabling a feature flag like withFoo = true or providing a different craneLib). This is the standard way to configure a package's behavior.
    2. Use .overrideAttrs when you want to change the derivation attributes directly (e.g., setting an environment variable like NIX_DEBUG = 10). This is a low-level escape hatch for modifying the final build environment.
  8. Filter Cargo.toml manifests to reduce Nix rebuilds

    master

    To prevent unnecessary Nix rebuilds caused by changes to irrelevant fields in Cargo.toml (like documentation or authorship), you can use craneLib.cleanCargoToml or pass a filter to craneLib.mkDummySrc via the cleanCargoTomlFilter argument.

    craneLib.mkDummySrc (used by craneLib.buildDepsOnly) minimizes the source set to only Cargo.lock, .cargo/config.toml, and Cargo.toml files. Applying a filter further strips these manifests down to only the fields required for dependency resolution.

  9. Build a Cargo project using an alternative crate registry

    master

    To build a Cargo project that utilizes a custom or alternative crate registry instead of the default crates.io, you can use the alt-registry example from the Crane repository.

    Option 1: Start with a fresh directory

    You can initialize a new environment using the specific Nix flake for this example:

    nix flake init -t github:ipetkov/crane#alt-registry

    Option 2: Integrate into an existing project

    If you have an existing project, follow these steps:

    1. Configure your .cargo/config.toml to include the declaration of the alternative registry and its index URL.
    2. Ensure .cargo/config.toml is either committed to your repository or staged in git using git add -N .cargo/config.toml so Nix can see the file.
    3. Add the flake.nix configuration provided in the alt-registry example to your project root.
  10. Initialize a new Cargo project with SQLx support

    master

    To quickly bootstrap a new Cargo project that is pre-configured to work with the sqlx crate using Crane, use the nix flake init command with the specific sqlx template from the Crane repository.

    nix flake init -t github:ipetkov/crane#sqlx
  11. Quick-start an E2E testing project

    master

    You can quickly initialize a new workspace configured for End-to-End (E2E) testing using a Nix flake template. This setup is designed for scenarios where you have a server (e.g., an Axum web server with PostgreSQL) and an E2E test script that drives a browser (e.g., Firefox) to interact with that server.

    nix flake init -t github:ipetkov/crane#end-to-end-testing