crane/docs/overriding_derivations.md
Ivan Petkov a3f0c63eed
Try to avoid IFD in vendorCargoDeps and crateNameFromCargoToml; also avoid recommending nesting cleanCargoSource and path (#641)
We don't need to nest `cleanCargoSource` and `path` just to populate a
default value for `name`. As they both ultimately delegate to
`builtins.path`, the nesting can lead to IFD in situations which are
otherwise avoidable
2024-06-10 20:53:46 -07:00

3.9 KiB

Overriding derivations

Sometimes it is useful for a downstream consumer of a derivation to override portions of its behavior (such as swapping out a dependency with another customized package, or to perhaps opt-in or opt-out of additional behavior). There are two main techniques to achieve this defined by nixpkgs: using .override and .overrideAttrs.

Neither of these are specific to crane, but are documented here as a general primer.

.override

The .override attribute comes from makeOverridable from nixpkgs, which is automatically invoked by callPackage. Normally using .override only changes the parameters made available to the function which prepares the derivation, but does not alter the derivation's attributes directly:

# my-crate.nix
{ craneLib
, lib
, withFoo ? true
, withBar ? false
}:

craneLib.buildPackage {
  src = craneLib.cleanCargoSource ./..;
  strictDeps = true;
  cargoExtraArgs =
      (lib.optionalString withFoo "--features foo") +
      (lib.optionalString withBar "--features bar");
}
# flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

    crane = {
      url = "github:ipetkov/crane";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    rust-overlay = {
      url = "github:oxalica/rust-overlay";
      inputs = {
        nixpkgs.follows = "nixpkgs";
        flake-utils.follows = "flake-utils";
      };
    };
  };

  outputs = { self, nixpkgs, crane, fenix, flake-utils, advisory-db, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          overlays = [ (import rust-overlay) ];
        };

        craneLib = crane.mkLib pkgs;
        my-crate = pkgs.callPackage ./my-crate.nix {
          inherit craneLib;
        };
      in
      {
        packages = {
          # The default definition
          default = my-crate;

          # Ensure all additional options are enabled
          my-crate-all = my-crate.override {
            withBar = true;
          };

          # Disable all optional functionality
          my-crate-minimal = my-crate.override {
            withFoo = false;
          };

          # Use a different `craneLib` instantiation: one with a nightly compiler
          my-crate-nightly = my-crate.override {
            craneLib = craneLib.overrideToolchain pkgs.rust-bin.nightly.latest.default;
          };
        };
      });
}

.overrideAttrs

The .overrideAttrs attribute comes from mkDerivation (which all crane APIs eventually call) and it allows changing what is passed into mkDerivation itself (i.e. this does change derivation attributes). It is a much more low level operation, and although it can be used to achieve the same things possible via .override, it may be more cumbersome to plumb the changes through.

Note that .overrideAttrs will not change what inputs crane APIs see, as it affects the derivation produced after those APIs have finished running. If you need to change behavior that way, consider using a combination of callPackage and .override.

# flake.nix
{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";

    crane = {
      url = "github:ipetkov/crane";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, crane, fenix, flake-utils, advisory-db, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = nixpkgs.legacyPackages.${system};

        craneLib = crane.mkLib pkgs;
        my-crate = craneLib.buildPackage {
          src = craneLib.cleanCargoSource ./.;
          strictDeps = true;
        };
      in
      {
        packages = {
          # The default definition
          default = my-crate;

          # Perform a build with debug logging enabled
          my-crate-debug = my-crate.overrideAttrs (old: {
            NIX_DEBUG = 10;
          });
        };
      });
}