leanPackages: structural reimagining — own toolchain, lake --packages, Hydra visibility

Give leanPackages its own lean4, independent of pkgs.lean4. Binary-
patch the toolchain so the language server discovers the wrapped lake
despite lake serve deriving LAKE from IO.appPath unconditionally.
Supplant Lake's config trace validation for /nix/store/ dependencies,
deferring cache coherence to Nix.

Migrate Nix-managed dependency injection from package-overrides.json
to lake --packages. Patch Cli to pre-build static library for
downstream executables. Add recurseIntoAttrs for Hydra.

Upstream accepted FetchContent for mimalloc vendoring:
https://github.com/leanprover/lean4/commit/a145b9c11a0fe38fd4c921024a7376c99cc34bd2
This commit is contained in:
Nadja Yang
2026-03-28 13:53:22 -04:00
parent 81b7eb12a4
commit 3c2a3b804d
18 changed files with 274 additions and 267 deletions
+42 -136
View File
@@ -1,20 +1,11 @@
# buildLakePackage: build Lean 4 projects that use the Lake build system.
#
# Dependencies can be provided in two ways:
# - `leanDeps`: already-packaged Lean libraries from leanPackages.
# These are injected into LEAN_PATH via setup hooks and propagated
# transitively, similar to Haskell's libraryHaskellDepends.
# - `leanDeps`: nix-packaged Lean libraries, injected via
# `lake --packages` and propagated transitively via LEAN_PATH.
# - `lakeHash`: SRI hash for a fetchLakeDeps FOD that clones git
# dependencies listed in lake-manifest.json (like buildGoModule's
# vendorHash). Not needed when all deps are in `leanDeps`.
#
# Library output layout:
# $out/ Package root (source + build artifacts)
# $out/lakefile.{lean,toml} Lake package configuration
# $out/lean-toolchain Lean version pin
# $out/.lake/build/lib/lean/ Compiled .olean/.ilean files
# $out/.lake/build/ir/ Compiled C/object files
# $out/nix-support/setup-hook LEAN_PATH propagation hook
{
lib,
stdenv,
@@ -22,7 +13,7 @@
gitMinimal,
cacert,
jq,
lndir,
writeText,
stdenvNoCC,
}:
@@ -55,32 +46,19 @@ lib.extendMkDerivation {
nativeBuildInputs ? [ ],
passthru ? { },
# SRI hash for the Lake dependencies FOD.
# Set to null if the project has no external dependencies
# (or all deps are provided via leanDeps).
# SRI hash for the Lake dependencies FOD (null = all deps nix-managed).
lakeHash ? null,
# Pre-built Lake dependencies derivation (overrides lakeHash).
lakeDeps ? null,
# Already-packaged Lean libraries from nixpkgs.
# These are added to LEAN_PATH (via setup hook) and propagated
# transitively. Each must be a buildLakePackage output with
# .olean files under $out/.lake/build/lib/lean/.
# Nix-packaged Lean libraries, injected via lake --packages.
leanDeps ? [ ],
# Lean package name as declared in lakefile.lean/toml.
# Defaults to pname.
# Lake package name as declared in lakefile (defaults to pname).
leanPackageName ? finalAttrs.pname,
# Lake build targets. Empty list means the default target.
# Lake build targets (empty = default targets).
buildTargets ? [ ],
# Whether this is a library (install full package tree with
# .olean/.ilean files) or an executable (install binaries only).
# Library (install .olean tree) or executable (install binaries only).
isLibrary ? true,
# Override attributes of the lakeDeps derivation.
# Override the FOD derivation attrs.
overrideLakeDepsAttrs ? (finalAttrs: previousAttrs: { }),
meta ? { },
@@ -96,6 +74,10 @@ lib.extendMkDerivation {
isLibrary = args.isLibrary or true;
leanPackageName = args.leanPackageName or finalAttrs.pname;
allLeanDeps = lib.unique (
builtins.concatMap (dep: [ dep ] ++ (dep.passthru.allLeanDeps or [ ])) leanDeps
);
computedLakeDeps =
if lakeDeps' != null then
lakeDeps'
@@ -114,11 +96,18 @@ lib.extendMkDerivation {
}).overrideAttrs
(lib.toExtension overrideLakeDepsAttrs);
# Transitively collect all Lean dependencies. Each buildLakePackage
# library stores its own transitive closure in passthru.allLeanDeps,
# so this flattens the entire dependency DAG.
allLeanDeps = lib.unique (
builtins.concatMap (dep: [ dep ] ++ (dep.passthru.allLeanDeps or [ ])) leanDeps
# Nix-managed dep overrides, generated at eval time.
# --packages takes precedence over .lake/package-overrides.json.
overridesFile = writeText "lake-overrides.json" (
builtins.toJSON {
schemaVersion = "1.2.0";
packages = map (dep: {
type = "path";
name = dep.passthru.lakePackageName or dep.pname;
inherited = false;
dir = "${dep}";
}) allLeanDeps;
}
);
in
{
@@ -128,14 +117,9 @@ lib.extendMkDerivation {
lean4
gitMinimal
jq
lndir
];
# Propagate so downstream packages get transitive LEAN_PATH entries
# via each dependency's nix-support/setup-hook.
propagatedBuildInputs = lib.optionals isLibrary leanDeps;
# Executables only need deps at build time.
buildInputs = lib.optionals (!isLibrary) leanDeps;
configurePhase =
@@ -144,106 +128,34 @@ lib.extendMkDerivation {
export HOME="$TMPDIR"
# Disable Lake cloud caching and Reservoir lookups
# Disable cloud caching and Reservoir lookups.
export LAKE_NO_CACHE=1
export RESERVOIR_API_URL=""
# Point leanc at the nix-provided C compiler
export LEAN_CC="${stdenv.cc}/bin/cc"
# Validate that the lean-toolchain file (if present) matches the
# Lean toolchain we are building against. Mismatches between the
# toolchain version and the compiler produce confusing errors, so
# fail early with a clear message.
leanVersion="${lean4.version}"
if [ -f lean-toolchain ]; then
toolchainVersion=$(sed -n 's/^.*:v\([0-9][0-9.]*\).*/\1/p' lean-toolchain)
if [ -n "$toolchainVersion" ] && [ "$toolchainVersion" != "$leanVersion" ]; then
echo "buildLakePackage: lean-toolchain requests v$toolchainVersion but lean4 is v$leanVersion" >&2
echo "buildLakePackage: update the package or use a matching lean4 version" >&2
exit 1
fi
fi
${lib.concatStringsSep "\n" (
builtins.map (
dep:
let
name = dep.passthru.lakePackageName or dep.pname;
in
''
# Fail fast if nix-packaged dep "${name}" was built against a
# different Lean version. This avoids wasting build time when
# the package set is mid-update (e.g. lean4 bumped but a dep
# has not been updated yet).
if [ -f "${dep}/lean-toolchain" ]; then
depToolchain=$(sed -n 's/^.*:v\([0-9][0-9.]*\).*/\1/p' "${dep}/lean-toolchain")
if [ -n "$depToolchain" ] && [ "$depToolchain" != "$leanVersion" ]; then
echo "buildLakePackage: dependency ${name} was built with Lean v$depToolchain but lean4 is v$leanVersion" >&2
echo "buildLakePackage: update ${name} first, or override lean4 in leanPackages" >&2
exit 1
fi
fi
''
) allLeanDeps
)}
if [ -n "''${LEAN_PATH:-}" ]; then
echo "buildLakePackage: LEAN_PATH=$LEAN_PATH"
fi
mkdir -p .lake/packages
# Create a minimal empty manifest if none exists. Lake requires
# this file, but when all deps come from leanDeps (nix-managed),
# the actual dependency entries come from package-overrides.json.
if [ ! -f lake-manifest.json ]; then
echo '{"version":"1.1.0","packagesDir":".lake/packages","packages":[]}' \
> lake-manifest.json
fi
${lib.optionalString (computedLakeDeps != null) ''
# Copy fetched (not yet nix-packaged) deps into .lake/packages/
mkdir -p .lake/packages
for dep in ${computedLakeDeps}/*; do
depName="$(basename "$dep")"
cp -r "$dep" ".lake/packages/$depName"
chmod -R u+w ".lake/packages/$depName"
done
''}
${lib.concatStringsSep "\n" (
builtins.map (
dep:
let
name = dep.passthru.lakePackageName or dep.pname;
in
''
# Install nix-packaged dep "${name}" into .lake/packages/.
# lndir creates a symlink tree so artifacts remain as
# zero-copy references to the store; writable dirs let Lake
# create metadata during workspace initialization.
rm -rf ".lake/packages/${name}"
mkdir -p ".lake/packages/${name}"
lndir -silent "${dep}" ".lake/packages/${name}"
''
) allLeanDeps
)}
# Generate package-overrides.json redirecting deps to local
# paths. Scans .lake/packages/ so that nix-managed deps work
# even without a lake-manifest.json (like Haskell's package DB
# approach nix is the sole dependency provider, Lake just
# validates against lakefile.lean at build time).
if [ -d .lake/packages ] && [ -n "$(ls -A .lake/packages/ 2>/dev/null)" ]; then
# FOD deps use package-overrides.json (the on-disk mechanism).
# Nix-managed deps use --packages (the CLI mechanism, takes precedence).
jq -n --argjson pkgs "$(
for dep in .lake/packages/*/; do
[ -d "$dep" ] || continue
depName="$(basename "$dep")"
printf '{"type":"path","name":"%s","inherited":false,"configFile":"lakefile","dir":".lake/packages/%s"}\n' \
"$depName" "$depName"
jq -n --arg name "$depName" --arg dir ".lake/packages/$depName" \
'{type: "path", name: $name, inherited: false, dir: $dir}'
done | jq -s '.'
)" '{schemaVersion: "1.1.0", packages: $pkgs}' > .lake/package-overrides.json
fi
)" '{schemaVersion: "1.2.0", packages: $pkgs}' > .lake/package-overrides.json
''}
runHook postConfigure
'';
@@ -255,7 +167,7 @@ lib.extendMkDerivation {
local targets="${lib.concatStringsSep " " buildTargets}"
echo "buildLakePackage: building ''${targets:-default targets}"
lake build --no-ansi $targets
lake build --no-ansi --packages=${overridesFile} $targets
runHook postBuild
'';
@@ -266,25 +178,22 @@ lib.extendMkDerivation {
''
runHook preInstall
# Install the complete Lake package tree. $out/ IS the
# package directory source, lakefile, and pre-built
# artifacts under .lake/build/.
# Install the complete Lake package tree.
cp -rT . "$out"
# Remove build-environment artifacts that reference the
# build sandbox or dependency store paths.
# Remove build-time artifacts.
rm -rf "$out/.lake/packages"
rm -f "$out/.lake/package-overrides.json"
# Install the setup hook so that downstream derivations
# (and `nix develop` shells) automatically get this
# package's oleans in LEAN_PATH.
# Reconcile config trace directory naming.
if [ -d "$out/.lake/config/[anonymous]" ]; then
mv "$out/.lake/config/[anonymous]" "$out/.lake/config/${leanPackageName}"
fi
# Setup hook propagates LEAN_PATH to downstream packages.
mkdir -p "$out/nix-support"
cp ${./setup-hook.sh} "$out/nix-support/setup-hook"
# Symlink any built executables into $out/bin/ for
# discoverability (e.g. packages that are both libraries
# and executables).
if [ -d "$out/.lake/build/bin" ]; then
mkdir -p "$out/bin"
for exe in "$out/.lake/build/bin"/*; do
@@ -300,7 +209,6 @@ lib.extendMkDerivation {
''
runHook preInstall
# Install executables only.
if [ -d .lake/build/bin ]; then
mkdir -p "$out/bin"
find .lake/build/bin -type f -executable \
@@ -314,8 +222,6 @@ lib.extendMkDerivation {
passthru = passthru // {
inherit computedLakeDeps lean4 allLeanDeps;
lakePackageName = leanPackageName;
# Canonicalize overrideLakeDepsAttrs as an attribute overlay,
# following the same pattern as buildGoModule's overrideModAttrs.
overrideLakeDepsAttrs = lib.toExtension overrideLakeDepsAttrs;
};
@@ -1,4 +0,0 @@
import WeakMinimax
def main : IO Unit := do
IO.println "weak_minimax: verified (maximin <= minimax)"
@@ -0,0 +1 @@
{"version":"1.1.0","packagesDir":".lake/packages","packages":[]}
@@ -6,7 +6,3 @@ package weakMinimax
require "leanprover-community" / "mathlib" @ git "main"
@[default_target] lean_lib WeakMinimax
@[default_target]
lean_exe weakMinimax.run where
root := `Main
@@ -1,12 +1,5 @@
# Test that buildLakePackage works with nix-only deps (no lake-manifest.json).
# Builds a Lean proof of the weak minimax inequality using mathlib.
#
# Note: building the executable recompiles .c → .c.o for all transitive
# dependency modules because library packages only ship .olean/.ilean/.c
# artifacts (the default Lake library facet). Lake's trace system would
# reuse pre-built object files if present, but since Lean 4 is rarely
# used for application code, we defer shipping .o files in library
# packages to keep store footprint minimal.
{
leanPackages,
runCommand,
@@ -24,17 +17,10 @@ let
};
in
runCommand "buildLakePackage-weak-minimax"
{
nativeBuildInputs = [ testPackage ];
}
''
mkdir -p $out
runCommand "buildLakePackage-weak-minimax" { } ''
mkdir -p $out
# Verify the executable runs (proof was verified at build time).
weakMinimax-run | tee $out/result
grep -q "weak_minimax" $out/result
# Verify library output has compiled oleans.
test -d "${testPackage}/.lake/build/lib/lean"
''
# Verify library output has compiled oleans.
test -d "${testPackage}/.lake/build/lib/lean"
touch $out/success
''
+13 -3
View File
@@ -6,17 +6,27 @@
buildLakePackage {
pname = "lean4-cli";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover";
repo = "lean4-cli";
tag = "v4.28.0";
hash = "sha256-9nX+dozmDAaVb5uKWL14zbILr7aqbVerTyPcN12Niw4=";
tag = "v4.29.0";
hash = "sha256-jCUl4sXVmwtYPuQecEUFH6mwFzPaQY7au4624EOiWjk=";
};
leanPackageName = "Cli";
# Pre-build static library for downstream executables.
# TODO: upstream this to lean4-cli
postPatch = ''
substituteInPlace lakefile.toml \
--replace-fail '[[lean_lib]]
name = "Cli"' '[[lean_lib]]
name = "Cli"
defaultFacets = ["static"]'
'';
meta = {
description = "Command-line argument parser for Lean 4";
homepage = "https://github.com/leanprover/lean4-cli";
@@ -18,12 +18,6 @@ buildLakePackage {
leanPackageName = "LeanSearchClient";
# Upstream lean-toolchain lags behind; remove it so the
# buildLakePackage toolchain check does not reject this package.
postPatch = ''
rm -f lean-toolchain
'';
meta = {
description = "Lean 4 client for LeanSearch and Moogle proof search";
homepage = "https://github.com/leanprover-community/LeanSearchClient";
+3 -3
View File
@@ -6,13 +6,13 @@
buildLakePackage {
pname = "lean4-Qq";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "quote4";
tag = "v4.28.0";
hash = "sha256-BRrSdDJQAsgM/NeSL2FODCez/8zEffjDRWUToGlKDNQ=";
tag = "v4.29.0";
hash = "sha256-pNY5hv1nJbreCfU4EewIHCpiryIBv1ghWibrUW8vnQ0=";
};
leanPackageName = "Qq";
@@ -7,13 +7,13 @@
buildLakePackage {
pname = "lean4-aesop";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "aesop";
tag = "v4.28.0";
hash = "sha256-KeP46qtEf4/lgi4iCVuYIQbazufTR4luTbsuia9JkK4=";
tag = "v4.29.0";
hash = "sha256-CNwxNig8OWjtfQRYyRnM/HGBn2oaNX5qP9CVT2eWNlg=";
};
leanPackageName = "aesop";
@@ -6,13 +6,13 @@
buildLakePackage {
pname = "lean4-batteries";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "batteries";
tag = "v4.28.0";
hash = "sha256-3N1MCFsg5UiwBCMAhDK7WwIowMNnhjlFgAsm0UPtGKc=";
tag = "v4.29.0";
hash = "sha256-sEIDi2i2FaLTgKYWt/kzqPrjMdf+bFURfhw6ZZWBawQ=";
};
leanPackageName = "batteries";
@@ -7,13 +7,13 @@
buildLakePackage {
pname = "lean4-importGraph";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "import-graph";
tag = "v4.28.0";
hash = "sha256-fZS8bFQjV7eLZCJwD+SVRzmCcCthrl+PO8vL8U8AOYs=";
tag = "v4.29.0";
hash = "sha256-tqdO2qyWiJzEbK0yuu4+tiOXTEg9XJfGnI7z6Jh/abg=";
};
leanPackageName = "importGraph";
@@ -0,0 +1,138 @@
# Lean 4 toolchain for the leanPackages set (independent of pkgs.lean4).
{
lib,
stdenv,
symlinkJoin,
cmake,
fetchFromGitHub,
git,
gmp,
cadical,
pkg-config,
libuv,
perl,
testers,
}:
let
lean4 = stdenv.mkDerivation (finalAttrs: {
pname = "lean4";
version = "4.29.0";
mimalloc-src = fetchFromGitHub {
owner = "microsoft";
repo = "mimalloc";
tag = "v2.2.3";
hash = "sha256-B0gngv16WFLBtrtG5NqA2m5e95bYVcQraeITcOX9A74=";
};
src = fetchFromGitHub {
owner = "leanprover";
repo = "lean4";
tag = "v${finalAttrs.version}";
hash = "sha256-0v4OTrCLdHBbWJUq7hIjJonqget9SvsG3izGlOwhwyU=";
};
# Vendor mimalloc. Upstream has since partially adopted FetchContent:
# https://github.com/leanprover/lean4/commit/a145b9c11a0fe38fd4c921024a7376c99cc34bd2
#
# Dynamically adjust the source tree to maintain a healthy boundary
# with Nix and avoid overstepping on its jurisdiction over cache coherence.
postPatch =
let
pattern = "\${LEAN_BINARY_DIR}/../mimalloc/src/mimalloc";
in
''
substituteInPlace src/CMakeLists.txt \
--replace-fail 'set(GIT_SHA1 "")' 'set(GIT_SHA1 "${finalAttrs.src.tag}")'
rm -rf src/lake/examples/git/
substituteInPlace CMakeLists.txt \
--replace-fail 'GIT_REPOSITORY https://github.com/microsoft/mimalloc' \
'SOURCE_DIR "${finalAttrs.mimalloc-src}"' \
--replace-fail 'GIT_TAG ${finalAttrs.mimalloc-src.tag}' ""
for file in stage0/src/CMakeLists.txt stage0/src/runtime/CMakeLists.txt src/CMakeLists.txt src/runtime/CMakeLists.txt; do
substituteInPlace "$file" \
--replace-fail '${pattern}' '${finalAttrs.mimalloc-src}'
done
substituteInPlace src/lake/Lake/Load/Lean/Elab.lean \
--replace-fail \
'let upToDate := ( olean.pathExists) ' \
'let upToDate := cfg.pkgDir.toString.startsWith "/nix/store/" ( olean.pathExists) '
'';
preConfigure = ''
patchShebangs stage0/src/bin/ src/bin/
'';
nativeBuildInputs = [
cmake
pkg-config
];
buildInputs = [
gmp
libuv
cadical
];
nativeCheckInputs = [
git
perl
];
cmakeFlags = [
"-DUSE_GITHASH=OFF"
"-DINSTALL_LICENSE=OFF"
"-DUSE_MIMALLOC=ON"
];
passthru.tests = {
version = testers.testVersion {
package = finalAttrs.finalPackage;
version = "v${finalAttrs.version}";
};
};
meta = {
description = "Automatic and interactive theorem prover";
homepage = "https://leanprover.github.io/";
changelog = "https://github.com/leanprover/lean4/blob/${finalAttrs.src.tag}/RELEASES.md";
license = lib.licenses.asl20;
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [ nadja-y ];
mainProgram = "lean";
};
});
oldStorePath = builtins.substring 0 43 (toString lean4);
in
# Binary-patched for correct runtime discovery in wrapped environments.
symlinkJoin {
inherit (lean4) name pname;
paths = [ lean4 ];
nativeBuildInputs = [ perl ];
postBuild = ''
newStorePath=$(echo "$out" | head -c 43)
# Copy (not symlink) IO.appPath resolves through symlinks.
rm $out/bin/lean $out/bin/lake
cp ${lean4}/bin/lean $out/bin/lean
cp ${lean4}/bin/lake $out/bin/lake
for bin in $out/bin/lean $out/bin/lake; do
cat "$bin" \
| perl -pe "s|\Q${oldStorePath}\E|$newStorePath|g" \
> "$bin.tmp"
chmod +x "$bin.tmp"
mv "$bin.tmp" "$bin"
done
'';
inherit (lean4) version src meta;
passthru = {
inherit (lean4) version src;
};
}
@@ -14,13 +14,13 @@
buildLakePackage {
pname = "lean4-mathlib";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "mathlib4";
tag = "v4.28.0";
hash = "sha256-7kR0WvEDey5kEdqKKVEO/JgQd1VyB6a+zwPvIV5E5Pg=";
tag = "v4.29.0";
hash = "sha256-fe+qS7gNxdLnACX3/jqToa9m7r1gbskY6kDJbm1ZefE=";
};
leanPackageName = "mathlib";
@@ -34,6 +34,8 @@ buildLakePackage {
importGraph
];
requiredSystemFeatures = [ "big-parallel" ];
passthru.tests = {
inherit (tests.lake) weak-minimax;
};
@@ -6,13 +6,13 @@
buildLakePackage {
pname = "lean4-plausible";
version = "4.28.0";
version = "4.29.0";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "plausible";
tag = "v4.28.0";
hash = "sha256-xuOfeoRPt5L0Rk4fEJPIi1A0aoNIkC1fsh5yeIx5bFI=";
tag = "v4.29.0";
hash = "sha256-08fNB2GK5AqDJ15n5Ol+HYqaSbsznyp4cerDo32bG50=";
};
leanPackageName = "plausible";
@@ -8,19 +8,18 @@
}:
let
version = "0.0.95";
src = fetchFromGitHub {
owner = "leanprover-community";
repo = "ProofWidgets4";
tag = "v0.0.87";
hash = "sha256-qXEqNfwUBPnxAtLRkBZTBFhrM4JYl43gLo/PM6HOG7o=";
tag = "v${version}";
hash = "sha256-LETljr+QEU6CxprR3pB4hUzhgCD8PrIuiPOgTIdhHVM=";
};
in
buildLakePackage {
pname = "lean4-proofwidgets";
version = "0.0.87";
inherit src;
inherit version src;
leanPackageName = "proofwidgets";
@@ -38,7 +37,7 @@ buildLakePackage {
name = "lean4-proofwidgets-npm-deps";
inherit src;
sourceRoot = "source/widget";
hash = "sha256-CzBRrreOSytquZ/xFHPlY8r+lz5Bg9Zk9ienRhc8SiY=";
hash = "sha256-ShH6MDr76wzWQrJvhMWCnklaox/uRsfoe+aYVSo/eNA=";
};
npmRoot = "widget";
+45 -45
View File
@@ -1,33 +1,33 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p nix-update common-updater-scripts curl jq
# Update all leanPackages to match the lean4 version in nixpkgs.
#
# All mathlib-ecosystem packages (batteries, aesop, Qq, plausible,
# importGraph, Cli, mathlib) release with the same version tag as
# lean4 (lockstep versioning). ProofWidgets and LeanSearchClient
# have their own versioning; the correct versions are read from
# mathlib's lake-manifest.json at the matching lean4 tag.
#
# This script only prefetches source hashes — it does not build
# anything. Output is a summary suitable for commit messages.
# Update the leanPackages set.
#
# Usage:
# ./pkgs/development/lean-modules/update.sh
# ./pkgs/development/lean-modules/update.sh [version]
set -euo pipefail
lean4_version=$(nix eval --raw .#lean4.version)
lean4_version="${1:-$(curl -sL https://api.github.com/repos/leanprover/lean4/releases/latest | jq -r '.tag_name' | sed 's/^v//')}"
# Snapshot current versions for diffing.
# Snapshot before any updates.
old_lockstep=$(nix eval --raw .#leanPackages.mathlib.version 2>/dev/null || echo "")
old_pw=$(nix eval --raw .#leanPackages.proofwidgets.version 2>/dev/null || echo "")
old_lsc=$(nix eval --raw .#leanPackages.LeanSearchClient.version 2>/dev/null || echo "")
run() { echo " $*"; "$@"; }
# --- lean4 toolchain ---
run nix-update leanPackages.lean4 --version="$lean4_version"
# --- mathlib dependency tree ---
# Versions are derived from mathlib's lake-manifest.json at the
# matching lean4 tag. Most packages release in lockstep with lean4;
# ProofWidgets and LeanSearchClient have their own versioning.
manifest=$(curl -sL "https://raw.githubusercontent.com/leanprover-community/mathlib4/v${lean4_version}/lake-manifest.json")
# Verify that mathlib's dependency set matches what we package.
# If mathlib adds or removes a dep, this script needs manual updating.
known_deps="Cli LeanSearchClient Qq aesop batteries importGraph plausible proofwidgets"
manifest_deps=$(echo "$manifest" | jq -r '[.packages[].name] | sort | join(" ")')
if [ "$manifest_deps" != "$known_deps" ]; then
@@ -43,41 +43,41 @@ lsc_rev=$(echo "$manifest" | jq -r '.packages[] | select(.name == "LeanSearchCli
lsc_date=$(curl -sL "https://api.github.com/repos/leanprover-community/LeanSearchClient/commits/$lsc_rev" | jq -r '.commit.committer.date[:10]')
lsc_version="0-unstable-$lsc_date"
# Leaf packages (no leanDeps).
nix-update leanPackages.batteries --version="$lean4_version"
nix-update leanPackages.Qq --version="$lean4_version"
nix-update leanPackages.plausible --version="$lean4_version"
nix-update leanPackages.Cli --version="$lean4_version"
nix-update leanPackages.proofwidgets --version="$pw_version"
echo "--- mathlib tree ---"
# LeanSearchClient has no lockstep tags; pin to the exact rev mathlib uses.
update-source-version leanPackages.LeanSearchClient "$lsc_version" \
--rev="$lsc_rev"
# Lockstep version synchronization.
dir=pkgs/development/lean-modules
for pkg in batteries aesop Qq plausible Cli importGraph mathlib; do
sed -i "s|tag = \"v${old_lockstep}\"|tag = \"v${lean4_version}\"|" "$dir/$pkg/default.nix"
done
# Packages with leanDeps.
nix-update leanPackages.aesop --version="$lean4_version"
nix-update leanPackages.importGraph --version="$lean4_version"
run nix-update leanPackages.batteries --version="$lean4_version"
run nix-update leanPackages.Qq --version="$lean4_version"
run nix-update leanPackages.plausible --version="$lean4_version"
run nix-update leanPackages.Cli --version="$lean4_version"
run nix-update leanPackages.proofwidgets --version="$pw_version"
run update-source-version leanPackages.LeanSearchClient "$lsc_version" --rev="$lsc_rev"
run nix-update leanPackages.aesop --version="$lean4_version"
run nix-update leanPackages.importGraph --version="$lean4_version"
run nix-update leanPackages.mathlib --version="$lean4_version"
# mathlib (all deps are nix-packaged, no lakeHash needed).
nix-update leanPackages.mathlib --version="$lean4_version"
# --- summary ---
# Summary.
changes=()
if [ "$old_lockstep" != "$lean4_version" ]; then
changes+=("lockstep packages: $old_lockstep -> $lean4_version")
fi
if [ "$old_pw" != "$pw_version" ]; then
changes+=("proofwidgets: $old_pw -> $pw_version")
fi
if [ "$old_lsc" != "$lsc_version" ]; then
changes+=("LeanSearchClient: $old_lsc -> $lsc_version")
fi
[ "$old_lockstep" != "$lean4_version" ] && changes+=("mathlib tree: $old_lockstep -> $lean4_version")
[ "$old_pw" != "$pw_version" ] && changes+=("proofwidgets: $old_pw -> $pw_version")
[ "$old_lsc" != "$lsc_version" ] && changes+=("LeanSearchClient: $old_lsc -> $lsc_version")
if [ ${#changes[@]} -eq 0 ]; then
echo "leanPackages: already up to date at lean4 $lean4_version"
else
echo "leanPackages: update to lean4 $lean4_version"
for c in "${changes[@]}"; do
echo " - $c"
done
echo "status: up-to-date"
exit 0
fi
echo "commit-title: leanPackages: lean4 $old_lockstep -> $lean4_version"
echo "---"
for c in "${changes[@]}"; do
echo " - $c"
done
echo "---"
echo "manifest-source: https://github.com/leanprover-community/mathlib4/blob/v${lean4_version}/lake-manifest.json"
echo "lean4-release: https://github.com/leanprover/lean4/releases/tag/v${lean4_version}"
+1 -1
View File
@@ -2853,7 +2853,7 @@ with pkgs;
leanblueprint = with python3Packages; toPythonApplication leanblueprint;
leanPackages = callPackage ../top-level/lean-packages.nix { };
leanPackages = recurseIntoAttrs (callPackage ../top-level/lean-packages.nix { });
inherit (callPackage ../development/tools/lerna { })
lerna_6
+3 -24
View File
@@ -1,45 +1,24 @@
# Lean 4 package set.
# Lean 4 package set with its own toolchain (independent of pkgs.lean4).
#
# All packages are built against a single Lean toolchain version.
# Dependencies between packages use `leanDeps` which propagates
# .olean files via LEAN_PATH (through setup hooks), similar to how
# Haskell propagates package.conf.d entries.
#
# Overriding lean4 propagates to all packages in the set:
# Override the toolchain for the entire set:
# leanPackages.overrideScope (self: super: { lean4 = lean4-custom; })
#
# Usage:
# leanPackages.batteries
# leanPackages.mathlib
# leanPackages.callPackage ./my-package.nix { }
{
lib,
newScope,
lean4,
}:
lib.makeScope newScope (self: {
inherit lean4;
lean4 = self.callPackage ../development/lean-modules/lean4 { };
# Resolve via self.callPackage so overriding lean4 in the scope
# propagates to the builder (same pattern as coqPackages).
buildLakePackage = self.callPackage ../build-support/lake { };
batteries = self.callPackage ../development/lean-modules/batteries { };
aesop = self.callPackage ../development/lean-modules/aesop { };
Qq = self.callPackage ../development/lean-modules/Qq { };
proofwidgets = self.callPackage ../development/lean-modules/proofwidgets { };
plausible = self.callPackage ../development/lean-modules/plausible { };
LeanSearchClient = self.callPackage ../development/lean-modules/LeanSearchClient { };
Cli = self.callPackage ../development/lean-modules/Cli { };
importGraph = self.callPackage ../development/lean-modules/importGraph { };
mathlib = self.callPackage ../development/lean-modules/mathlib { };
})