diff options
| author | tv <tv@krebsco.de> | 2026-11-10 05:48:43 +0100 |
|---|---|---|
| committer | tv <tv@krebsco.de> | 2026-11-10 05:48:43 +0100 |
| commit | baec651a12204daccd76cacb3a59f13bda8ba6a6 (patch) | |
| tree | 026e307bce106a66d25421b01faa1f8a3b68ffb8 /pkgs/rust | |
| parent | e732f21699db07b0777f43ef2a64d503274171a6 (diff) | |
pkgs: add rust overlay
Diffstat (limited to 'pkgs/rust')
| -rw-r--r-- | pkgs/rust/default.nix | 102 | ||||
| -rw-r--r-- | pkgs/rust/lib/crate2nix-package.nix | 77 |
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; +} |
