diff --git a/src/modules/languages/rust.nix b/src/modules/languages/rust.nix index 960f81019..5f05d3f7e 100644 --- a/src/modules/languages/rust.nix +++ b/src/modules/languages/rust.nix @@ -3,16 +3,44 @@ let cfg = config.languages.rust; - fenix = config.lib.getInput { - name = "fenix"; - url = "github:nix-community/fenix"; - attribute = "languages.rust.version"; + rust-overlay = config.lib.getInput { + name = "rust-overlay"; + url = "github:oxalica/rust-overlay"; + attribute = "languages.rust.input"; follows = [ "nixpkgs" ]; }; + + # https://github.com/nix-community/fenix/blob/cdfd7bf3e3edaf9e3f6d1e397d3ee601e513613c/lib/combine.nix + combine = name: paths: + pkgs.symlinkJoin { + inherit name paths; + postBuild = '' + for file in $(find $out/bin -xtype f -maxdepth 1); do + install -m755 $(realpath "$file") $out/bin + + if [[ $file =~ /rustfmt$ ]]; then + continue + fi + + ${lib.optionalString pkgs.stdenv.isLinux '' + if isELF "$file"; then + patchelf --set-rpath $out/lib "$file" || true + fi + ''} + + ${lib.optionalString pkgs.stdenv.isDarwin '' + install_name_tool -add_rpath $out/lib "$file" || true + ''} + done + + for file in $(find $out/lib -name "librustc_driver-*"); do + install $(realpath "$file") "$file" + done + ''; + }; in { imports = [ - (lib.mkRenamedOptionModule [ "languages" "rust" "version" ] [ "languages" "rust" "channel" ]) (lib.mkRenamedOptionModule [ "languages" "rust" "packages" ] [ "languages" "rust" "toolchain" ]) ]; @@ -34,7 +62,7 @@ in default = [ ]; defaultText = lib.literalExpression ''[ ]''; description = '' - List of extra [targets](https://github.com/nix-community/fenix#supported-platforms-and-targets) + List of extra [targets](https://doc.rust-lang.org/nightly/rustc/platform-support.html) to install. Defaults to only the native target. ''; }; @@ -46,6 +74,16 @@ in description = "The rustup toolchain to install."; }; + version = lib.mkOption { + type = lib.types.str; + default = "latest"; + defaultText = lib.literalExpression ''"latest"''; + description = '' + Which version of rust to use, this value could be `latest`,`1.81.0`, `2021-01-01`. + Only works when languages.rust.channel is NOT nixpkgs. + ''; + }; + rustflags = lib.mkOption { type = lib.types.str; default = ""; @@ -101,6 +139,17 @@ in The nixpkgs channel does not support cross-compiling with targets. Use the stable, beta, or nightly channels instead. For example: + languages.rust.channel = "stable"; + ''; + } + { + assertion = cfg.channel == "nixpkgs" -> (cfg.version == "latest"); + message = '' + Cannot use `languages.rust.channel = "nixpkgs"` with `languages.rust.version`. + + The nixpkgs channel does not contain all versions required, and is + therefore not supported to be used together. + languages.rust.channel = "stable"; ''; } @@ -153,21 +202,17 @@ in (lib.mkIf (cfg.channel != "nixpkgs") ( let - rustPackages = fenix.packages.${pkgs.stdenv.system}; - fenixChannel = - if cfg.channel == "nightly" - then "latest" - else cfg.channel; - toolchain = rustPackages.${fenixChannel}; + toolchain = (rust-overlay.lib.mkRustBin {} pkgs.buildPackages)."${cfg.channel}"."${cfg.version}"; + filteredToolchain = (lib.filterAttrs (n: _: builtins.elem n toolchain._manifest.profiles.complete) toolchain); in { languages.rust.toolchain = - (builtins.mapAttrs (_: pkgs.lib.mkDefault) toolchain); + (builtins.mapAttrs (_: pkgs.lib.mkDefault) filteredToolchain); packages = [ - (rustPackages.combine ( - (map (c: toolchain.${c}) cfg.components) ++ - (map (t: rustPackages.targets.${t}.${fenixChannel}.rust-std) cfg.targets) + (combine "rust-mixed" ( + (map (c: cfg.toolchain.${c}) cfg.components) ++ + (map (t: toolchain._components.${t}.rust-std) cfg.targets) )) ]; }