summaryrefslogtreecommitdiffstats
path: root/pkgs/rust
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-10 05:48:43 +0100
committertv <tv@krebsco.de>2026-11-10 05:48:43 +0100
commitbaec651a12204daccd76cacb3a59f13bda8ba6a6 (patch)
tree026e307bce106a66d25421b01faa1f8a3b68ffb8 /pkgs/rust
parente732f21699db07b0777f43ef2a64d503274171a6 (diff)
pkgs: add rust overlay
Diffstat (limited to 'pkgs/rust')
-rw-r--r--pkgs/rust/default.nix102
-rw-r--r--pkgs/rust/lib/crate2nix-package.nix77
2 files changed, 179 insertions, 0 deletions
diff --git a/pkgs/rust/default.nix b/pkgs/rust/default.nix
new file mode 100644
index 0000000..d273db6
--- /dev/null
+++ b/pkgs/rust/default.nix
@@ -0,0 +1,102 @@
+self: super:
+
+let
+ inherit (super) lib mylib;
+
+ # Merges an override into attrs. The override is attrs, or a function from
+ # the original attrs to attrs, like the argument of nixpkgs' .override.
+ applyOverride = override: attrs: attrs // lib.toFunction override attrs;
+
+ explicitPackages =
+ mylib.mapNixDir' (pname: path: path) [ ./. ];
+
+ automaticPackages =
+ let
+ root = /home/tv/sync/src;
+ in
+ lib.optionalAttrs (builtins.pathExists root)
+ (lib.mapAttrs (pname: _type: root + "/${pname}")
+ (lib.filterAttrs
+ (pname: type: type == "directory" && builtins.pathExists (root + "/${pname}/Cargo.toml"))
+ (builtins.readDir root)));
+
+ # callPackage adds override and overrideDerivation to the returned attrset,
+ # which crate2nix-package.nix would reject as unexpected arguments.
+ callArgs = path: builtins.removeAttrs (self.callPackage path {}) [ "override" "overrideDerivation" ];
+
+ # A plan kept next to the package in hrm: pkgs/rust/<pname>/Cargo.json.
+ # Settings in the package file itself take precedence.
+ hrmPlan = path:
+ lib.optionalAttrs (builtins.pathExists (path + "/Cargo.json")) {
+ resolvedJson = path + "/Cargo.json";
+ };
+in
+
+{
+ # Builds a crate2nix workspace.
+ crate2nixPackage = args: import ./lib/crate2nix-package.nix ({
+ inherit applyOverride;
+ pkgs = self;
+ } // args);
+
+ # Applied to our own crates: debug builds, but dependencies in release.
+ rustDevCrateAttrs = args: {
+ release = false;
+ codegenUnits = 256;
+ extraRustcOpts = args.extraRustcOpts or [] ++ [
+ "-C debuginfo=line-tables-only"
+ "-C link-arg=-fuse-ld=mold"
+ ];
+ nativeBuildInputs = args.nativeBuildInputs or [] ++ [ self.mold ];
+ };
+
+ # Builds a crate from rustCrateArgs.<pname> merged with an override: attrs,
+ # or a function from the stored arguments to attrs, e.g.
+ # rustCrateWith "continuum" { features = [ "tor" ]; }
+ # With {}, that's the package itself.
+ rustCrateWith = pname: f:
+ (self.crate2nixPackage (applyOverride f self.rustCrateArgs.${pname})).build;
+
+ # crate2nixPackage arguments per package. Change them in a later overlay:
+ # self: super: {
+ # rustCrateArgs = super.rustCrateArgs // {
+ # continuum = super.rustCrateArgs.continuum // { resolvedJson = ./continuum.json; };
+ # };
+ # }
+ rustCrateArgs =
+ lib.mapAttrs (pname: path: hrmPlan path // callArgs path) explicitPackages
+ //
+ lib.mapAttrs
+ (pname: dir: let
+ src = self.cleanCargoSource pname dir;
+ in
+ if explicitPackages ? ${pname} then
+ assert mylib.debug "pkgs/rust: overriding ${pname}.src with ${mylib.pretty dir}";
+ hrmPlan explicitPackages.${pname} // callArgs explicitPackages.${pname} // { inherit src; }
+ else
+ assert mylib.debug "pkgs/rust: automatic package ${pname} from ${mylib.pretty dir}";
+ { name = pname; inherit src; }
+ )
+ automaticPackages;
+
+ # Copies a Cargo workspace into the store, leaving out what the build
+ # doesn't need.
+ cleanCargoSource = name: src: builtins.path {
+ inherit name;
+ path = src;
+ filter = path: type:
+ !builtins.any lib.id [
+ (type == "directory" && builtins.elem (baseNameOf path) [ ".git" ".graveyard" ])
+ # Cargo.json is the resolved lock.
+ (type == "regular" && baseNameOf path == "Cargo.lock" && builtins.pathExists (builtins.dirOf path + "/Cargo.json"))
+ ];
+ };
+}
+
+//
+
+lib.mapAttrs
+ (pname: _path:
+ assert mylib.debugIf (super ? ${pname}) "pkgs/rust: overriding ${pname}";
+ self.rustCrateWith pname {})
+ (explicitPackages // automaticPackages)
diff --git a/pkgs/rust/lib/crate2nix-package.nix b/pkgs/rust/lib/crate2nix-package.nix
new file mode 100644
index 0000000..d97a97e
--- /dev/null
+++ b/pkgs/rust/lib/crate2nix-package.nix
@@ -0,0 +1,77 @@
+# Per-crate Rust builds with crate2nix.
+#
+# resolvedJson selects how the build plan is obtained:
+# null (default) <src>/Cargo.json if present, else IFD from <src>/Cargo.lock
+# a path that file (crate2nix generate --format json)
+# false always IFD from <src>/Cargo.lock
+#
+# Overrides are attrs, or functions from the crate's buildRustCrate arguments
+# to attrs, and are merged into those arguments before buildRustCrate sees
+# them, so they can also set release. For a workspace member,
+# workspaceOverride applies first and crateOverrides.<name> sees its result.
+# nixpkgs' defaultCrateOverrides still apply inside buildRustCrate.
+
+{ pkgs
+, applyOverride
+
+, name
+, src
+
+# crate name -> attrs or (args -> attrs)
+, crateOverrides ? {}
+
+# attrs or (args -> attrs), for every workspace member
+, workspaceOverride ? {}
+
+# IFD only; Cargo.json has its features baked in
+, features ? [ "default" ]
+
+, resolvedJson ? null
+}:
+
+let
+ resolvedJsonFromSrc = src + "/Cargo.json";
+
+ useJson =
+ if resolvedJson == null then builtins.pathExists resolvedJsonFromSrc
+ else resolvedJson != false;
+
+ resolvedJson' =
+ if resolvedJson != null then resolvedJson else resolvedJsonFromSrc;
+
+ workspaceMembers = builtins.attrNames cargoNix.workspaceMembers;
+
+ buildRustCrateForPkgs = pkgs: args:
+ let
+ withWorkspace =
+ if builtins.elem args.crateName workspaceMembers
+ then applyOverride workspaceOverride args
+ else args;
+ in
+ pkgs.buildRustCrate
+ (applyOverride (crateOverrides.${args.crateName} or {}) withWorkspace);
+
+ fromJson = pkgs.crate2nix.build-from-json {
+ inherit buildRustCrateForPkgs pkgs src;
+ resolvedJson = resolvedJson';
+ };
+
+ fromLock =
+ pkgs.callPackage
+ (pkgs.crate2nix.tools.generatedCargoNix {
+ inherit name src;
+ additionalCargoNixArgs = [ "--all-features" ];
+ })
+ {
+ rootFeatures = features;
+ inherit buildRustCrateForPkgs;
+ };
+
+ cargoNix =
+ if useJson then fromJson else fromLock;
+in
+cargoNix // {
+ build =
+ if cargoNix.rootCrate or null != null then cargoNix.rootCrate.build
+ else cargoNix.allWorkspaceMembers;
+}