Fenix

repository·main·Indexed 22 days ago

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

A Nix-based Rust toolchain provider that serves as a replacement for rustup and the nixpkgs-mozilla overlay. Fenix offers minimal, default, and complete profiles for stable and nightly channels, providing granular control over Rust components and targets. It supports installation via Flakes, overlays, or as a set of packages, and integrates with makeRustPlatform, crane, and naersk.

Tokens
3.7K
Snippets
12
Records
13
Agent score
28%

What's inside Fenix

  1. Understand the Fenix Toolchain structure

    main

    A Fenix toolchain is an attribute set containing various components and helper functions.

    Components:

    • cargo: The cargo package.
    • rustc: The rustc package including rust-std.
    • rustc-unwrapped: The rustc package without rust-std.
    • rustfmt: An alias to rustfmt-preview.
    • rust-src: The source code for the standard library.

    Derivations:

    • toolchain: A derivation containing all components.
    • minimalToolchain, defaultToolchain, completeToolchain: Derivations based on specific profiles (not available in nightly toolchains).

    Functions:

    • withComponents : [string] -> derivation: Creates a derivation with a specific list of components.
    • combine : [derivation] -> derivation: Combines a list of components into a single derivation (use withComponents if components are from the same toolchain).
    • fromManifest, fromManifestFile, toolchainOf, fromToolchainFile, fromToolchainName: Functions to create toolchains from various manifest formats or names.
  2. Install Fenix as a Flake

    main

    To use Fenix in a Flake-based project, add it to your inputs and access the toolchains via fenix.packages.<system>. This is the recommended method.

    Example for a NixOS configuration within a flake:

    {
      inputs = {
        fenix = {
          url = "github:nix-community/fenix";
          inputs.nixpkgs.follows = "nixpkgs";
        };
        nixpkgs.url = "nixpkgs/nixos-unstable";
      };
    
      outputs = { self, fenix, nixpkgs }: {
        packages.x86_64-linux.default = fenix.packages.x86_64-linux.minimal.toolchain;
        nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
          system = "x86_64-linux";
          modules = [
            ({
              pkgs, ...
            }: {
              nixpkgs.overlays = [ fenix.overlays.default ];
              environment.systemPackages = [
                ({
                  pkgs, ...
                }: {
                  pkgs.fenix.complete.withComponents [
                    "cargo"
                    "clippy"
                    "rust-src"
                    "rustc"
                    "rustfmt"
                  ])
                  pkgs.rust-analyzer-nightly
                })
              ];
            })
          ];
        };
      };
    }
  3. Install Fenix as an Overlay

    main

    You can use Fenix as a Nixpkgs overlay in your configuration.nix. This allows you to access Fenix packages through pkgs.

    Note: When using Fenix as an overlay, the nixpkgs from your system will be used, which may not be cached if you are using a stable/older version of nixpkgs. To fix this, use the workaround provided in the documentation.

    # configuration.nix
    { pkgs, ... }: {
      nixpkgs.overlays = [
        (import "${fetchTarball "https://github.com/nix-community/fenix/archive/main.tar.gz"}/overlay.nix")
      ];
      environment.systemPackages = with pkgs; [
        (fenix.complete.withComponents [
          "cargo"
          "clippy"
          "rust-src"
          "rustc"
          "rustfmt"
        ])
        rust-analyzer-nightly
      ];
    }
  4. Install Fenix as a set of packages

    main

    You can import Fenix directly as a set of packages using fetchTarball.

    let
      fenix = import (fetchTarball "https://github.com/nix-community/fenix/archive/main.tar.gz") { };
    in
    fenix.minimal.toolchain
  5. Use the monthly Fenix branch

    main

    If you want to use Rust nightly but do not need frequent updates, you can use the Fenix monthly branch, which is updated on the 1st of every month.

    {
      inputs = {
        fenix.url = "github:nix-community/fenix/monthly";
      };
    
      outputs = { self, fenix }: {
        packages.x86_64-linux.default = fenix.packages.x86_64-linux.default.toolchain;
      };
    }
  6. Cross compile Rust with naersk

    main

    When cross-compiling with naersk, you can construct a custom toolchain using Fenix's combine function. This allows you to mix components like minimal.cargo, minimal.rustc, and specific target standard libraries (e.g., targets.${target}.latest.rust-std). You must also provide the appropriate linker via environment variables like CARGO_TARGET_<TARGET>_LINKER.

    {
      inputs = {
        fenix = {
          url = "github:nix-community/fenix";
          inputs.nixpkgs.follows = "nixpkgs";
        };
        flake-utils.url = "github:numtide/flake-utils";
        naersk = {
          url = "github:nix-community/naersk";
          inputs.nixpkgs.follows = "nixpkgs";
        };
        nixpkgs.url = "nixpkgs/nixos-unstable";
      };
    
      outputs = { self, fenix, flake-utils, naersk, nixpkgs }: 
        flake-utils.lib.eachDefaultSystem (system: {
          packages.default = 
            let
              pkgs = nixpkgs.legacyPackages.${system};
              target = "aarch64-unknown-linux-gnu";
              toolchain = with fenix.packages.${system}; combine [
                minimal.cargo
                minimal.rustc
                targets.${target}.latest.rust-std
              ];
            in
    
            (naersk.lib.${system}.override {
              cargo = toolchain;
              rustc = toolchain;
            }).buildPackage {
              src = ./.;
              CARGO_BUILD_TARGET = target;
              CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = 
                let
                  inherit (pkgs.pkgsCross.aarch64-multiplatform.stdenv) cc;
                in
                "${cc}/bin/${cc.targetPrefix}cc";
            };
        });
    }
  7. Build Rust packages with crane

    main

    To use Fenix with crane, use the overrideToolchain method on the craneLib to inject a specific Fenix toolchain (e.g., stable.toolchain).

    {
      inputs = {
        crane = {
          url = "github:ipetkov/crane";
          inputs = {
            flake-utils.follows = "flake-utils";
            nixpkgs.follows = "nixpkgs";
          };
        };
        fenix = {
          url = "github:nix-community/fenix";
          inputs.nixpkgs.follows = "nixpkgs";
        };
        flake-utils.url = "github:numtide/flake-utils";
        nixpkgs.url = "nixpkgs/nixos-unstable";
      };
    
      outputs = { self, crane, fenix, flake-utils, nixpkgs }: 
        flake-utils.lib.eachDefaultSystem (system: {
          packages.default = 
            let
              craneLib = (crane.mkLib nixpkgs.legacyPackages.${system}).overrideToolchain fenix.packages.${system}.stable.toolchain;
            in
    
            craneLib.buildPackage {
              src = ./.;
            };
        });
    }
  8. Build Rust packages with makeRustPlatform

    main

    You can use Fenix toolchains with Nixpkgs' makeRustPlatform by passing the Fenix toolchain to both the cargo and rustc arguments. This allows you to leverage Fenix's managed Rust versions within standard Nixpkgs build infrastructures.

    {
      inputs = {
        fenix = {
          url = "github:nix-community/fenix";
          inputs.nixpkgs.follows = "nixpkgs";
        };
        flake-utils.url = "github:numtide/flake-utils";
        nixpkgs.url = "nixpkgs/nixos-unstable";
      };
    
      outputs = { self, fenix, flake-utils, nixpkgs }: 
        flake-utils.lib.eachDefaultSystem (system: {
          packages.default = 
            let
              toolchain = fenix.packages.${system}.minimal.toolchain;
              pkgs = nixpkgs.legacyPackages.${system};
            in
    
            (pkgs.makeRustPlatform {
              cargo = toolchain;
              rustc = toolchain;
            }).buildRustPackage {
              pname = "example";
              version = "0.1.0";
              src = ./.;
              cargoLock.lockFile = ./Cargo.lock;
            };
        });
    }
  9. Pin Rust version using fromManifestFile

    main

    To pin a specific Rust version without using Import Flake Dependencies (IFD), you can use the fromManifestFile function. Pass a URL to a Rust manifest file (like channel-rust-stable.toml) to generate a toolchain based on that manifest.

    {
      inputs = {
        fenix = {
          url = "github:nix-community/fenix";
          inputs.nixpkgs.follows = "nixpkgs";
        };
        nixpkgs.url = "nixpkgs/nixos-unstable";
        rust-manifest = {
          url = "https://static.rust-lang.org/dist/channel-rust-stable.toml";
          flake = false;
        };
      };
    
      outputs = { self, fenix, nixpkgs, rust-manifest }: {
        packages.x86_64-linux.default = 
          (fenix.packages.x86_64-linux.fromManifestFile rust-manifest).minimalToolchain;
      };
    }
  10. Create a toolchain with fromToolchainName

    main

    Use fromToolchainName to create a toolchain from a name (channel, version, or date). Requires sha256 for pure evaluation.

    # Example: Version number
    fromToolchainName { name = "1.90.0"; sha256 = "sha256-SJwZ8g0zF2WrKDVmHrVG3pD2RGoQeo24MEXnNx5FyuI="; }
    
    # Example: Nightly date
    fromToolchainName { name = "nightly-2023-08-07"; sha256 = "Ho2/rJSi6KiHbxgDpdvYE0dwrEUD3psnyYyLmFNYKII="; }
  11. Use nightly rust-analyzer and VSCode extension

    main

    Fenix provides nightly versions of rust-analyzer and its VSCode extension.

    • rust-analyzer: Available as a derivation or via overlay as rust-analyzer-nightly.
    • rust-analyzer-vscode-extension: Available as rust-analyzer-vscode-extension or via overlay as vscode-extensions.rust-lang.rust-analyzer-nightly.
    # Using the VSCode extension with an overlay
    with pkgs; vscode-with-extensions.override {
      vscodeExtensions = [
        vscode-extensions.rust-lang.rust-analyzer-nightly
      ];
    }