How can I set up my Rust programming environment?

I am quite new to NixOS, and if you’re asking, I did read the manual.
I want a nice guide on how to use nix-shell with Rust, managing Cargo packages, building my programs and other stuff.
Also, share your own workflow if you are a Rust programmer, would be helpful for me to take as an example.

3 Likes

Which manual? Also the Nixpkgs manual with the section on Rust with the section on nix-shell usage?

Oh, it looks like I only read NixOS 23.11 manual | Nix & NixOS
Guess that’s another manual for me to read.
I followed the guide on the page you linked, worked for building a simple hello world program.
What I want to know now is how can I create a .nix file that when ran using nix-shell will install some packages like carnix, cargo and rustc
Also that particular .nix file ran using nix-shell, what is it called? I’d like to call it by it’s name the next time I mention it.

The simplest shell.nix for rust would look like

{ pkgs: import <nixpkgs> }:
pkgs.mkShell {
  buildInputs = with pkgs; [ cargo carnix ];
}

I think that’ll bring in all the dependencies you’d need. When you start needing outside dependencies (sqlite, openssl, etc) you can add them to that.

For development I mostly use a shell.nix with the Rust toolchain. I use Mozilla’s Rust overlay because it makes it so easy to get the current stable versions, nightlies, or even specific nightlies (for pyo3). E.g.

with import <nixpkgs> {};

stdenv.mkDerivation rec {
  name = "finalfusion-utils-env";
  env = buildEnv { name = name; paths = buildInputs; };

  buildInputs = [
    latest.rustChannels.stable.rust
}

To make something properly buildable, I add default.nix using crate2nix + buildRustCrate or buildRustPackage.

3 Likes

FWIW here’s my shell.nix for rust stuff:

let
  # Last updated: 2/26/21. Update as necessary from https://status.nixos.org/...
  pkgs = import (fetchTarball("https://github.com/NixOS/nixpkgs/archive/04ac9dcd311956d1756d77f4baf9258392ee7bdd.tar.gz")) {};

  # Rolling updates, not deterministic.
  # pkgs = import (fetchTarball("channel:nixpkgs-unstable")) {};
in pkgs.mkShell {
  buildInputs = [
    pkgs.cargo
    pkgs.rustc
    pkgs.rustfmt

    # Necessary for the openssl-sys crate:
    pkgs.openssl
    pkgs.pkg-config
  ];

  # See https://discourse.nixos.org/t/rust-src-not-found-and-other-misadventures-of-developing-rust-on-nixos/11570/3?u=samuela.
  RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}";
}
2 Likes

Howdy!
My comments are slightly off-topic since they do not constitute a full how-to guide.

I have followed examples on the wiki. These examples demonstrate a few options. But they could also be out-of-date or inaccurate.

Yesterday I learned about another Rust overlay from @oxalica: GitHub - oxalica/rust-overlay: Pure and reproducible nix overlay of binary distributed rust toolchains
This overlay looks incredibly promising because it has precompiled toolchains. I have seen the Mozilla overlay recompile a full toolchain before.

I hope to write a shell.nix using oxalica’s rust-overlay for another OSS project. I’ll post a link here once I get around to it!

2 Likes

For others looking, it turns out Oxalica’s Rust overlay is very nice, here is a shell.nix file I use:

{ nixpkgs ? import <nixpkgs> { }}:

let
  rustOverlay = builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz";
  pinnedPkgs = nixpkgs.fetchFromGitHub {
    owner  = "NixOS";
    repo   = "nixpkgs";
    rev    = "1fe6ed37fd9beb92afe90671c0c2a662a03463dd";
    sha256 = "1daa0y3p17shn9gibr321vx8vija6bfsb5zd7h4pxdbbwjkfq8n2";
  };
  pkgs = import pinnedPkgs {
    overlays = [ (import rustOverlay) ];
  };
in
  pkgs.mkShell {
    buildInputs = with pkgs; [
      rust-bin.stable.latest.default
      rust-analyzer
    ];

    RUST_BACKTRACE = 1;
  }

I blogged about a more classic approach too here if anyone is interested.

2 Likes

I’ve been using the Oxalica overlay for my shell for a while.

let
    rust_overlay = import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz");
    cargo2nix = import (builtins.fetchTarball "https://github.com/cargo2nix/cargo2nix/tarball/master") {};
    pkgs = import <pkgs-21.05> { overlays = [ rust_overlay ]; };
    unstable = import <unstable> {};
    rust = pkgs.rust-bin.stable."1.54.0".default.override {
      extensions = [ "rust-src" ];
    };

in pkgs.mkShell {
    name = "luminescent-dreams-core";

    buildInputs = [
      pkgs.exiftool
      pkgs.file
      pkgs.pkgconfig
      pkgs.glib
      pkgs.gtk3
      pkgs.wrapGAppsHook
      rust
      cargo2nix.package
      unstable.rust-analyzer
    ];

    shellHook = ''
      if [ -e ~/.nixpkgs/shellhook.sh ]; then . ~/.nixpkgs/shellhook.sh; fi

      export MAGIC_DB=${pkgs.file}/share/misc/magic.mgc;
    '';
}

I was particularly happy when I discovered the extensions = [ "rust-src" ] statement, which finally got rust-analyzer working reliably.

So, any of you know how to use Oxalica to specify the Rust and Cargo packages for buildRustPackage? I know that as part of a nixpkgs package, I would just use the default that nixpkgs uses, but my work is internal and I really need to specify a known version in order to stay with my co-workers.

2 Likes

Great question. I do not know off the top of my head.
@savannidgerinel would you be up for posting this as a separate topic? I’m curious if anyone has done this. It also seems like a good question to have for reference on this discourse.

From memory, something like this should work:

let
  rust = pkgs.rust-bin.stable."1.54.0".default.override {
    extensions = [ "rust-src" ];
  };
  rustPlatform = pkgs.makeRustPlatform {
    cargo = rust;
    rustc = rust;
  };
in
rustPlatform.buildRustPackage {
  ...
}
2 Likes

see also the nixpkgs manual: Controlling Rust Version Inside nix-shell

1 Like