Skip to content

Latest commit

 

History

History
163 lines (120 loc) · 6.02 KB

File metadata and controls

163 lines (120 loc) · 6.02 KB

AGENTS.md

This file provides guidance to AI agents when working with code in this repository.

Project Overview

This is a Nix flake library providing reusable functions for building Rust projects with cross-compilation, Docker images, and development environments. It is designed to be imported as a flake input by other projects.

Development Commands

Formatting

nix fmt

Enter development shell

nix develop

Build example package

nix build .#example-shell

Test the library in a consuming project

Use a local path reference in the consuming project's flake:

inputs.nix-lib.url = "path:../nix-lib";

Architecture

Flake Dependencies

The library has the following input dependencies:

  • Core: nixpkgs, flake-utils, rust-overlay, crane
  • Optional for flakeModule: treefmt-nix, flake-parts

If consuming projects don't use nix-lib.flakeModules.default, the treefmt-nix input is not required and can be removed for lighter dependency graphs. Most consuming projects will want the flakeModule for automatic formatting configuration, making treefmt-nix a practical requirement in practice.

Library Structure

The library is organized as a flake that exposes functions through lib.${system}. All functions are defined in lib/ and exported through lib/default.nix.

Entry point: lib/default.nix imports and re-exports all library functions.

Core Modules

Rust Builders (rust-builders.nix + rust-builder.nix)

  • Two-layer design: rust-builders.nix provides high-level platform-specific builders (local, x86_64-linux, aarch64-linux, etc.), while rust-builder.nix is the low-level factory that creates individual builders
  • mkAllBuilders: Returns an attrset with pre-configured builders for all supported platforms (local, localNightly, x86_64-linux, aarch64-linux, x86_64-darwin, aarch64-darwin)
  • Cross-compilation: Uses nixpkgs cross-compilation with musl for static Linux binaries
  • Toolchain support: Can use rust-toolchain.toml, nightly toolchain, or stable
  • Builder pattern: Each builder has a callPackage method that wraps rust-package.nix with the appropriate cross-compilation environment variables (CARGO_BUILD_TARGET, linker settings, RUSTFLAGS for static linking)

Source Filtering (sources.nix)

  • Three source types:
    • mkDepsSrc: Minimal source for dependency resolution (Cargo.toml, Cargo.lock, .cargo/config.toml)
    • mkSrc: Full source for building (adds .rs files, README.md)
    • mkTestSrc: Source with test data
  • Purpose: Reduces build closure size and improves caching by filtering files

Rust Package Builder (rust-package.nix)

  • Low-level builder: Called via builder.callPackage from consumer projects
  • Multi-mode: Supports release builds, tests (runTests), clippy (runClippy), docs (buildDocs), and benchmarks (runBench)
  • Configurable test arguments: The cargoTestExtraArgs parameter (default: "--workspace") controls what flags are passed to cargo test. This enables splitting unit tests (--lib) and integration tests (--test '*') into separate Nix derivations, each independently cacheable by Nix. The prependPackageName flag (default: true) controls whether -p ${pname} is prepended to cargoExtraArgs; set to false for workspace-wide operations
  • Cargo profiles: Controlled via CARGO_PROFILE (release/dev/test)
  • Cross-compilation handling:
    • Patches interpreter for cross-compiled Linux binaries (patchelf)
    • Darwin-specific setup hooks for cross-compilation from macOS
    • Static linking via RUSTFLAGS with crt-static feature
  • Dependencies: Uses crane's two-phase build (buildDepsOnly for caching dependencies, then buildPackage)

Docker Images (docker.nix)

  • Creates OCI-compliant layered images using nixpkgs dockerTools
  • Default includes minimal base packages (cacert, tzdata, glibc/musl)
  • Must use Linux packages (handles cross-building from Darwin)

Development Shells (shells.nix)

  • Provides Rust toolchain, build tools, and optional PostgreSQL
  • Integrates with treefmt for code formatting

Utility Apps (apps.nix)

  • mkCheckApp: Runs nix flake checks
  • mkAuditApp: Runs cargo-audit for security scanning
  • mkFindPortApp: Finds available ports for CI testing
  • mkUpdateGithubLabelsApp: Updates GitHub labels based on crate structure

Key Design Patterns

  1. Per-system library instantiation: The flake uses eachSystemMap to create a library instance for each system, accessible via nix-lib.lib.${system}

  2. Builder factory pattern: Builders are created with platform-specific settings, then consumers call builder.callPackage to build packages with those settings

  3. Source separation: Dependencies and main source are built separately for better caching (depsSrc vs src)

  4. Environment variable injection: Cross-compilation settings are injected via overrideAttrs on both the main derivation and cargoArtifacts

  5. Optional toolchain file: Most functions accept an optional rustToolchainFile parameter for reproducible Rust versions

  6. Split test derivations: Tests are built by Nix (not inside nix develop) to leverage Nix's caching. Unit tests and integration tests are separate derivations via cargoTestExtraArgs, exposed as both packages (nix build) and checks (nix flake check). Arguments after -- (e.g., --test-threads=1) can be included in cargoTestExtraArgs

Important Notes

  • This is a library, not an application. Changes should maintain backward compatibility.
  • All platform-specific logic is in rust-builder.nix (Darwin build hooks, static linking flags, linker selection).
  • Docker images must use Linux packages; mkDockerImage handles this automatically.
  • Cross-compilation from macOS to Linux is supported, but macOS targets must be built on Darwin for code signing.
  • The library exposes both high-level conveniences (mkRustBuilders) and low-level building blocks (mkRustBuilder, mkRustPackage).