{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [], stdenv, lib, cmake, pkg-config, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs, ... } @ args: with builtins; lib.warn "The Nix-based build is deprecated" rec { inherit stdenv; sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs); buildCMake = args: stdenv.mkDerivation ({ nativeBuildInputs = [ cmake pkg-config ]; buildInputs = [ gmp libuv llvmPackages.llvm ]; # https://github.com/NixOS/nixpkgs/issues/60919 hardeningDisable = [ "all" ]; dontStrip = (args.debug or debug); postConfigure = '' patchShebangs . ''; } // args // { src = args.realSrc or (sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]); cmakeFlags = (args.cmakeFlags or [ "-DSTAGE=1" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" "-DCADICAL=${cadical}/bin/cadical" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ]; preConfigure = args.preConfigure or "" + '' # ignore absence of submodule sed -i 's!lake/Lake.lean!!' CMakeLists.txt ''; }); lean-bin-tools-unwrapped = buildCMake { name = "lean-bin-tools"; outputs = [ "out" "leanc_src" ]; realSrc = sourceByRegex (src + "/src") [ "CMakeLists\.txt" "[a-z].*" ".*\.in" "Leanc\.lean" ]; dontBuild = true; installPhase = '' mkdir $out $leanc_src mv bin/ include/ share/ $out/ mv leanc.sh $out/bin/leanc mv leanc/Leanc.lean $leanc_src/ substituteInPlace $out/bin/leanc --replace '$root' "$out" --replace " sed " " ${gnused}/bin/sed " substituteInPlace $out/bin/leanmake --replace "make" "${gnumake}/bin/make" substituteInPlace $out/share/lean/lean.mk --replace "/usr/bin/env bash" "${bash}/bin/bash" ''; }; leancpp = buildCMake { name = "leancpp"; src = src + "/src"; buildFlags = [ "leancpp" "leanrt" "leanrt_initial-exec" "leanshell" "leanmain" ]; installPhase = '' mkdir -p $out mv lib/ $out/ mv runtime/libleanrt_initial-exec.a $out/lib ''; }; stage0 = args.stage0 or (buildCMake { name = "lean-stage0"; realSrc = src + "/stage0/src"; debug = stage0debug; cmakeFlags = [ "-DSTAGE=0" ]; extraCMakeFlags = []; preConfigure = '' ln -s ${src + "/stage0/stdlib"} ../stdlib ''; installPhase = '' mkdir -p $out/bin $out/lib/lean mv bin/lean $out/bin/ mv lib/lean/*.{so,dylib} $out/lib/lean ''; meta.mainProgram = "lean"; }); stage = { stage, prevStage, self }: let desc = "stage${toString stage}"; build = args: buildLeanPackage.override { lean = prevStage; leanc = lean-bin-tools-unwrapped; # use same stage for retrieving dependencies lean-leanDeps = stage0; lean-final = self; } ({ src = src + "/src"; roots = [ { mod = args.name; glob = "andSubmodules"; } ]; fullSrc = src; srcPath = "$PWD/src:$PWD/src/lake"; inherit debug; leanFlags = [ "-DwarningAsError=true" ]; } // args); Init' = build { name = "Init"; deps = []; }; Std' = build { name = "Std"; deps = [ Init' ]; }; Lean' = build { name = "Lean"; deps = [ Std' ]; }; attachSharedLib = sharedLib: pkg: pkg // { inherit sharedLib; mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods; }; in (all: all // all.lean) rec { inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package; Init = attachSharedLib leanshared Init'; Std = attachSharedLib leanshared Std' // { allExternalDeps = [ Init ]; }; Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Std ]; }; Lake = build { name = "Lake"; sharedLibName = "Lake_shared"; src = src + "/src/lake"; deps = [ Init Lean ]; }; Lake-Main = build { name = "LakeMain"; roots = [{ glob = "one"; mod = "LakeMain"; }]; executableName = "lake"; deps = [ Lake ]; linkFlags = lib.optional stdenv.isLinux "-rdynamic"; src = src + "/src/lake"; }; stdlib = [ Init Std Lean Lake ]; modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); }; depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; }; iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; }; Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; }; stdlibLinkFlags = "${lib.concatMapStringsSep " " (l: "-L${l.staticLib}") stdlib} -L${leancpp}/lib/lean"; libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } '' mkdir $out touch empty.c ${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c ''; leanshared_1 = runCommand "leanshared_1" { buildInputs = [ stdenv.cc ]; libName = "leanshared_1${stdenv.hostPlatform.extensions.sharedLibrary}"; } '' mkdir $out touch empty.c ${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c ''; leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } '' mkdir $out LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \ -Wl,--whole-archive ${leancpp}/lib/temp/libleanshell.a -lInit -lStd -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++ \ -lm ${stdlibLinkFlags} \ $(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \ -o $out/$libName ''; mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib; print-paths = Lean.makePrintPathsFor [] mods; leanc = writeShellScriptBin "leanc" '' LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${libInit_shared} -L${leanshared_1} -L${leanshared} -L${Lake.sharedLib} "$@" ''; lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } '' mkdir -p $out/bin ${leanc}/bin/leanc ${leancpp}/lib/temp/libleanmain.a ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* -o $out/bin/lean ''; # derivation following the directory layout of the "basic" setup, mostly useful for running tests lean-all = stdenv.mkDerivation { name = "lean-${desc}"; buildCommand = '' mkdir -p $out/bin $out/lib/lean ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* ${Lake.sharedLib}/* $out/lib/lean/ # put everything in a single final derivation so `IO.appDir` references work cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin # NOTE: `lndir` will not override existing `bin/leanc` ${lndir}/bin/lndir -silent ${lean-bin-tools-unwrapped} $out ''; meta.mainProgram = "lean"; }; cacheRoots = linkFarmFromDrvs "cacheRoots" ([ stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src ] ++ map (lib: lib.oTree) stdlib); test = buildCMake { name = "lean-test-${desc}"; realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ]; buildInputs = [ gmp libuv perl git cadical ]; preConfigure = '' cd src ''; extraCMakeFlags = [ "-DLLVM=OFF" ]; postConfigure = '' patchShebangs ../../tests ../lake rm -r bin lib include share ln -sf ${lean-all}/* . ''; buildPhase = '' ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi|leanruntest_timeIO' -j$NIX_BUILD_CORES ''; installPhase = '' mkdir $out mv test-results.xml $out ''; }; update-stage0 = let cTree = symlinkJoin { name = "cs"; paths = map (lib: lib.cTree) (stdlib ++ [Lake-Main]); }; in writeShellScriptBin "update-stage0" '' CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"} ''; update-stage0-commit = writeShellScriptBin "update-stage0-commit" '' set -euo pipefail ${update-stage0}/bin/update-stage0 git commit -m "chore: update stage0" ''; link-ilean = writeShellScriptBin "link-ilean" '' dest=''${1:-src} rm -rf $dest/build/lib || true mkdir -p $dest/build/lib ln -s ${iTree}/* $dest/build/lib ''; benchmarks = let entries = attrNames (readDir (src + "/tests/bench")); leanFiles = map (n: elemAt n 0) (filter (n: n != null) (map (match "(.*)\.lean") entries)); in lib.genAttrs leanFiles (n: (buildLeanPackage { name = n; src = filterSource (e: _: baseNameOf e == "${n}.lean") (src + "/tests/bench"); }).executable); }; stage1 = stage { stage = 1; prevStage = stage0; self = stage1; }; stage2 = stage { stage = 2; prevStage = stage1; self = stage2; }; stage3 = stage { stage = 3; prevStage = stage2; self = stage3; }; }