Rust: Difference between revisions
imported>Amjoseph-nixpkgs No edit summary |
Phanirithvij (talk | contribs) m dream2nix update link |
||
(28 intermediate revisions by 22 users not shown) | |||
Line 5: | Line 5: | ||
# or with unofficial overlays on nixpkgs. | # or with unofficial overlays on nixpkgs. | ||
Installing via nixpkgs is the | Installing via nixpkgs is the best way to use Rust, but there are valid reasons to use any approach. | ||
== Installing via nixpkgs == | == Installing via nixpkgs == | ||
The <code>cargo</code> and <code>rustc</code> derivations provide the Rust toolchain in nixpkgs. An advantage of using nixpkgs is that it's dead simple and you get pinned versions, deterministic builds in nix-shell, etc. However, nixpkgs only maintains a single version of the Rust stable toolchain, so if you require a nightly toolchain or | The <code>cargo</code> and <code>rustc</code> derivations provide the Rust toolchain in nixpkgs. An advantage of using nixpkgs is that it's dead simple and you get pinned versions, deterministic builds in nix-shell, etc. However, nixpkgs only maintains a single version of the Rust stable toolchain, so if you require a nightly toolchain or switch between multiple toolchains then this approach may not be for you. | ||
Here's an example <code>shell.nix</code>: | Here's an example <code>shell.nix</code>: | ||
Line 21: | Line 21: | ||
in pkgs.mkShell { | in pkgs.mkShell { | ||
buildInputs = [ pkgs.cargo pkgs.rustc ]; | buildInputs = [ pkgs.cargo pkgs.rustc ]; | ||
} | |||
</syntaxHighlight> | |||
== Installating with bindgen support == | |||
By default crates using <code>bindgen</code> will not compile. To add bindegen support add the <code>rustPlatform.bindegenHook</code> to your <code>nativeBuildInputs</code>. | |||
Here's an example <code>shell.nix</code>: | |||
<syntaxHighlight lang="nix"> | |||
{ pkgs ? import <nixpkgs> {} }: | |||
pkgs.mkShell { | |||
nativeBuildInputs = [ | |||
pkgs.cargo | |||
pkgs.rustc | |||
pkgs.rustPlatform.bindgenHook | |||
# optional: add pkg-config support | |||
pkgs.pkg-config | |||
]; | |||
buildInputs = [ | |||
# add desired native packages | |||
# ... | |||
]; | |||
# ... | |||
} | |||
</syntaxHighlight> | |||
This also works, when compiling rust crates: | |||
<syntaxHighlight lang="nix"> | |||
{ | |||
rustPlatform, | |||
pkg-config, | |||
... | |||
}: | |||
rustPlatform.buildRustPackage { | |||
# ... | |||
nativeBuildInputs = [ | |||
rustPlatform.bindgenHook | |||
pkg-config | |||
]; | |||
buildInputs = [ | |||
# add desired native packages | |||
# ... | |||
]; | |||
} | } | ||
</syntaxHighlight> | </syntaxHighlight> | ||
== Installation via rustup == | == Installation via rustup == | ||
The rustup tool is maintained by the Rust community and offers | The rustup tool is maintained by the Rust community and offers an interface to install and switch between Rust toolchains. In this scenario, rustup handles the "package management" of Rust toolchains and places them in <code>$PATH</code>. Nixpkgs offers rustup via the <code>rustup</code> derivation. More info on using rustup can be found on their official website: https://rustup.rs/. | ||
If you want | If you want the most "normal" Rust experience I recommend using rustup with the following example shell.nix: | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
{ pkgs ? import <nixpkgs> {} }: | { pkgs ? import <nixpkgs> {} }: | ||
let | |||
overrides = (builtins.fromTOML (builtins.readFile ./rust-toolchain.toml)); | |||
libPath = with pkgs; lib.makeLibraryPath [ | |||
# load external libraries that you need in your rust project here | |||
]; | |||
in | |||
pkgs.mkShell rec { | pkgs.mkShell rec { | ||
buildInputs = with pkgs; [ | buildInputs = with pkgs; [ | ||
clang | |||
# Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16) | |||
llvmPackages.bintools | |||
rustup | rustup | ||
]; | ]; | ||
RUSTC_VERSION = | RUSTC_VERSION = overrides.toolchain.channel; | ||
# https://github.com/rust-lang/rust-bindgen#environment-variables | # https://github.com/rust-lang/rust-bindgen#environment-variables | ||
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ]; | LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ]; | ||
shellHook = '' | shellHook = '' | ||
export PATH=$PATH:${CARGO_HOME:-~/.cargo}/bin | export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin | ||
export PATH=$PATH:${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/ | export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/ | ||
''; | ''; | ||
# Add | # Add precompiled library to rustc search path | ||
RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') [ | RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') [ | ||
pkgs.libvmi | # add libraries here (e.g. pkgs.libvmi) | ||
]); | ]); | ||
# Add | LD_LIBRARY_PATH = libPath; | ||
BINDGEN_EXTRA_CLANG_ARGS = | # Add glibc, clang, glib, and other headers to bindgen search path | ||
# Includes | BINDGEN_EXTRA_CLANG_ARGS = | ||
# Includes normal include path | |||
(builtins.map (a: ''-I"${a}/include"'') [ | (builtins.map (a: ''-I"${a}/include"'') [ | ||
pkgs.libvmi | # add dev libraries here (e.g. pkgs.libvmi.dev) | ||
pkgs.glibc.dev | pkgs.glibc.dev | ||
]) | ]) | ||
# Includes with special directory paths | # Includes with special directory paths | ||
Line 67: | Line 112: | ||
''-I${pkgs.glib.out}/lib/glib-2.0/include/'' | ''-I${pkgs.glib.out}/lib/glib-2.0/include/'' | ||
]; | ]; | ||
} | } | ||
</syntaxHighlight> | </syntaxHighlight> | ||
It's important to have a file named <code>rust-toolchain</code> lying in the same directory as the shell.nix. | It's important to have a file named <code>rust-toolchain.toml</code> lying in the same directory as the shell.nix. | ||
Rust already has a standardized way of pinning a toolchain version for a workspace or a project. | |||
< | See [https://rust-lang.github.io/rustup/overrides.html#the-toolchain-file the Rustup book] for its syntax. | ||
nightly- | A minimal example of the <code>rust-toolchain.toml</code>: | ||
</ | <syntaxhighlight lang="toml"> | ||
[toolchain] | |||
channel = "stable" # This can also be "nightly" if you want a nightly rust | |||
# or nightly-20XX-XX-XX for a specific nightly. | |||
</syntaxhighlight> | |||
The important part is that this also works with complex setups using bindgen and precompiled C libraries. To add a new C library in the search path of bindgen and rustc edit the variables <code>BINDGEN_EXTRA_CLANG_ARGS</code> and <code>RUSTFLAGS</code> | The important part is that this also works with complex setups using bindgen and precompiled C libraries. To add a new C library in the search path of bindgen and rustc edit the variables <code>BINDGEN_EXTRA_CLANG_ARGS</code> and <code>RUSTFLAGS</code> | ||
Line 93: | Line 141: | ||
# https://github.com/mozilla/nixpkgs-mozilla (Flake support, Nightly & Stable) | # https://github.com/mozilla/nixpkgs-mozilla (Flake support, Nightly & Stable) | ||
== | == devenv.sh support == | ||
# | # https://github.com/cachix/devenv/blob/main/examples/rust/devenv.nix and <code>devenv shell</code> | ||
== Developing Rust projects using Nix == | == Developing Rust projects using Nix == | ||
Line 102: | Line 149: | ||
The [https://nixos.org/manual/nixpkgs/stable/#rust Nixpkgs manual] uses <code>buildRustPackage</code>. | The [https://nixos.org/manual/nixpkgs/stable/#rust Nixpkgs manual] uses <code>buildRustPackage</code>. | ||
[https:// | [https://srid.ca/rust-nix This] blog post shows how to do it using <code>dream2nix</code>. A template repo is available here: https://github.com/srid/rust-nix-template | ||
== Using overrideAttrs with Rust Packages == | == Using overrideAttrs with Rust Packages == | ||
Line 142: | Line 189: | ||
| Yes | | Yes | ||
| Built into nixpkgs | | Built into nixpkgs | ||
|- | |- | ||
| [https://github.com/kolloch/crate2nix <code>crate2nix</code>] | | [https://github.com/kolloch/crate2nix <code>crate2nix</code>] | ||
Line 154: | Line 194: | ||
| Many | | Many | ||
| <code>buildRustCrate</code> | | <code>buildRustCrate</code> | ||
| [ | | [https://github.com/kolloch/crate2nix/commit/8bfeb42bda097e0bdf5452691a5e157aad3cc11f experimental] | ||
| Spiritual successor to carnix | | Spiritual successor to [https://github.com/nix-community/carnix <code>carnix</code>] | ||
|- | |- | ||
| [https://github.com/nmattia/naersk/ <code>naersk</code>] | | [https://github.com/nmattia/naersk/ <code>naersk</code>] | ||
Line 161: | Line 201: | ||
| 2 | | 2 | ||
| cargo | | cargo | ||
| | | Yes | ||
| [https://github.com/nmattia/naersk/blob/22b96210b2433228d42bce460f3befbdcfde7520/rust/rustc.nix#L22-L29 Seems to only support building on x86] | | [https://github.com/nmattia/naersk/blob/22b96210b2433228d42bce460f3befbdcfde7520/rust/rustc.nix#L22-L29 Seems to only support building on x86] | ||
|- | |- | ||
Line 185: | Line 225: | ||
| Inspired by naersk, with [https://discourse.nixos.org/t/introducing-crane-composable-and-cacheable-builds-with-cargo/17275/4 better support for composing Cargo invocations as completely separate derivations] | | Inspired by naersk, with [https://discourse.nixos.org/t/introducing-crane-composable-and-cacheable-builds-with-cargo/17275/4 better support for composing Cargo invocations as completely separate derivations] | ||
|- | |- | ||
| [https:// | | [https://dream2nix.dev/reference/rust-crane <code>dream2nix</code>] | ||
| Codegen | | Codegen | ||
| 1 or 2 | | 1 or 2 | ||
| cargo (via <code>buildRustPackage</code> or <code>crane</code>) | | cargo (via <code>buildRustPackage</code> or <code>crane</code>) | ||
| Yes | | Yes | ||
| A framework for unifying 2nix converters across languages | | A framework for unifying 2nix converters across languages (Experimental) | ||
|} | |} | ||
Line 204: | Line 244: | ||
{ pkgs ? import <nixpkgs> {} }: | { pkgs ? import <nixpkgs> {} }: | ||
pkgs.mkShell { | pkgs.mkShell { | ||
nativeBuildInputs = with pkgs; [ rustc cargo gcc | nativeBuildInputs = with pkgs; [ rustc cargo gcc rustfmt clippy ]; | ||
# Certain Rust tools won't work without this | # Certain Rust tools won't work without this | ||
Line 215: | Line 254: | ||
This will have the stable Rust compiler + the official formatter and linter inside the ephemeral shell. It'll also set the RUST_SRC_PATH environment variable to point to the right location, which tools, such as rust-analyzer, require to be set. | This will have the stable Rust compiler + the official formatter and linter inside the ephemeral shell. It'll also set the RUST_SRC_PATH environment variable to point to the right location, which tools, such as rust-analyzer, require to be set. | ||
=== | === Custom Rust version === | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
/* | |||
based on | |||
https://discourse.nixos.org/t/how-can-i-set-up-my-rust-programming-environment/4501/9 | |||
*/ | |||
let | |||
rust_overlay = import (builtins.fetchTarball "https://github.com/oxalica/rust-overlay/archive/master.tar.gz"); | |||
pkgs = import <nixpkgs> { overlays = [ rust_overlay ]; }; | |||
rustVersion = "latest"; | |||
#rustVersion = "1.62.0"; | |||
rust = pkgs.rust-bin.stable.${rustVersion}.default.override { | |||
extensions = [ | |||
"rust-src" # for rust-analyzer | |||
"rust-analyzer" | |||
]; | ]; | ||
}; | }; | ||
} | in | ||
pkgs.mkShell { | |||
buildInputs = [ | |||
rust | |||
] ++ (with pkgs; [ | |||
pkg-config | |||
# other dependencies | |||
#gtk3 | |||
#wrapGAppsHook | |||
]); | |||
RUST_BACKTRACE = 1; | |||
} | |||
</syntaxHighlight> | </syntaxHighlight> | ||
=== VSCode integration === | |||
The [https://marketplace.visualstudio.com/items?itemName=rust-lang.rust rust-lang.rust] and [https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer rust-lang.rust-analyzer] VSCode extensions offer Rust support. | |||
You can use the [https://marketplace.visualstudio.com/items?itemName=arrterian.nix-env-selector arrterian.nix-env-selector] extension to enable your nix-shell inside VSCode and have these settings picked up by other extensions. | |||
== FAQ == | == FAQ == | ||
Line 269: | Line 314: | ||
</syntaxHighlight> | </syntaxHighlight> | ||
Note that you need to use a <code>nix-shell</code> environment. Installing the Nix packages <code>openssl</code> or <code>sqlite</code> globally under <code>systemPackages</code> in NixOS or in <code>nix-env</code> [ | Note that you need to use a <code>nix-shell</code> environment. Installing the Nix packages <code>openssl</code> or <code>sqlite</code> globally under <code>systemPackages</code> in NixOS or in <code>nix-env</code> [[FAQ/I installed a library but my compiler is not finding it. Why? | is discouraged]] and doesn't always work (<code>pkg-config</code> may not be able to locate the libraries). | ||
=== Building with a different Rust version than the one in Nixpkgs === | === Building with a different Rust version than the one in Nixpkgs === | ||
The following uses the [https://github.com/nix-community/fenix fenix] overlay and <code>makeRustPlatform</code> to build a crate with Rust | The following uses the [https://github.com/nix-community/fenix fenix] overlay and <code>makeRustPlatform</code> to build a crate with Rust Nightly: | ||
<syntaxHighlight lang="nix"> | <syntaxHighlight lang="nix"> | ||
Line 301: | Line 346: | ||
} | } | ||
</syntaxHighlight> | </syntaxHighlight> | ||
=== Using LLD instead of LD === | |||
If you want to use <code>lld</code>, then the correct way to do this is to use <code>pkgs.llvmPackages.bintools</code>, <em>not</em> <code>pkgs.lld</code>. This is because the former uses a wrapper script that correctly sets <code>rpath</code>. You can find more information about this [https://matklad.github.io/2022/03/14/rpath-or-why-lld-doesnt-work-on-nixos.html here]. | |||
[[Category:Languages]] |