A Rust crate as a derivation — buildRustPackage
Read cargo-tops.nix line by line. Name src, cargoLock, and what lands in $out.
<!-- hal:authoritative:yaml -->
*Read a rustPlatform.buildRustPackage expression line by line. Name what lands in $out.*
§I — Frame
Asr session 16. First live fire of the Nix Rust-roads block (Topics #16 to #20). Topic T7 Env & CI. Home: . Primary corpus file: ~/projects/rust-tops/nix/cargo-tops.nix (vault mirror under foundry/rust-tops/repo/rust-tops/nix/). Live attribute reference: https://nixos.org/manual/nixpkgs/stable/#rust.
Sessions 01–15 closed the language-to-stdenv spine. Session 15 chose buildInputs vs propagatedBuildInputs. Today the unmarked row asks a different question: how does a Rust workspace crate become a store path through rustPlatform.buildRustPackage.
Duha Beat B today already packaged a channels crate as a teaching shell (lesson_class: duha, topic T1). That bundle did not consume this Asr cursor. Asr owns the line-by-line read of the protocol crate’s own derivation.
Done-criteria from the syllabus: you can read a Rust package derivation line by line (src, cargoLock/cargoHash, buildInputs, and what lands in $out).
Not writers. Not musl cross. Not flake devShell/checks. Not Pill 20 re-teach.
§II — Call Package Shape (named technique)
Call Package Shape: the file is a function of { lib, rustPlatform }, then a single rustPlatform.buildRustPackage { … } attrset. The overlay wires it with final.callPackage ./cargo-tops.nix { }.
From nix/overlay.nix:
cargo-tops = final.callPackage ./cargo-tops.nix { };
From nix/cargo-tops.nix (full file is short; quote the spine):
{
lib,
rustPlatform,
}:
rustPlatform.buildRustPackage {
pname = "cargo-tops";
version = "0.1.3";
src = lib.cleanSource ../.;
cargoLock.lockFile = ../Cargo.lock;
buildAndTestSubdir = "crates/cargo-tops";
doCheck = true;
meta = {
description = "init / check / gate for the Rust-TOPS protocol";
homepage = "https://github.com/Hedronite/rust-tops";
license = with lib.licenses; [ mit asl20 ];
mainProgram = "cargo-tops";
};
}
Musashi: the derivation is the package. callPackage fills lib and rustPlatform from the final package set. You do not invent attribute names; you read the ones present.
If-then-thus: if the file starts as { lib, rustPlatform }:, then the build helper comes from nixpkgs Rust support, thus the body is a specialized mkDerivation, not a hand-rolled bash builder.
§III — Source Lock Walk (named technique)
Source Lock Walk: name how source and Cargo deps enter the sandbox.
| Field | In cargo-tops.nix | Role |
|---|---|---|
pname / version | cargo-tops / 0.1.3 | Store name stem |
src | lib.cleanSource ../. | Workspace root, filtered |
cargoLock.lockFile | ../Cargo.lock | Vendored/locked crate graph for the build |
buildAndTestSubdir | crates/cargo-tops | Which workspace member builds |
doCheck | true | Run crate tests in checkPhase |
Two locking styles exist in nixpkgs Rust packaging: cargoLock (point at a lock file; common for workspace crates in-repo) and cargoHash / cargoSha256 (hash of the fetched cargo deps when you are not shipping the lock walk the same way). This corpus file uses cargoLock.lockFile. When you see cargoHash in another flake, it is the alternate fixed-output path for Cargo dependencies. Do not mix the two styles in one package without reading the manual section for that helper.
lib.cleanSource drops VCS and other noise from src so the store path stays stable when junk files change.
If-then-thus: if buildAndTestSubdir points at crates/cargo-tops, then Cargo builds that member against the workspace lock, thus $out holds that member’s binary, not every workspace crate.
§IV — Out Path Contract (named technique)
Out Path Contract: say what the realized store path contains after a successful build.
buildRustPackage runs the Rust build inside stdenv. With meta.mainProgram = "cargo-tops", the primary CLI is expected on $out/bin/cargo-tops. Libraries and intermediate target artifacts do not define the package identity for this binary crate; the installable program does.
doCheck = true means the checkPhase runs the crate’s tests before the output is accepted. A red test fails the derivation. That is the same fail-closed idea Bend encodes for laws, applied to Cargo’s test runner inside Nix.
Session 15’s dep walk still applies when you add native libraries: put compile-time C deps in buildInputs / nativeBuildInputs as the Rust section and stdenv rules require. This particular cargo-tops.nix lists none beyond what rustPlatform already injects.
If-then-thus: if the build succeeds and mainProgram is set, then lib.getExe pkgs.cargo-tops resolves the CLI, thus consumers and flake packages can treat the derivation as the tool.
§V — Dualfire: paving Rust roads
Asr Nix seats T7 so Rust crates become reproducible store objects. Reading cargo-tops.nix is not tourism; it is how the protocol kit itself is packaged. Overlay + callPackage + buildRustPackage is the road from workspace member to packages.${system}.cargo-tops.
Keep the Duha/Asr split clear: Duha Beat B may package today’s lesson crate under lesson_class: duha. Asr advances NIX-SYLLABUS rows under lesson_class: asr and topic: T7.
§VI — Done-criteria check
Say aloud without looking:
- Call Package Shape:
{ lib, rustPlatform }:thenrustPlatform.buildRustPackage. - Source Lock Walk:
src,cargoLock.lockFile(orcargoHashelsewhere),buildAndTestSubdir. - Out Path Contract: binary under
$out/bin(herecargo-topsviamainProgram);doCheckgates acceptance. - Overlay wire:
final.callPackage ./cargo-tops.nix { }.
§VII — Common mistakes
- Treating Duha’s channels packaging shell as this Asr Topics #16 ship.
- Inventing nixpkgs attribute names instead of quoting the corpus file and the manual.
- Confusing
cargoLock.lockFilewithcargoHashand “fixing” both. - Assuming every workspace crate lands in
$outwhenbuildAndTestSubdirnames one member. - Jumping to flake
checks(row #19) or writers (row #17) before this read is fluent. - Re-opening Pill 20 as if hooks were today’s unmarked topic.
§VIII — Boundaries
- Not
pkgs.writers/ cargo script (Topics #17). - Not static
muslcross (Topics #18). - Not flake
devShell/checksschema (Topics #19). - Not POSIX floor gate (Topics #20).
- Not Pill 20 re-teach.
- Not editing rust-tops product files from this lesson.
- Not Python
withPackages(retired Asr lane).
§IX — Close
Session 15 closed the Pills spine. Session 16 opens Rust roads: Call Package Shape, Source Lock Walk, Out Path Contract on cargo-tops.nix. Next unmarked: session 17, pkgs.writers + cargo script.
Related:
Open nix/cargo-tops.nix. Speak each field once. Leave the keyboard.