VSCode with Rust

Have any of you tried using VSCode and Rust together on NixOS?

I’ve used vim for many years, and things like Rust support were just available because I would always start vim in a shell that had a Rust client already present in the shell.

But my new job is all VSCode. Since VSCode is a gui app instead of a shell app, it doesn’t have the benefit of having my normal development environment. As a compromise, I’d like to figure out how to add things like the rust language server, rustc, and rustfmt to the VSCode installation so that I have the tools available for dev, I have them available for VSCode, but i don’t have them littered around in my normal shells.

So, this is my overlay:

  my-vscode = (super.vscode-with-extensions.overrideAttrs (attrs: {
      buildInputs = attrs.buildInputs ++ [ super.rls super.rustc ];
    })).override {
    vscodeExtensions = with super.vscode-extensions; [
    ] ++ super.vscode-utils.extensionsFromVscodeMarketplace [
      {
        name = "Nix";
        publisher = "bbenoist";
        version = "1.0.1";
        sha256 = "0zd0n9f5z1f0ckzfjr38xw2zzmcxg1gjrava7yahg5cvdcw6l35b";
      }
      {
        name = "rust";
        publisher = "rust-lang";
        version = "0.7.8";
        sha256 = "039ns854v1k4jb9xqknrjkj8lf62nfcpfn0716ancmjc4f0xlzb3";
      }
      ];
  };

Do any of you have any ideas for how the rust language server works and how i can bundle it in with VSCode?

Of course, it would be really incredible if I can have per-project Rust versions, because I tend to pin a Rust version in my nix-shell, but I’m totally willing to compromise on that.

As far as I remember, the VScode rust extension will just use the rust language server from PATH.

So make sure it is installed in your shell and start vscode from the terminal when in the correct environment.

1 Like

This suggestion seems to work. I’ll probably trip on it when I start doing multiple projects.

Unfortunately, the rls in the 20.03 repository seems to not work with rust 1.43 (found crate core compiled by an incompatible version of rustc), and trying to build a new rls fails because rls uses features from the “nightly” build. :woman_facepalming:

Looks like I might have to finally give in and create an FHS environment that uses Rustup.

You don’t need FHS for rustup. The rustup we have in nixpkgs does patchelf on all binaries. If something does not work as expected open an issue.

1 Like

Where does that install the rust compilers? I just noticed rustup and am messing with it, but I’m accustomed to most third party auto-updaters being really incompatible with the nix store.

Why not use an rls matching your rust?

rustPackages_1_42 and rustPackages_1_43 exist (on unstable at least) as well as the nixpkgs-mozilla overlay.

Is this a problem with the Rustup derivation?

[] savanni@garnet:~/s/l/fitnesstrax (sol) $ cargo build --verbose --jobs 1
   Compiling pkg-config v0.3.17
     Running `rustc --crate-name pkg_config /home/savanni/.cargo/registry/src/github.com-1ecc6299db9ec823/pkg-config-0.3.17/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type lib --emit=dep-info,metadata,link -C debuginfo=2 -C metadata=7788bba80f4e792d -C extra-filename=-7788bba80f4e792d --out-dir /home/savanni/src/luminescent-dreams/fitnesstrax/target/debug/deps -L dependency=/home/savanni/src/luminescent-dreams/fitnesstrax/target/debug/deps --cap-lints allow`
   Compiling libc v0.2.69
     Running `rustc --crate-name build_script_build /home/savanni/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.69/build.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="std"' -C metadata=47ecdcc5e40d24a2 -C extra-filename=-47ecdcc5e40d24a2 --out-dir /home/savanni/src/luminescent-dreams/fitnesstrax/target/debug/build/libc-47ecdcc5e40d24a2 -L dependency=/home/savanni/src/luminescent-dreams/fitnesstrax/target/debug/deps --cap-lints allow`
error: linker `cc` not found
  |
  = note: No such file or directory (os error 2)

error: aborting due to previous error

error: could not compile `libc`.

Caused by:
  process didn't exit successfully: `rustc --crate-name build_script_build /home/savanni/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.69/build.rs --error-format=json --json=diagnostic-rendered-ansi --crate-type bin --emit=dep-info,link -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="std"' -C metadata=47ecdcc5e40d24a2 -C extra-filename=-47ecdcc5e40d24a2 --out-dir /home/savanni/src/luminescent-dreams/fitnesstrax/target/debug/build/libc-47ecdcc5e40d24a2 -L dependency=/home/savanni/src/luminescent-dreams/fitnesstrax/target/debug/deps --cap-lints allow` (exit code: 1)

To me, it looks like rustup depends on, but does not install, gcc. But I’ve never before used rustup and don’t know the scope of it or the derivation.

Mostly I’ve shied away from these and built custom Rust derivations because I’ve wanted reliable builds, and either stable is too far behind, or unstable is advancing too quickly and dropping my compilers at unexpected times.

Thats why I:

  1. Pin to exact commits in my shells
  2. Use the overlay

rustup does have a dependency on stdenv.cc as part of its patchelf step, which means it does depend on gcc, but that doesn’t put cc in the PATH. It can’t wrap rustup to add it because that won’t affect invocations of rustup’s installed binaries (such as cargo and rustc). So basically, it looks like you need to ensure cc is in your environment to use as a linker. You can pass a flag to rustc to explicitly tell it where to find the linker, but that can’t be done automatically.

This suggests two reasonable courses of action:

  1. Install nixos.stdenv.cc into your environment (or nixos.gcc, which should be the same thing).
  2. Stop using rustup and instead either install nixos.rls (and probably nixos.rustPlatform.rust too so you can run rustc and cargo yourself), or switch to the mozilla overlay if you want a version of rust other than what nixpkgs has.

Sticking stdenv.cc into your environment is probably the simplest approach. And if you don’t want it available globally you could use something like direnv or lorri to only make it available in certain directories, as long as you launch vscode from those directories.

I would not recommend install a C/C++ compiler into your profile but use a nix-shell or direnv for the reasons stated here: How do I install rust? - #8 by Mic92

Nope. Looks fine. Just needs a nix-shell to get a compiler into scope. Also add pkg-config to nativeBuildInputs when writing a shell.nix/default.nix.

So, it suddenly works, and I’ve only taken part of your advice.

I switched to the mozilla-overlay, and then switched all of my packages from buildInputs to nativeBuildInputs. Here’s what it looks like:

    nativeBuildInputs = [ pkgs.pkgconfig
                          pkgs.carnix
                          pkgs.glib
                          pkgs.gtk3-x11
                          rust.rust
                          pkgs.rls
                        ];

So, I don’t know why the native RLS was angry with me before. It was the first tool that did not like the custom Rust derivation I’ve written, but maybe it’s happy with the mozilla one. But, mysteriously, I don’t have cc explicitely in this shell, and that’s a touch weird.

Anyway, here’s my project shell.nix and my overlay with vscode. So, maybe things are okay. For now I’ll hope and will see when things break again.

cc comes with stdenv automatically.

If you’re using nix-shell, the mozilla overlay sets propagatedBuildInputs = [ stdenv.cc ]; so cc will be available to the shell.

Ah, that would explain it.

Plus, now I know about propogatedBuildInputs. Bet I forget before I actually need to use it again.

FWIW, I had a relatively painless setup by just leaning on VS Code and Rust’s native “package managers”. That is, I added vscode and rustup to my systemPackages, then installed rust toolchain via rustup and VS Code extensions via the Marketplace*

*: it is a bit more elaborate in reality, as I use override for the latest vscode and code --list-extensions to sync the list of extensions I use.