Compare commits

..

784 Commits

Author SHA1 Message Date
Wojciech Nawrocki
f1f693fcd5 Update Trace.lean 2023-07-27 15:27:56 -07:00
Wojciech Nawrocki
a75fc1d756 Update src/Lean/Util/Trace.lean
Co-authored-by: Gabriel Ebner <gebner@gebner.org>
2023-07-27 15:27:24 -07:00
Wojciech Nawrocki
b4f08799fb fix: handle error in withTrace message action 2023-07-27 12:36:56 -07:00
Sebastian Ullrich
53477089fe chore: remove unused macOS dependencies 2023-07-26 15:36:36 +02:00
Sebastian Ullrich
132f655736 chore: add zlib search path on macOS only when linking libleanshared 2023-07-26 15:36:36 +02:00
Sebastian Ullrich
978a5b2528 fix: loading libc++ on macOS Sonoma 2023-07-26 15:36:36 +02:00
Siddharth Bhat
96c59ccced chore: update stage0 2023-07-25 11:03:16 +02:00
Siddharth Bhat
073c8fed86 feat: LLVM backend: support for visibility Style & DLL storage
Changes peeled from:
https://github.com/leanprover/lean4/pull/2340

to allow a `stage0` bump on master before merging in the
changes that allow LLVM to build in stage1+.
2023-07-25 11:03:16 +02:00
Alex J Best
808bb9b579 perf: dont repeatedly elab term in rw at multiple locations #2317 2023-07-24 08:47:52 -07:00
Bulhwi Cha
3b6bc4a87d style: remove unnecessary space characters 2023-07-23 16:11:11 +02:00
Mario Carneiro
dd313c6894 feat: add IO.FS.rename 2023-07-22 23:21:32 +02:00
Bulhwi Cha
7809d49a62 doc: fix type signature of Coe 2023-07-22 14:16:21 +02:00
Sebastian Ullrich
544b704a25 test: add Lake tests 2023-07-21 09:19:19 +02:00
Sebastian Ullrich
d991f5efe0 fix: ship libLake.a 2023-07-21 09:19:19 +02:00
Sebastian Ullrich
e2fbfb5731 chore: remove Lake flake
Fixes leanprover/lake#165
2023-07-21 09:19:19 +02:00
Sebastian Ullrich
8999ef067b chore: Nix: fixup Lake integration 2023-07-21 09:19:19 +02:00
Jannis Limperg
6407197e54 chore: better error message for loose bvar in whnf 2023-07-20 13:47:20 -07:00
Bulhwi Cha
367b38701f refactor: simplify String.splitOnAux (#2271) 2023-07-19 11:50:27 +00:00
Wojciech Nawrocki
e1b3f10250 doc: fix contradictory docstring 2023-07-19 10:53:47 +02:00
F. G. Dorais
d10e3da673 fix: protect sizeOf lemmas 2023-07-19 08:50:59 +02:00
Sebastian Ullrich
d62fca4e9c chore: safer bench script 2023-07-19 08:31:39 +02:00
Leonardo de Moura
634193328b fix: fixes #2327 2023-07-18 07:18:27 -07:00
Sebastian Ullrich
daae36d44d chore: remove obsolete file 2023-07-17 10:38:35 +02:00
Sebastian Ullrich
c35e41ce15 chore: Nix: add lake executable 2023-07-17 10:38:35 +02:00
Sebastian Ullrich
90aab46071 chore: fix update-stage0 2023-07-17 10:38:35 +02:00
Sebastian Ullrich
bf76eca0cd chore: merge Lake into src/lake 2023-07-17 10:38:20 +02:00
Sebastian Ullrich
9a3657df3f chore: remove Lake submodule 2023-07-15 12:03:41 +02:00
tydeu
d37bbf4292 chore: update Lake 2023-07-14 23:43:04 -04:00
Floris van Doorn
1a6663a41b chore: write "|-" as "|" noWs "-" (#2299)
* remove |- as an alias for ⊢

* revert false positive |->

* fix docstring

* undo previous changes

* [unchecked] use suggestion

* next attempt

* add test
2023-07-14 09:48:20 -07:00
Leonardo de Moura
212cd9c3e6 fix: fixes #2321 2023-07-13 14:41:32 -07:00
Scott Morrison
0d5c5e0191 feat: relax test in checkLocalInstanceParameters to allow instance implicits 2023-07-13 10:54:06 -07:00
Scott Morrison
7213ff0065 doc: document generating releases via tags (#2302) 2023-07-13 17:39:54 +02:00
Sebastian Ullrich
4562e8d9a2 fix: do not use GMP on ARM Linux 2023-07-13 09:35:00 +02:00
Leonardo de Moura
6e90442130 chore: disable benchtest at debug and fsanitize 2023-07-11 19:19:42 -07:00
Leonardo de Moura
fd0549feb5 chore: improve test 2023-07-11 19:19:42 -07:00
Leonardo de Moura
6d857a93b5 perf: pointer set for traversing DAGs 2023-07-11 19:19:42 -07:00
Leonardo de Moura
264e376741 chore: add helper function 2023-07-11 19:19:42 -07:00
Sebastian Ullrich
a3ebfe29ea chore: revert "chore: compile against glibc 2.26"
This reverts commit ae0e0ed1db.
2023-07-10 21:44:10 +02:00
Sebastian Ullrich
ae0e0ed1db chore: compile against glibc 2.26 2023-07-10 18:59:06 +02:00
Adrien Champion
d8a548fe51 chore: fix Int.div docstring examples 2023-07-10 09:09:07 -07:00
Scott Morrison
60b8fdd8d6 feat: use nat_pow in the kernel 2023-07-10 09:01:14 -07:00
Mario Carneiro
51694cd6de fix: calling convention for module initializers 2023-07-10 09:00:17 -07:00
Mario Carneiro
76023a7c6f fix: don't run [builtin_init] when builtin = false 2023-07-10 08:58:02 -07:00
tydeu
f46c792206 doc: fix up facet module docs 2023-07-06 00:37:32 -04:00
Sebastian Ullrich
c268d7e97b fix: kill descendant processes on worker exit 2023-07-05 23:42:53 +02:00
Sebastian Ullrich
9901804a49 feat: SpawnArgs.setsid, Child.kill 2023-07-05 23:42:53 +02:00
Leonardo de Moura
32d5def5b8 feat: add bne_iff_ne 2023-07-05 08:51:34 -07:00
tydeu
538ed26ca4 feat: module deps facet (+ test)
also improve facet build info docs
2023-07-03 18:31:34 -04:00
tydeu
331c4c39b8 feat: type-level named Package + target fetch helpers 2023-07-01 23:10:25 -04:00
tydeu
68800cdcf8 chore: fix test 2023-07-01 19:25:51 -04:00
tydeu
a0626a9334 refactor: libDir -> nativeLibDir; oleanDir -> leanLibDir
also
* remove deprecated `isLeanOnly`
* touch-up some docs
2023-07-01 11:53:52 -04:00
Leonardo de Moura
5402c3cf76 chore: fix test file names 2023-07-01 06:20:36 -07:00
Mario Carneiro
f1b2a8acce fix: lazy_binop + coercion bug
fixes #2300
2023-07-01 06:05:25 -07:00
Leonardo de Moura
94d4a427e2 fix: fixes #2115 2023-06-30 19:54:38 -07:00
Leonardo de Moura
a002ce6d0d fix: fixes #2077 2023-06-30 19:26:00 -07:00
Sebastian Ullrich
e2383729a6 doc: clarify current release process 2023-06-30 10:30:37 -07:00
tydeu
aee9ce4321 chore: update Lake 2023-06-30 09:44:26 +02:00
tydeu
01b3e70a8d feat: add some helpers for pkg and lib roots
also update some docstrings
2023-06-29 23:00:03 -04:00
tydeu
8f3468b82c chore: bump Lean version 2023-06-29 20:16:58 -04:00
tydeu
5190c7fcc3 test: rename issue dirs that test multiple issues 2023-06-29 17:47:18 -04:00
tydeu
337891c9eb fix: do not build missing directory modules (+ test)
error reported on Zulip:
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/lake.20build.20all/near/370788618
2023-06-29 17:42:27 -04:00
Leonardo de Moura
ec42581d1f perf: use Core.transform instead of Meta.transform at betaReduceLetRecApps
Observed big performance improvement on files containing big proofs
generated using tactics.
2023-06-28 12:29:12 -07:00
Sebastian Ullrich
371fc8868a doc: move out Nix setup 2023-06-28 09:49:08 +01:00
Leonardo de Moura
eece499da9 fix: fixes #2282 2023-06-27 16:46:38 -07:00
Sebastian Ullrich
f0583c3fd6 feat: trace nodes for SizeOf and injectivity theorem generation 2023-06-27 16:17:46 -07:00
Wojciech Nawrocki
ba4bfe26f2 fix: add missing instantiateMVars 2023-06-27 16:13:56 -07:00
Sebastian Ullrich
d54ecc4373 doc: refer to mathlib4 instructions in quickstart 2023-06-27 14:21:44 -07:00
Sebastian Ullrich
e84a5891f8 doc: quickstart note on moving from Lean 3 to 4 2023-06-27 14:21:44 -07:00
Mario Carneiro
3104c223d8 fix: reference implementation for Array.mapM 2023-06-27 14:21:22 -07:00
tydeu
46c77afeaf chore: update Lake 2023-06-27 21:35:51 +01:00
Sebastian Ullrich
e1999ada7f fix: make "elaboration" metric work in language server 2023-06-27 15:56:34 +01:00
Mario Carneiro
bb8cc08de8 chore: compact objects in post-order 2023-06-26 08:35:19 -07:00
Pietro Monticone
fff4aea0d9 doc: fix typos (#2287) 2023-06-25 20:30:33 +02:00
Leonardo de Moura
4036be4f50 fix: add missing check at IR checker 2023-06-23 08:43:39 -07:00
Mario Carneiro
123c1ff7f0 fix: basic ident fallback in identComponents 2023-06-22 09:50:24 +01:00
Floris van Doorn
32e93f1dc1 fix: delete Measure and SizeOfRef (#2275)
* move Measure to Nat namespace

We could (and maybe should) also move various other declarations to namespaces, like measure. However, measure seems to be used a lot in termination_by statements, so that requires other fixes as well. Measure seems to be almost unused

* fix

* delete Measure and SizeOfRef instead
2023-06-21 22:51:28 -07:00
Mario Carneiro
e0893b70e5 fix: incorrect type for SpecInfo.argKinds 2023-06-21 22:50:29 -07:00
Leonardo de Moura
26877c42ae chore: update stage0 2023-06-21 22:30:53 -07:00
Leonardo de Moura
425f42cd83 feat: better support for Nat literals at DiscrTree.lean 2023-06-21 22:30:09 -07:00
Leonardo de Moura
bebf1927f8 chore: remove workarounds 2023-06-21 20:35:33 -07:00
Leonardo de Moura
19d266e0c5 chore: upate stage0 2023-06-21 20:31:47 -07:00
Leonardo de Moura
184f2ed597 chore: improve isNonTrivialProof 2023-06-21 20:28:17 -07:00
Leonardo de Moura
7367f2edc6 fix: unfold constant theorems when transparency is set to .all 2023-06-21 20:28:17 -07:00
Leonardo de Moura
9df2f6b0c9 fix: bump transparency to .all when reducing the major premise of Acc.rec and WellFounded.rec 2023-06-21 20:28:17 -07:00
Leonardo de Moura
2b8e55c2f1 fix: Nat literal bug at DiscrTree.lean 2023-06-21 20:28:17 -07:00
Leonardo de Moura
d6695a7a2e fix: use mkAuxTheoremFor when creating helper proof_n theorems 2023-06-21 20:28:17 -07:00
tydeu
3f9a867469 test: generalize make test/clean targets 2023-06-21 18:48:09 -04:00
tydeu
abdbc39403 test: add test for leanprover/lake#174 2023-06-21 18:19:12 -04:00
Scott Morrison
a44dd71ad6 feat: add flag for apply to defer failed typeclass syntheses as goals 2023-06-19 20:07:07 -07:00
Scott Morrison
82196b5b94 feat: allow upper case single character identifiers when relaxedAutoImplicit false (#2277)
* feat: allow upper case single character identifiers when relaxedAutoImplicit false

* update tests

* fix tests

* fix another test

---------

Co-authored-by: Scott Morrison <scott.morrison@anu.edu.au>
2023-06-19 20:04:09 -07:00
Mario Carneiro
2348fb37d3 fix: use Lean.initializing instead of IO.initializing 2023-06-17 06:57:14 -07:00
Mario Carneiro
e64a2e1a12 fix: misleading indentation 2023-06-17 06:56:53 -07:00
Denis Gorbachev
1292819f64 chore: update scripts example to new GetElem syntax (leanprover/lake#171) 2023-06-10 03:55:55 -04:00
Gabriel Ebner
bff612e59e fix: simp: synthesize non-inst-implicit tc args
Fixes #2265.
2023-06-09 16:32:02 -07:00
Mario Carneiro
1ac8a4083f feat: report section name in invalid end msg 2023-06-09 14:41:39 -07:00
Mario Carneiro
b4cf1dd943 feat: binder info for generalize 2023-06-09 14:41:00 -07:00
tydeu
3fb146fad2 chore: fix test on MacOS 2023-06-08 14:05:04 -04:00
tydeu
462d306184 chore: fix test on non-Windows 2023-06-08 13:40:21 -04:00
tydeu
13d5e6f542 feat: add untraced weakLeanArgs
closes leanprover/lake#172
2023-06-08 03:29:51 -04:00
tydeu
cf216ecd16 chore: update Lean to 06-01
also:
* refactor code relying on the old `toName`
* do not decapitalize package names in `lake new`
2023-06-08 02:06:13 -04:00
tydeu
c0edda1373 doc: fix some README wording 2023-06-07 22:25:52 -04:00
tydeu
3f49861ee1 test: add test with - in lake new
from https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/lake.20new.20lean-data
2023-06-02 03:18:06 -04:00
Mac
b74d9c09d5 chore: delete unintended commit of flake.lock (leanprover/lake#170) 2023-05-24 19:26:36 -04:00
Sebastian Ullrich
a32c3e0140 feat: make .lean hashes cross-platform compatible (leanprover/lake#170) 2023-05-23 08:10:19 -04:00
tydeu
72487e5650 fix: remove olean/ilean duplication in module traces 2023-04-18 20:58:40 -04:00
tydeu
eb157000a4 chore: remove doc of isLeanOnly and warn on its use 2023-04-18 20:58:40 -04:00
Gabriel Ebner
0656482b91 feat: show number of files to go when building 2023-04-18 20:58:40 -04:00
Gabriel Ebner
312960820c feat: priority for bindSync 2023-04-18 20:58:40 -04:00
Gabriel Ebner
98a55105ff chore: update Lean version 2023-04-18 20:58:40 -04:00
Gabriel Ebner
a1a30aac1c refactor: simplify recBuildLeanCore 2023-04-18 20:58:40 -04:00
tydeu
c49a7d84e9 chore: fix test 2023-04-15 21:04:46 -04:00
tydeu
346da2c29c feat: bare lake run default scripts 2023-04-15 20:07:47 -04:00
tydeu
227a350747 doc: tweak README + fix some typos 2023-04-15 18:32:21 -04:00
Gabriel Ebner
caa4494cb7 chore: remove dangerous instances 2023-04-15 18:16:53 -04:00
Scott Morrison
a45f808da4 chore: don't rely on simp calling decide (leanprover/lake#168) 2023-03-28 12:32:39 -04:00
Sebastian Ullrich
7648ec57b5 fix: adapt to new Handle.mk signature
The previous code was arguably wrong in any case as the result of `lake
init` should not depend on the current platform
2023-03-17 09:15:26 -04:00
Gabriel Ebner
620587fc42 feat: make lake clean clean all packages
Fixes leanprover/lake#155
2023-03-10 22:51:11 -05:00
Gabriel Ebner
57fea2d8e3 feat: accept empty git hash as version
Fixes leanprover/lake#154
2023-03-10 22:49:36 -05:00
Gabriel Ebner
276bf837e2 feat: show stdout by default 2023-03-10 22:48:35 -05:00
Kaiyu Yang
421e73f6c5 doc: fix typo in README (leanprover/lake#157) 2023-02-24 16:02:00 -05:00
Martin Dvořák
83dffbc2f8 doc: mention lake clean in README (leanprover/lake#156) 2023-02-23 12:14:17 -05:00
tydeu
16af1dddf4 fix: include link args in shared lib trace of extern lib 2023-02-21 06:35:39 -05:00
tydeu
5080b08922 chore: reduce imports in Lake.Build.Actions 2023-02-02 20:38:06 -05:00
Arthur Paulino
05c2ac5f3c download lean-toolchain directly 2023-02-02 20:34:02 -05:00
tydeu
7055f953f1 doc: fix typo
closes leanprover/lake#151
2023-02-02 15:40:02 -05:00
tydeu
e1887fa510 fix: put FFI lib in pkg lib dir in example (for Linux) 2023-01-11 18:24:15 -05:00
tydeu
55fa486ce6 fix: packages dir path and repo url 2023-01-11 18:18:09 -05:00
tydeu
15d656bd9a fix: Linux still needs augmented library path 2023-01-11 17:32:26 -05:00
tydeu
4f505cd056 fix: use full path when loading dynlibs in the server
closes leanprover/lake#146
2023-01-11 16:17:47 -05:00
tydeu
8c793eaae5 chore: bump Lean version 2023-01-11 15:11:26 -05:00
Gabriel Ebner
cee959078d fix: do not require Environment to be inhabited 2023-01-11 15:01:45 -05:00
tydeu
148b067724 test: fix shell script permissions 2022-12-02 17:58:51 -05:00
tydeu
479fe81894 feat: print log on failing lake print-paths
closes leanprover/lake#116
2022-12-02 17:26:36 -05:00
Gabriel Ebner
47b4eae9a6 perf: use ByteArray.hash directly 2022-12-02 14:31:48 -05:00
tydeu
c60ccdc974 test: increase sleep in 44 2022-12-02 14:20:58 -05:00
tydeu
25ab266a2e fix: escape names from new/init
closes leanprover/lake#128
2022-12-02 14:17:57 -05:00
tydeu
b8c4ed5a83 feat: -U to update & build; add packagesDir to manifest 2022-12-02 14:17:57 -05:00
tydeu
93f1d05e2a fix: various build problems
fixes leanprover/lake#139
touches on leanprover/lake#132
2022-12-02 14:17:56 -05:00
tydeu
b813197b36 chore: cleanup 2022-12-02 14:17:56 -05:00
Gabriel Ebner
b76bfcac91 fix: do not rely on iteration order of NameSet 2022-12-02 14:11:12 -05:00
Gabriel Ebner
7603e49169 chore: bump Lean version 2022-12-02 14:06:15 -05:00
Leonardo de Moura
8fbb866798 fix: incorrect use of outParam
We have
```
class BindAsync (n : Type u → Type v) (k : outParam $ Type u → Type u)
instance : BindAsync BaseIO (EIOTask ε)
instance : BindAsync BaseIO OptionIOTask
instance [BindAsync n k] [Pure n] [Pure k] : BindAsync n (ExceptT ε k)
instance [BindAsync n k] [Pure n] [Pure k] : BindAsync n (OptionT k)
```

See discussion at: https://leanprover.zulipchat.com/#narrow/stream/147302-lean4-maintainers/topic/Increasing.20.60Expr.2Ehash.60.20to.2064.20bits/near/313183466
2022-11-30 16:56:09 -08:00
Leonardo de Moura
dc937cb1f9 chore: Name.append 2022-11-29 23:05:19 -08:00
Gabriel Ebner
733f015c65 chore: reduce imports 2022-11-23 20:56:40 -05:00
Gabriel Ebner
42a8e0f190 refactor: split code for lake update and lake build 2022-11-23 20:56:40 -05:00
Gabriel Ebner
1949285fdb chore: disable parallel testing in ci 2022-11-23 20:56:40 -05:00
Gabriel Ebner
2808cc2744 feat: improve manifest test 2022-11-23 20:56:40 -05:00
Gabriel Ebner
031d9712d5 chore: simplify test/manifest/test.sh 2022-11-23 20:56:40 -05:00
Gabriel Ebner
716fe7abb8 perf: use parseImports' 2022-11-11 13:21:42 -05:00
Gabriel Ebner
c614ffa2f7 chore: bump Lean version 2022-11-11 13:21:42 -05:00
tydeu
837eec5d9a feat: add buildO helper
closes leanprover/lake#126
2022-11-10 20:48:05 -05:00
tydeu
8e6abd7c56 doc: add --old to lake help 2022-11-10 20:48:05 -05:00
tydeu
ddd7581ee4 refactor: lean_packages -> lake-packages + cleanup 2022-11-10 20:48:04 -05:00
tydeu
855a655033 refactor: split actions requiring load into separate file
see 1bd8430c15 (r82430947)
2022-11-10 20:48:03 -05:00
tydeu
0bf59a5921 feat: library defaultFacets setting
closes leanprover/lake#117
2022-11-10 20:48:02 -05:00
tydeu
d3d526d43f test: make FFI example builds verbose 2022-11-10 20:46:57 -05:00
tydeu
0b1d2956a4 refactor: change manifest file path
closes leanprover/lake#111
2022-11-10 20:46:57 -05:00
Mario Carneiro
9544a0572e fix: remove #check 2022-11-10 20:46:55 -05:00
tydeu
f40dbbcf02 chore: remove verbosity from LoadConfig 2022-11-10 20:46:55 -05:00
tydeu
fc65f6e73e chore: start next Lake version 2022-11-10 20:46:54 -05:00
tydeu
17a4bcb3e1 Merge remote-tracking branch 'gebner/minmax' 2022-10-25 20:58:41 -04:00
Gabriel Ebner
56d0fbd537 chore: bump Lean version 2022-10-25 15:20:38 -07:00
Gabriel Ebner
783a61ab76 chore: Min/Max typeclasses 2022-10-21 11:23:29 -07:00
tydeu
3ad183e502 Merge branch 'snake' 2022-10-20 12:27:16 -04:00
tydeu
25fe4a6f4d chore: update Lean version + attr fixes 2022-10-20 12:20:57 -04:00
Mario Carneiro
39feeaab74 chore: snake-case attributes 2022-10-18 21:34:51 -04:00
Gabriel Ebner
96acc7269d fix: use typed syntax 2022-10-18 10:53:48 -07:00
Gabriel Ebner
7da0dd2fcf fix: remove ` (funBinder|`` 2022-10-17 14:07:16 -07:00
Gabriel Ebner
1742c79afe chore: remove auxDecl binder info 2022-10-10 16:30:16 -07:00
tydeu
37811b2104 chore: update Lean version 2022-09-28 16:15:46 -04:00
tydeu
4811ba7850 Merge remote-tracking branch 'digama0/std_ns' 2022-09-28 16:03:27 -04:00
Mario Carneiro
ebdbc77631 chore: move Std -> Lean namespace 2022-09-24 00:08:26 -04:00
Sebastian Ullrich
3c6c1c25e4 chore: simplify elan CI setup 2022-09-21 16:36:05 -04:00
tydeu
48688da4b1 chore: update Lean version 2022-09-20 18:34:50 -04:00
tydeu
e55589cc7f Merge remote-tracking branch 'digama0/import_reduction' 2022-09-20 18:34:33 -04:00
Mario Carneiro
032dc4bc8f chore: move NameMap into a separate file 2022-09-14 21:32:25 -04:00
Gabriel Ebner
024a298eb7 chore: use new constructor docstring syntax 2022-09-13 19:11:13 +02:00
Mario Carneiro
21262e5dca chore: move Bootstrap.Data -> Lean.Data 2022-08-29 11:14:25 -04:00
Mario Carneiro
f4bae4cd2a chore: move Std -> Bootstrap 2022-08-29 01:03:08 -04:00
tydeu
f0c79f0954 chore: update Lean version 2022-08-08 18:03:25 -04:00
Leonardo de Moura
1c5ec65260 chore: runTermElabM refactor 2022-08-07 07:30:29 -07:00
tydeu
a7e0e5b50a release: 4.0.0 2022-08-05 22:51:13 -04:00
tydeu
70172158a4 fix: improve targets/facets UX (e.g., errors when type incorrect) 2022-08-05 22:24:32 -04:00
tydeu
5ae0b979e8 doc: update README and some comments 2022-08-05 22:06:32 -04:00
tydeu
4fba6ae385 chore: bump Lean version 2022-08-05 17:42:00 -04:00
tydeu
c6327e66ca chore: bump Lake version 2022-08-05 17:38:27 -04:00
tydeu
ecadca6902 feat: make manifest file configurable
see leanprover/lake#111
2022-08-05 17:31:04 -04:00
tydeu
db39141034 feat: replace extraDepTarget with extraDepTargets 2022-08-05 15:48:23 -04:00
tydeu
a889a7387c test: make test 44 more consistent 2022-08-04 22:23:46 -04:00
tydeu
350e1b810a refactor: split CLI actions into separate file 2022-08-04 21:31:58 -04:00
tydeu
f0ae7bff1e feat: ws.runBuild 2022-08-04 21:19:23 -04:00
tydeu
9121c4dfa8 feat: facet info param + unique names for facet syntax 2022-08-04 19:55:32 -04:00
tydeu
5558ad89a1 refactor: move fetching releases to extraDep build 2022-08-04 18:58:17 -04:00
tydeu
f2bcba7c73 refactor: renames + cleanup 2022-08-04 18:30:53 -04:00
tydeu
b8ed74e89f feat: recursive builds in extern_lib 2022-08-04 16:58:42 -04:00
tydeu
19afb95dd7 chore: test 44 shell script fixes 2022-08-03 00:56:50 -04:00
tydeu
5b81042614 ci: add diffutils to Windows MSYS2 setup 2022-08-03 00:42:30 -04:00
tydeu
56cec0b41c feat: --old to use outdated unchanged modules
closes leanprover/lake#44
2022-08-03 00:35:44 -04:00
tydeu
99a0a1ee1f refactor: remove remainder of Target code 2022-08-02 21:46:51 -04:00
tydeu
93c0b44623 doc: correct require syntax docs 2022-08-02 02:26:42 -04:00
tydeu
65825e4210 refactor; cleanup (primarly resolve code) 2022-08-02 01:58:13 -04:00
tydeu
b022a99027 fix: pass pkg linking args to extern lib linking 2022-08-02 00:13:58 -04:00
tydeu
59585d2374 refactor: cleanup logging API (unify BuildIO with LogIO) 2022-08-01 22:37:07 -04:00
tydeu
d5b6a49054 feat: platform bits in build archive name + related cleanup 2022-08-01 18:50:06 -04:00
tydeu
f4734e35ff feat: inherit deep desp's revision from dep's manifest
closes leanprover/lake#70
2022-07-31 03:16:27 -04:00
tydeu
c0a04de055 feat: store config rev in manifest and warn on change
see leanprover/lake#85
2022-07-29 15:15:39 -04:00
tydeu
aed23307b0 chore: correctly mark version as prerelease 2022-07-29 01:15:39 -04:00
tydeu
3cfc0d9f68 feat: cloud build support 2022-07-28 23:31:39 -04:00
Mario Carneiro
a0400cbe97 feat: verbosity options for logging + neater build progress 2022-07-28 14:45:23 -04:00
tydeu
2d2bed90aa refactor: Lake.Build.Topological tweaks + docs 2022-07-28 02:26:45 -04:00
tydeu
6bb5101256 refactor: pattern TargetConfig off FacetConfig 2022-07-27 19:54:15 -04:00
tydeu
bc8c809d66 refactor; replace ActiveTarget with Job 2022-07-27 16:08:09 -04:00
tydeu
dd30925ba6 chore: fix targets example 2022-07-27 02:46:36 -04:00
tydeu
1c916b755a refactor: reduce use of targets + IndexT cleanup 2022-07-27 00:27:12 -04:00
tydeu
226def8b82 refactor: remove many used Target methods 2022-07-26 23:40:29 -04:00
tydeu
6709a795df fix: apply nameToSharedLib to modTargets too 2022-07-26 23:24:49 -04:00
tydeu
8b402c4ee0 refactor: move info into target task 2022-07-26 21:13:43 -04:00
tydeu
5e3282347e refactor: remove facet target helpers 2022-07-26 15:30:11 -04:00
tydeu
33e05e16be chore: cleanup at recBuildExternalDynlibs 2022-07-26 15:27:01 -04:00
tydeu
a05e35c783 feat: library facets 2022-07-26 15:07:27 -04:00
tydeu
97100dcd02 feat: build all CLI targets in the same build pass 2022-07-25 20:48:31 -04:00
tydeu
f843d29f72 refactor: remove module facet special casing 2022-07-25 15:36:42 -04:00
tydeu
1d2ca29f2a chore: remove package config builtin targets 2022-07-25 14:59:49 -04:00
tydeu
90ba1a6556 chore: start next Lake version 2022-07-25 14:59:39 -04:00
tydeu
afe18ac02e release: 3.2.2 2022-07-24 22:44:36 -04:00
tydeu
48b1ed711a chore: bump Lean version 2022-07-24 22:37:48 -04:00
tydeu
b784f8c3af ci: don't skip after successful duplicate
Old duplicate runs can be lost (e.g., on a force push)
2022-07-24 22:00:39 -04:00
tydeu
dc8097dae6 feat: support pkg/ to disambiguate packages 2022-07-24 21:47:34 -04:00
tydeu
10940bf07b refactor: merge IndexTargets into Index 2022-07-24 21:47:13 -04:00
tydeu
ff23465a04 chore: try to fix meta test script on macOS 2022-07-24 21:43:41 -04:00
tydeu
09e05cc1a9 feat: add do helper for grouping cmds + meta test 2022-07-24 21:43:40 -04:00
tydeu
ac5d83ca15 feat: add meta if helper command for config switchs 2022-07-24 21:43:40 -04:00
tydeu
67775edd18 refactor: make LeanLib.buildModules a proper recursive build 2022-07-24 00:34:57 -04:00
tydeu
abe8e8b1f8 docs: touch-up of Lake.Util.Family comments 2022-07-23 22:07:34 -04:00
tydeu
d68029092a refactor: simplify FacetConifg and build monads ala leanprover/lake#107
closes leanprover/lake#107
2022-07-23 19:39:47 -04:00
tydeu
1256453ad5 refactor: move mod/pkg facets from pkg to ws 2022-07-22 17:56:06 -04:00
Mario Carneiro
fc34cd2b8e chore: convert doc/mod comments from /- to /--//-! 2022-07-22 10:46:14 -04:00
tydeu
6caea9306c feat: resolve depss while loading a pkg 2022-07-22 04:46:44 -04:00
tydeu
a6cc5f3a9d doc: mention types of root(s)/lib/exeName in README
closes leanprover/lake#105
2022-07-20 19:38:09 -04:00
tydeu
aaf3c1e959 refactor: split config elab into its own file 2022-07-15 21:42:20 -04:00
tydeu
695b8f9b5d refactor: move all manifest code to its file + split Package.load 2022-07-15 21:06:55 -04:00
tydeu
ab528009ee refactor: move config loading code into its own directory 2022-07-15 16:38:35 -04:00
tydeu
5f9166c621 test: try to fix sed script for test 104 for MacOS 2022-07-15 15:58:13 -04:00
tydeu
f93a47de69 fix: do not fetch if dep rev matches manifest
also add some warnings on url/manifest mismatch + other minor cleanup

closes leanprover/lake#104
2022-07-15 15:11:27 -04:00
tydeu
23a578c37c refactor: add LawfulCmpEq + post-PR cleanup 2022-07-14 18:11:12 -04:00
tydeu
32f870a994 chore: update Lean version 2022-07-14 15:04:45 -04:00
Gabriel Ebner
f76b488fd5 chore: hash field in Name was dropped 2022-07-14 15:04:45 -04:00
tydeu
5cd2d85515 doc: add trace to glossary + cleanup 2022-07-14 14:47:51 -04:00
tydeu
e498ff1aa8 doc: add glossary of Lake terminology to README
also added missing doc on `LeanLibConifg.srcDir`
2022-07-12 01:43:50 -04:00
tydeu
68b81ca065 refactor: intro Lake.Env & add it to Workspace
also `LakeConfig` -> `LoadConfig`
2022-07-11 23:06:19 -04:00
tydeu
2e38df619c fix: Glob.forEachModuleIn
closes leanprover/lake#102
2022-07-11 15:45:50 -04:00
Sebastian Ullrich
fe5d95e7e3 fix: flake.nix 2022-07-10 22:57:44 +02:00
tydeu
62bdde1548 chore: update Lean version 2022-07-09 15:08:09 -04:00
Sebastian Ullrich
03da79a603 fix: restore script arg syntax 2022-07-09 15:05:19 -04:00
Sebastian Ullrich
1ea2a52448 chore: adapt to simpleBinder removal 2022-07-09 15:05:18 -04:00
Leonardo de Moura
b33aa09384 chore: the for in elaborator now propagates the element type to the body 2022-07-09 14:54:40 -04:00
tydeu
25d3860823 feat: lake exe CLI to run workspace exes
closes leanprover/lake#82
2022-07-09 02:47:01 -04:00
Sebastian Ullrich
b57ca74794 chore: skip elan test if no elan found 2022-07-08 23:05:12 -04:00
Sebastian Ullrich
49a025889a chore: remove redundant declaration in .envrc 2022-07-08 23:05:12 -04:00
Sebastian Ullrich
a45d86cb96 chore: update flake.nix 2022-07-08 23:05:12 -04:00
tydeu
958e3fc4da feat: add shorthands for lake script run/list
closes leanprover/lake#88
2022-07-08 23:03:42 -04:00
tydeu
ca04bf9b43 refactor: reorg cli code some (e.g., split cmds into defs) 2022-07-08 22:51:07 -04:00
tydeu
0fbd7a866a feat: replace __args__ with get_config? + related refactors 2022-07-08 19:00:52 -04:00
tydeu
185e10f6f3 misc: hoist facet name check to load + related bugfixes/refactors 2022-07-07 21:38:55 -04:00
tydeu
c45088b2ea chore: start next Lake version 2022-07-07 21:38:54 -04:00
tydeu
ee59d66268 release: 3.2.1 2022-07-05 19:28:40 -04:00
tydeu
adc6317e7b chore: bump Lean version 2022-07-05 19:15:45 -04:00
tydeu
958f38b31e feat: setup lean/lake env for server even if config has errors 2022-07-05 19:08:47 -04:00
tydeu
0a53ecb768 feat: add module file path helpers 2022-07-05 18:10:37 -04:00
tydeu
44f8e27a29 refactor: LeanExe.facet -> exeFacet 2022-07-05 17:46:44 -04:00
tydeu
3229d5084c fix: properly update deps w/ no branch or dir but no manifest
closes leanprover/lake#94
2022-07-05 17:36:38 -04:00
tydeu
df8085b7c2 fix: don't set LEAN_CC unless necessary + detect src dirs
closes leanprover/lake#93
2022-07-05 15:41:33 -04:00
tydeu
9e87958312 fix: linking libraries on Unix 2022-07-05 03:19:38 -04:00
tydeu
b6dc189f0a feat: augment server env + add dynlib search path
see leanprover/lake#93, closes leanprover/lake#91
2022-07-05 02:45:45 -04:00
tydeu
0875473b13 fix: parameterize CustomData by package and target name 2022-07-04 20:27:10 -04:00
tydeu
7049a8da5f refactor: DynamicType -> FamilyDef
Uses more principled terminology (i.e., its really an open type family)
2022-07-04 17:21:36 -04:00
tydeu
66e807146b chore: bump Lean version 2022-07-04 17:18:44 -04:00
tydeu
bee7e5d323 chore: start next Lake version 2022-07-04 15:39:23 -04:00
Leonardo de Moura
a6d6ae01a0 chore: String.getOp has been removed 2022-07-02 19:39:20 -04:00
tydeu
4f8c51f102 test: use -fPIC in ffi example 2022-07-01 20:25:02 -04:00
tydeu
83b9404d02 chore: don't use ../$LAKE idiom 2022-07-01 20:13:53 -04:00
tydeu
5eb591092d release: 3.2.0 2022-07-01 19:03:46 -04:00
tydeu
c7075f3f99 refactor: remove dead package DSL code 2022-07-01 18:45:50 -04:00
tydeu
2355ce06e7 chore: bump Lean version 2022-07-01 17:47:47 -04:00
tydeu
f0c9b74540 doc: update README 2022-07-01 17:30:38 -04:00
tydeu
906bc3c9c2 refactor: simplify custom target API (for now) 2022-07-01 16:26:35 -04:00
tydeu
8c46d7439a chore: remove some deprecated features + deprecate extraDepTarget 2022-07-01 15:35:45 -04:00
tydeu
b9beeff3ad chore: fix wording 2022-07-01 14:45:44 -04:00
tydeu
a81994871a feat: add build types (e.g., debug, release) 2022-07-01 14:45:19 -04:00
tydeu
2e43c1b6cf fix: keyName regression caused by refactor 2022-07-01 11:18:59 -04:00
tydeu
2f9eefd35a feat: inductive BuildKey + proper custom targets 2022-07-01 04:52:50 -04:00
tydeu
989b5666c9 refactor: remove unnecesssary build key subtypes 2022-07-01 02:54:08 -04:00
tydeu
72f555dd5b fix: properly trace module imports 2022-07-01 02:45:24 -04:00
tydeu
48d595b722 feat: preliminary custom package facets 2022-07-01 00:11:53 -04:00
tydeu
2ccd41ac82 feat: preliminary custom targets 2022-07-01 00:11:44 -04:00
tydeu
24fd2e37e1 chore: update Lean version + adapt to TSyntax 2022-06-30 19:24:18 -04:00
tydeu
74f3e963ff feat: use nativeFacets in exe's recBuild 2022-06-30 01:30:14 -04:00
tydeu
6035ed56ea fix: make root module "private" to the package 2022-06-30 01:26:01 -04:00
tydeu
5dd9042a2c fix: dummy git identity in test to make runner happy 2022-06-29 22:56:19 -04:00
tydeu
e33b5a2095 fix: properly update git packages specified by branch
closes leanprover/lake#84
2022-06-29 22:31:25 -04:00
tydeu
7955d0f73c refactor: typify git repos + log stdout/stderr on git failures
c.f. leanprover/lake#67
2022-06-29 21:58:11 -04:00
tydeu
c6f7a0d654 fix: build o files again to enable incremental rebuilds
This reverts commit 182a5787aabd8924823f2232a518911c81b2b2cd.
2022-06-29 18:05:53 -04:00
tydeu
49384a69bf fix: precompile imports of precompiled imports 2022-06-29 17:06:24 -04:00
tydeu
17a36f89aa fix: use Lake install's olean files over LEAN_PATH 2022-06-29 12:56:49 -04:00
tydeu
7ea0ea3393 fix: use library, not package, for lean root dir 2022-06-29 04:05:35 -04:00
tydeu
f62b017654 feat: user-specified native module facets for libraries 2022-06-29 03:36:05 -04:00
tydeu
85f6d1a402 feat: preliminary custom module facets 2022-06-28 23:39:47 -04:00
tydeu
4d118062b8 chore: add note highlighting perf decision 2022-06-28 14:02:07 -04:00
Mac
a2e39659f9 perf: do not build object files of imports when linking executable 2022-06-28 13:57:23 -04:00
tydeu
5f1eca5954 refactor: minor cleanup 2022-06-28 13:35:20 -04:00
tydeu
a4174a560b refactor: build code cleanup / reorg 2022-06-28 01:01:13 -04:00
tydeu
0e99494611 refactor: move lib/exe targets into the index 2022-06-27 02:07:45 -04:00
tydeu
62815168c6 feat: library-level module configuration 2022-06-26 20:35:23 -04:00
tydeu
c0bc0344b0 refactor: add LeanLib/LeanExe/ExternLib + reorg & cleanup 2022-06-26 18:26:12 -04:00
Mac
a8d1ff5fdc fix: properly link libraries on MacOS 2022-06-25 21:46:01 -04:00
tydeu
6812bae11a feat: link libraries in a path and platform independent way 2022-06-25 19:22:41 -04:00
tydeu
c4580839b5 test: "fix" library loading issues 2022-06-25 17:07:52 -04:00
tydeu
3200b43371 feat: include external libraries in precompilation 2022-06-25 00:35:29 -04:00
tydeu
45ff2dbc9d feat: add isLeanOnly package config
closes leanprover/lake#74
2022-06-24 18:35:14 -04:00
tydeu
961a328bfd fix: report precompiled dynlibs to server
a feature of leanprover/lake#47 I had hetherto missed
2022-06-24 17:04:42 -04:00
tydeu
4f739572c9 refactor: use IndexT at Index.lean 2022-06-24 15:05:41 -04:00
tydeu
241665dc27 refactor: move recurse arg into the monad stack 2022-06-23 23:42:12 -04:00
tydeu
0655233dd2 fix: precompile mods if they want not if their importer wants
closes leanprover/lake#83
2022-06-23 22:45:11 -04:00
tydeu
36fe59f687 test: expand precompile example to test leanprover/lake#83 2022-06-23 22:06:15 -04:00
tydeu
d842158172 refactor: reorg build code into smaller, focused files 2022-06-23 21:27:57 -04:00
tydeu
d3c373478e refactor: generalize module facet build code to any target 2022-06-23 13:19:39 -04:00
tydeu
f7451e025c feat: basic precompiled modules + builtin module facets
closes leanprover/lake#47
2022-06-22 13:20:15 -04:00
tydeu
aa4b82c53f chore: update Lean version 2022-06-17 04:39:47 -04:00
Sebastian Ullrich
dad47195da chore: adapt to where syntax change 2022-06-17 04:39:47 -04:00
Mac
7447cb444c ci: skip duplicate/unnecessary jobs 2022-06-16 18:08:36 -04:00
tydeu
f5126bc82a chore: remove lean-toolchain from version agnostic tests 2022-06-16 17:33:00 -04:00
tydeu
4ffe900d93 chore: update Lean version 2022-06-16 17:33:00 -04:00
Leonardo de Moura
8d854900fd chore: replace constant with opaque 2022-06-16 17:33:00 -04:00
Leonardo de Moura
4b7188e0ce chore: opaque is now a command keyword 2022-06-16 17:33:00 -04:00
tydeu
61926bbb32 chore: fix test 2022-06-16 02:24:46 -04:00
tydeu
eb7979b332 test: add test for leanprover/lake#75 2022-06-16 02:12:40 -04:00
tydeu
02ee011a0e refactor: simplify module target code + related cleanup
closes leanprover/lake#75
2022-06-16 02:04:31 -04:00
tydeu
8dc3133244 chore: use bash shebang in test scripts 2022-06-14 18:56:20 -04:00
tydeu
38fc7192ed chore: fix new shell scripts' premissions 2022-06-14 18:39:04 -04:00
tydeu
8faafb7ef6 test: reorg + regression tests 2022-06-14 18:33:01 -04:00
tydeu
4ff44fb050 fix: don't require know expected type for __dir__/__args__ 2022-06-14 16:59:13 -04:00
tydeu
854b154a5f fix: lake serve fallback regression
closes leanprover/lake#76
2022-06-14 15:54:07 -04:00
tydeu
1996d6710b chore: update Lean version 2022-06-14 13:07:42 -04:00
tydeu
7bbe6cfce8 feat: different package templates 2022-06-13 20:01:43 -04:00
tydeu
7cd0107ae1 chore: start next Lake version 2022-06-13 13:03:32 -04:00
tydeu
8646aa142d release: 3.1.1 2022-06-10 19:41:38 -04:00
tydeu
22ecda20c7 feat: rev opt in git dep + fix path opt in require 2022-06-10 19:28:52 -04:00
tydeu
2f7825e06b chore: start next Lake version 2022-06-10 19:20:32 -04:00
tydeu
bf5c89352d release: 3.1.0 2022-06-10 16:51:58 -04:00
tydeu
7ea84c5961 doc: update defaultFacet description 2022-06-10 16:13:55 -04:00
tydeu
05b4a8fc76 chore: silence some "unused variable" warnings 2022-06-10 15:44:08 -04:00
tydeu
e6e2c2ab72 test: make git example clone local repo 2022-06-10 15:25:34 -04:00
tydeu
144fbaf642 doc: update w/ extern_lib + some cleanup 2022-06-10 15:16:49 -04:00
tydeu
c77d6680a7 feat: allow @[defaultTarget] extern_lib 2022-06-10 14:57:46 -04:00
tydeu
1523e2d729 feat: extend DSL syntax and improve docs 2022-06-10 14:08:40 -04:00
tydeu
66797c4232 chore: bump Lean version 2022-06-10 13:54:52 -04:00
tydeu
e5782adeff feat: replace moreLibTargets w/ new extern_lib syntax 2022-06-10 12:08:58 -04:00
tydeu
8428ef7cd7 chore: improve imports lean-only build condition 2022-06-09 21:08:06 -04:00
tydeu
6f38ebebe9 doc: fix heading 2022-06-09 20:57:20 -04:00
tydeu
1f017deaa0 feat: trim log messages+ simplify MonadLog 2022-06-09 20:53:19 -04:00
tydeu
049259b47f fix: delete duplicate improperly case Ffi.lean 2022-06-09 20:29:44 -04:00
tydeu
5fdf97db20 feat: none package facet to avoid warnings in scripts example 2022-06-09 19:12:29 -04:00
tydeu
964eb5ef10 doc: update with new features + other cleanup 2022-06-09 18:58:43 -04:00
tydeu
108d9852ca chore: deprecate package facets 2022-06-09 16:38:07 -04:00
tydeu
d28cb121b5 feat: packages names don't eat up an identifier 2022-06-09 14:13:54 -04:00
tydeu
9dadf7e0b1 feat: attr to mark targets as package defaults 2022-06-09 12:52:54 -04:00
tydeu
cb6db07bb9 chore: warnings on deprecated features 2022-06-08 18:21:15 -04:00
tydeu
1be19f0ebd fix: another casing error in targets test 2022-06-08 17:53:40 -04:00
tydeu
318b12c710 fix: casing in targets test 2022-06-08 17:42:01 -04:00
tydeu
5ea07ae20e refactor: preserve case in exe root default 2022-06-08 17:37:05 -04:00
tydeu
427ad67d79 fix: include submodules at hasModule + test 2022-06-08 17:34:57 -04:00
tydeu
9c20cad9d8 feat: syntax for defining extra lib & exe targets 2022-06-08 17:06:03 -04:00
tydeu
76383dfccc fix: properly catch CLI errors 2022-06-07 22:38:16 -04:00
tydeu
18b6bf3cf8 fix: exe link args & targets test 2022-06-07 21:27:41 -04:00
tydeu
18eef56322 feat: multi lib & exe targets w/ updated build CLI syntax 2022-06-07 20:48:41 -04:00
tydeu
b6bce412a9 refactor: split lib and exe config from package 2022-06-07 16:48:55 -04:00
tydeu
431cdbb6b7 refactor: MainM code cleanup 2022-06-03 12:57:06 -04:00
tydeu
4bb5b407be refactor: split up DSL.Commands 2022-06-03 11:15:49 -04:00
tydeu
a815d29630 feat: __dir__/`__args__ syntax for config settings 2022-06-03 10:58:42 -04:00
tydeu
1c512bdf20 refactor: merge 'MonadLog and LogMethods` 2022-06-02 19:43:07 -04:00
tydeu
cf5fe7e478 refactor: some CLI code cleanup 2022-06-02 18:56:17 -04:00
tydeu
81ea5049af feat: caption process stdout and stderr
closes leanprover/lake#54
2022-06-01 18:09:39 -04:00
tydeu
c19417b86a feat: new require syntax for package deps 2022-06-01 16:26:39 -04:00
tydeu
94c48d2d29 refactor: cleanup runFrontend 2022-05-25 16:52:41 -04:00
Gabriel Ebner
b50f80c393 perf: cache imported environment 2022-05-25 13:13:38 -04:00
tydeu
55a2395db5 feat: retool configure into update
closes leanprover/lake#69
2022-05-24 13:57:30 -04:00
tydeu
85e3385aaa feat: only update deps in configure + don't ignore manifest.json
closes leanprover/lake#59, leanprover/lake#63
2022-05-23 20:38:54 -04:00
tydeu
c1b4074d54 fix: only write manifest if a package was resolved 2022-05-23 20:28:36 -04:00
tydeu
e8d59a7a6e feat: save resolved packages in a manifest
closes leanprover/lake#31
2022-05-23 19:47:29 -04:00
tydeu
10c444e5ef fix: include moreLeanArgs in module trace
closes leanprover/lake#50
2022-05-19 14:28:00 -04:00
tydeu
e24d6f1181 fix: include Lean version in binary trace
closes leanprover/lake#62
2022-05-19 11:34:01 -04:00
tydeu
9f333147f5 chore: start next Lake version 2022-05-16 11:28:12 -04:00
tydeu
7a499ee09b release: 3.0.1 2022-05-16 11:18:32 -04:00
tydeu
c03b388d6f chore: bump Lean version 2022-05-16 11:12:49 -04:00
Gabriel Ebner
a28c1da704 fix: do not call git checkout unless necessary
See leanprover/lake#63.
2022-05-15 16:13:14 -04:00
Gabriel Ebner
be570305fc perf: do not resolve full git object names 2022-05-15 16:13:14 -04:00
Gabriel Ebner
712b22b46f perf: do not import Lean.Elab.Frontend from Lake 2022-05-15 15:56:50 -04:00
tydeu
0fe9930d67 chore: update Lean version 2022-03-21 09:16:12 -04:00
Leonardo de Moura
2a4684a9ae chore: String.Pos is opaque now
See https://github.com/leanprover/lean4/issues/410

Remark: I did not try to fix the places where the code assumes all
characters have size 1. I marked them with `TODO`s
2022-03-21 09:14:54 -04:00
Sebastian Ullrich
bdd5185a7f fix: serve + print-paths without lakefile 2022-03-21 08:51:59 -04:00
Sebastian Ullrich
65d00098c7 chore: fix List.get use (leanprover/lake#56) 2022-02-16 13:21:33 -05:00
Gabriel Ebner
926a253680 fix: serve: fall back to lean --server on error 2022-02-04 17:30:47 -05:00
Leonardo de Moura
8c40a31573 chore: auto pure was removed 2022-02-03 21:32:27 -05:00
tydeu
0869780376 chore: start next Lake version 2022-02-03 01:24:28 -05:00
tydeu
17ac0d7f94 release: 3.0.0 2022-01-31 06:51:57 -05:00
tydeu
a9793b0a50 feat: add root package to workspace + and use it 2022-01-31 02:24:11 -05:00
tydeu
1c4b5ff3ac test: add package dependency diamond in deps example 2022-01-31 00:52:57 -05:00
tydeu
985bdcb4d0 fix: don't duplicate dep link targets in diamonds
closes  leanprover/lake#43
2022-01-31 00:52:37 -05:00
tydeu
30e3f10c6c chore: ilean code cleanup 2022-01-31 00:04:17 -05:00
Sebastian Ullrich
e6894c058b feat: create .ilean files 2022-01-30 23:46:08 -05:00
tydeu
bffcfde602 refactor: ModuleInfo -> Module 2022-01-30 23:16:08 -05:00
tydeu
705962847d fix: glob bugs + cleanup
closes leanprover/lake#42
2022-01-30 22:49:05 -05:00
Sebastian Ullrich
df1c1cde12 refactor: make LeanPaths usage forward-compatible (leanprover/lake#48) 2022-01-22 20:55:16 -05:00
tydeu
6d7fc7216c fix: get pkg for dep name not mod at buildDepOleans
Bug & fix first reported on Zulip: https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Lake.20mathport.20panic
2022-01-18 19:56:23 -05:00
tydeu
2be2466f78 chore: bump Lean version 2022-01-17 15:00:01 -05:00
Leonardo de Moura
4ac34f4cd5 chore: rename PointedType => NonemptyType 2022-01-15 11:42:09 -08:00
tydeu
f3d8fcc85d test: don't check for lean-toolchain generation in init example 2022-01-15 11:35:40 -05:00
Leonardo de Moura
e880dd52a4 chore: PointedType 2022-01-14 20:41:47 -08:00
tydeu
752bc24f78 feat: add args to binary & .o file traces + some cleanup
closes leanprover/lake#41
2021-12-27 12:07:15 -05:00
tydeu
2680e1c66f refactor: generalize computeHash + cleanup 2021-12-27 12:00:09 -05:00
tydeu
5029f30b27 refactor: tweak collectArgs in Cli 2021-12-27 11:00:18 -05:00
tydeu
5102d21cc5 feat: expand script CLI into its own script command 2021-12-24 03:26:34 -05:00
tydeu
2b0989ea28 refactor:: simplify/improve CLI API 2021-12-23 23:43:01 -05:00
tydeu
c9128d1ce6 refactor:: separate build and scheduler monads 2021-12-23 16:25:15 -05:00
tydeu
d4e7e33652 feat: split Lake context from BuildContext and also use it in scripts 2021-12-22 00:39:36 -05:00
tydeu
1b96c466ca refactor: use new version info from Lean + cleanup 2021-12-19 21:59:17 -05:00
tydeu
9ac989f0c9 chore: bump Lean version 2021-12-19 21:47:46 -05:00
tydeu
adcf2df9b5 refactor: async API tweaks 2021-12-19 21:45:42 -05:00
tydeu
8fb9dd8478 fix: consider globbed files local
easiest way to fix mathport builds (for now)
2021-12-16 21:56:10 -05:00
tydeu
34bf090300 fix: build dep's extraDepTarget not root's for each dep 2021-12-16 01:03:21 -05:00
tydeu
d781c3411a feat: add getLeanSysroot and getLeanLibDir 2021-12-15 20:08:14 -05:00
tydeu
f9e789af45 refactir: revamp install path API 2021-12-15 13:44:28 -05:00
tydeu
a23c5feec4 chore: bump Lean version 2021-12-15 11:14:02 -05:00
tydeu
e37cde0def test: reorganize ffi example 2021-12-14 16:45:43 -05:00
tydeu
7199eea687 refactor: cleanup/improve Target utils 2021-12-14 14:12:43 -05:00
tydeu
50a84fcd55 test: add print-paths of dep modules check 2021-12-13 20:27:35 -05:00
tydeu
ac47b4fb01 refactor: remove Package from BuildContext 2021-12-13 19:53:45 -05:00
tydeu
8f4b203b2f refactor: include package in module info
fixes various issues with `lake print-paths` builds
2021-12-13 19:08:06 -05:00
tydeu
e054596cfa chore: bump Lean version 2021-12-13 10:59:53 -05:00
Leonardo de Moura
99bd215dcb chore: where struct instance parser
The parser was modified to fix issue https://github.com/leanprover/lean4/issues/753

cc @tydeu
2021-12-12 08:26:20 -08:00
tydeu
56bae17924 feat: also set LEAN_SYSROOT and LEAN_SRC_PATH with env 2021-12-11 18:19:30 -05:00
tydeu
8b66dbf285 refactor: use error in Load.lean 2021-12-11 17:53:31 -05:00
tydeu
197b8e5c1d feat: better error messages for missing CLI args 2021-12-11 16:47:28 -05:00
tydeu
f0ad325e09 feat: fallback to ar when llvm-ar is not bundled with Lean 2021-12-10 18:30:34 -05:00
Anders Christiansen Sørby
bec311bf48 chore: fix Nix setup (leanprover/lake#38) 2021-12-10 17:59:56 -05:00
Leonardo de Moura
0555e29808 chore: do cannot be used in pure code anymore
cc @tydeu
2021-12-10 13:18:27 -08:00
tydeu
1210589771 feat: build package and deps simultanously 2021-12-05 18:45:58 -05:00
tydeu
5edbd6cf59 refactor: use workspace olean dirs in module targets and print-paths 2021-12-04 16:24:30 -05:00
tydeu
50fa9a0b53 feat: resolve deps immediately and store them in workspace 2021-12-04 16:24:19 -05:00
tydeu
8e728b1159 refactor: split Package and Workspace 2021-12-04 12:58:00 -05:00
tydeu
052d6623f0 refactor: move misc utilities to Util.Extra 2021-12-04 11:27:38 -05:00
tydeu
b996117482 doc: mention options for a package's Git revision in README
closes leanprover/lake#37
2021-12-02 21:37:10 -05:00
tydeu
fcc3e3d93e chore: cleanup 2021-12-02 21:29:16 -05:00
tydeu
a7a980c12d refactor: remove unused branch parameter from Source.git 2021-12-02 21:25:53 -05:00
tydeu
1284616296 refactor: revamp Async API 2021-11-30 11:56:35 -05:00
tydeu
a1368df5c9 chore: fix docstring formatting 2021-11-26 23:47:36 -05:00
tydeu
4b062543ec refactor: simplify trace checking somewhat 2021-11-26 21:53:18 -05:00
tydeu
c830953ded feat: use Lean bundled ar by default for static libs
closes leanprover/lake#35
2021-11-26 18:44:00 -05:00
tydeu
aa524e977c chore: bump Lean version 2021-11-26 18:20:07 -05:00
ammkrn
a727a3de5c fix: syntax/mathlib name in dependencies example
Mathlib4 changed the package name to just `mathlib`. Trying to build
with a dependency name `mathlib4 will now cause an error.
2021-11-25 19:45:45 -05:00
Sebastian Ullrich
91620481a5 fix: adapt to Lean change 2021-11-25 10:01:20 -05:00
tydeu
ca6c5b8c5c feat: add lake env 2021-11-25 06:49:22 -05:00
tydeu
2092850b02 refactor: lake server -> lake serve 2021-11-25 05:29:47 -05:00
tydeu
63bd325b3b refactor: split build CLI into separate file 2021-11-25 04:58:33 -05:00
tydeu
ec8b351445 refactor: generalize some IO-related code
* add `def OptionIO := EIO PUnit`
* add `OptionIOTask` for `OptionIO`
* rename `BuildCoreM` -> `BuildIO`
* rename `Util.LogT` ->  `Util.Log`
* generalize `error` to `MonadError`
* generalize` Cli.build`
2021-11-25 03:22:11 -05:00
tydeu
bb2c720411 doc: fix mathlib link in README 2021-11-21 16:55:29 -05:00
tydeu
8a1e413d5a doc: update README
* Add dependency example (closes leanprover/lake#27)
* Move build instructions to bottom (closes leanprover/lake#28)
* Remove mention of  the `name` option (closes leanprover/lake#29)
* Correct `OpaqueTarget` guidance (closes leanprover/lake#30)
2021-11-20 20:26:23 -05:00
tydeu
0422c0d019 ci: trigger on all branches 2021-11-11 18:51:24 -05:00
tydeu
2be3a23b46 feat: use IO.appPath for exe in LakeInstall 2021-11-11 02:41:23 -05:00
tydeu
40b6ca82b3 fix: include libleanshared in Lean trace
closes leanprover/lake#26
2021-11-11 02:23:54 -05:00
tydeu
36b0d7b60c feat: store current Package in BuildM 2021-11-11 00:10:52 -05:00
tydeu
8d96c2cbe8 refactor: move Workspace/Script code to separate files 2021-11-10 18:46:31 -05:00
tydeu
94d899ad95 refactor: use supportInterpreter in lakefile 2021-11-09 23:43:55 -05:00
tydeu
4c9c0cae30 refactor: use liftExcept in Task.lean 2021-11-09 23:43:23 -05:00
tydeu
445f0db973 chore: bump Lean version 2021-11-09 23:25:36 -05:00
tydeu
331bf0f7f2 refactor: reorganize code folder structure 2021-11-09 22:55:21 -05:00
tydeu
ce7779890b chore: minor Task async code cleanup 2021-11-09 16:49:14 -05:00
tydeu
7bc00f9b29 refactor: generalize IOTask to EIOTask 2021-11-05 19:16:30 -04:00
tydeu
f48d9fccd9 refactor: replace RealM with BaseIO 2021-11-05 17:55:27 -04:00
tydeu
8dfd7fccfc feat: use lean --githash for Lean version checking 2021-11-05 16:22:11 -04:00
tydeu
eb73594ec0 chore: update Lean version 2021-11-05 15:35:46 -04:00
tydeu
8babf3fc70 doc: nclude --help option info in scripts docs 2021-11-05 15:22:57 -04:00
tydeu
57c7e42752 fix: make buildRec target wait for deps 2021-11-05 14:12:58 -04:00
tydeu
ffcf715f30 refactor: allow -h between command and args 2021-11-05 13:53:17 -04:00
tydeu
50dd829d90 feat: add docs for scripts + CLI code cleanup 2021-11-02 13:19:41 -04:00
tydeu
0b0afef09a refactor: split EIO UInt32 from Cli into its own MainM file 2021-11-02 11:23:04 -04:00
tydeu
763ac9a2e8 refactor: pipe proc output to logger 2021-11-02 07:20:29 -04:00
tydeu
182409e0f4 refactor: use LogT at Resolve.lean 2021-11-02 05:35:53 -04:00
tydeu
8a20cafebf chore: fix some overlooked docs 2021-10-29 19:04:21 -04:00
tydeu
ae43e5b2fb feat: add package shared library build / facet 2021-10-29 19:00:02 -04:00
tydeu
d518e3df5b refactor: properly manage errors in the build monad 2021-10-28 13:36:07 -04:00
tydeu
781672e935 refactor: generalize Await signature a little 2021-10-27 12:19:02 -04:00
tydeu
b0991cf96b refactor: cleanup Task code some 2021-10-24 22:04:08 -04:00
tydeu
29f6c0fb5a refactor: split logging from BuildM into its own monad 2021-10-24 17:46:28 -04:00
tydeu
333a86ef5f fix: typing mistakes with CliMethodsRef + cleanup 2021-10-24 17:34:40 -04:00
tydeu
e006f8534d feat: add supportInterpreter config setting
also don't use `--export-all` on Windows anymore
2021-10-23 16:16:09 -04:00
tydeu
168ec3d178 perf: cache lean exe trace in BuildM 2021-10-23 14:36:37 -04:00
tydeu
20788e8237 refactor: separate module olean and c traces 2021-10-23 14:02:31 -04:00
tydeu
74276dd024 refactor: update ofByteArray with new primitives
also rename `getFileHash` to `computeFileHash`
2021-10-23 11:34:01 -04:00
tydeu
521311292d chore: bump Lean version 2021-10-23 11:04:51 -04:00
tydeu
738425b0b1 ci: mssing $ 2021-10-20 16:46:03 -04:00
tydeu
29975edb0e ci: use matrix OS for build artifact name 2021-10-20 16:44:54 -04:00
tydeu
7cbde2c852 ci: switch back to homebrew on macOS 2021-10-19 11:36:36 -04:00
tydeu
c6f6eec4c5 fix; leanmake build 2021-10-19 11:30:24 -04:00
tydeu
aa3f453ebf refactor: cleanup trace code some 2021-10-18 19:38:32 -04:00
tydeu
ffd5bc0f69 refactor: narrow Lean imports 2021-10-18 18:01:31 -04:00
tydeu
bfedab0f9b feat: build C files in print-paths if facet is not oleans 2021-10-18 15:21:43 -04:00
tydeu
4d66b6e4e2 fix: ci: don't use hombrew for MacOS (for now)
Reason: it is missing `lake` (see https://github.com/Homebrew/homebrew-core/pull/87486)
2021-10-18 13:40:50 -04:00
tydeu
44cc860c82 fix: ci: use elan's lake to build (for now)
Reason: `leanmake` build is broken due to bad dep inference
2021-10-18 13:27:58 -04:00
tydeu
53ad51e984 fix: correct the lake lib location of a co-located lake and lean 2021-10-18 12:39:30 -04:00
tydeu
e9443705d5 feat: include hash of lean in module traces
closes leanprover/lake#23
2021-10-18 12:11:56 -04:00
tydeu
d9f53dfec9 refactor: replace leanpkg.toml with a lakefile.lean + build reorg 2021-10-17 13:52:01 -04:00
tydeu
b558536129 feat: add basic lake server CLI 2021-10-13 15:31:49 -04:00
tydeu
4eec17c876 chore: use return at examples/scripts 2021-10-13 14:47:57 -04:00
tydeu
1074aaa5fa chore: fix hasModule error message at parseTargetBaseSpec 2021-10-10 12:52:49 -04:00
tydeu
b8b3f01c96 feat: add option to specify the lean used by Lake
also:
* support `=` for long CLI options
* cleanup some typos in `InstallPath`
2021-10-10 12:37:00 -04:00
tydeu
15a2981804 feat: new build CLI 2021-10-09 19:24:28 -04:00
tydeu
88af2ca4b7 refactor: reorg build package code 2021-10-09 18:48:53 -04:00
tydeu
d494626de6 chore: use Json.compress at print-paths
Reason: server expects JSON to be a single line
2021-10-09 12:04:08 -04:00
tydeu
ae01b5d586 chore: use c++ not cc at examples/fffi 2021-10-09 11:26:21 -04:00
tydeu
8635ce279b refactor: use LeanPaths in print-paths 2021-10-08 21:00:42 -04:00
tydeu
b2822ffab1 chore: bump Lean version 2021-10-08 20:58:53 -04:00
tydeu
427cb0fc7c feat: add inputFileTarget util 2021-10-08 15:26:07 -04:00
tydeu
85efdb159a test: expand examples/ffi to use getLeanIncludeDir 2021-10-08 15:20:23 -04:00
tydeu
8a06d4f529 feat: introduce Workspace which is shared across a pkg and its deps 2021-10-08 14:09:05 -04:00
tydeu
7a3aadd005 feat: add utils for constructing file targets with deps 2021-10-08 12:58:10 -04:00
tydeu
b3b7aa02d1 fix: wait for deps to build on a bare print-paths 2021-10-07 18:30:52 -04:00
tydeu
2e5c7c02f1 refactor: CLI code tweaks 2021-10-07 14:59:00 -04:00
tydeu
1d20cbd3d6 refacttor: check LEAN_SYSROOT rather than LEAN_HOME for Lean 2021-10-07 14:04:18 -04:00
tydeu
9700208501 feat: have print-paths exit silently with code 2 if config missing 2021-10-07 12:40:26 -04:00
tydeu
6cfbd90426 refactor: always pass -O3 and -DNDEBUG when building Lean o files
also add `more` prefix to `leanArgs`/`leancArgs`/`linkArgs`

closes leanprover/lake#19
2021-10-06 21:07:56 -04:00
tydeu
e171925991 chore: update Lean version
fixes leanprover/lake#21
2021-10-06 20:43:36 -04:00
tydeu
0e7a2bae8e refactor: clean up CLI code some 2021-10-06 20:06:03 -04:00
tydeu
429386c4c0 refactor: update print-paths JSON format to match server 2021-10-06 17:52:22 -04:00
tydeu
0f2d6c7fdd feat: use detected Lean install to build packages 2021-10-06 17:38:57 -04:00
tydeu
c32cd22504 feat: store detected Lean/Lake install in BuildContext
includes new `getLeanIncludeDir` for `BuildM` (leanprover/lake#18)
2021-10-06 17:01:52 -04:00
tydeu
0196cbe6a3 refactor: move build execution into CLI 2021-10-06 16:27:49 -04:00
tydeu
93cc196b10 chore: minor code cleanup 2021-10-06 15:22:19 -04:00
tydeu
3bcd18a1c6 refactor: generalize Lean/Lake installation detection 2021-10-05 20:00:30 -04:00
tydeu
4c0734b5f1 feat: use hash traces for o file, static lib, and bin targets
Also rename `.hash` file to `.trace` and add a `package-bootstrap` make job
2021-10-04 19:08:22 -04:00
tydeu
ae144112be refactor: generalize checkModuleTrace 2021-10-04 18:30:24 -04:00
tydeu
e906f39201 refactor: cleanup Compile.lean 2021-10-04 17:51:47 -04:00
tydeu
a9b87adbeb feat: print-paths as a JSON object 2021-10-04 12:50:57 -04:00
tydeu
b2acab81d4 refactor: output print-paths build info to stderr 2021-10-04 12:27:14 -04:00
tydeu
3ab3b69293 chore: minor ccide leanup 2021-10-04 12:25:40 -04:00
tydeu
5b0e264f8c feat: promote scripts from PackageConifg to top level commands 2021-10-03 21:38:22 -04:00
tydeu
583b534e6c refactor: simplify / reorder LeanConfig 2021-10-03 21:20:52 -04:00
tydeu
0ede8f2c4c chore; minor doc cleanup 2021-10-03 17:09:30 -04:00
tydeu
8852c5e236 feat: use an attribute to identify packages in lakefile 2021-10-03 14:13:49 -04:00
tydeu
50f70712a8 feat: add name to package DSL signature 2021-10-03 13:31:09 -04:00
tydeu
3b28d24319 refactor: make package name a Name 2021-10-03 12:42:24 -04:00
tydeu
d533606a86 chore: update examples/git URL 2021-10-03 00:01:56 -04:00
tydeu
557adf9ffc refactor: default binRoot to Main and expand init code 2021-10-02 23:41:55 -04:00
tydeu
0f5dd30880 refactor: use an Array for package depedencies 2021-10-02 21:48:23 -04:00
tydeu
7197f60d9c fix: do not resolve the same dependency multiple times 2021-10-02 21:33:08 -04:00
tydeu
3d76e48181 fix: do not build deep deps multiple times 2021-10-02 16:11:53 -04:00
tydeu
cfc8a2538d refactor: generalize buildTop and failOnImportCycle
Reason: will be useful for upcoming dependency build fix
2021-10-02 14:21:45 -04:00
tydeu
83ccf8a15d test: extend examples/deps to include a deep dependency 2021-10-01 21:23:31 -04:00
tydeu
f187761c2e chore: bump Lean version
Reason: fixes `leanc` on Linux
2021-10-01 21:20:45 -04:00
tydeu
a8d5348f4f chore: bump Lean version
Reason: 816dc1895f may be of use to Lake
2021-09-30 20:56:34 -04:00
tydeu
fe87b064a2 feat: for most CLI commands, error when given more args than expected 2021-09-30 20:37:18 -04:00
tydeu
a21274c302 refactor: make return code part of the CLI + have scripts return code 2021-09-30 20:36:21 -04:00
tydeu
526e6e223e refactor: throw error on build failure
Reason:  `lake` will now exit with code 1 rather than 0 on build failure
2021-09-30 19:24:37 -04:00
tydeu
8cd7efb2d8 chore: post PR cleanup 2021-09-30 16:25:58 -04:00
Anders Christiansen Sørby
cadc812608 feat: add a Nix flakes build setup 2021-09-30 16:13:58 -04:00
tydeu
2b8f0f768c chore: use lake clean for examples/hello 2021-09-30 15:56:46 -04:00
tydeu
628e5e2818 fix: only call removeDirAll if path exists 2021-09-30 15:50:22 -04:00
tydeu
3abf53d196 chore: just build bin in examples/bootstrap
Reason: `bin` now imports the entire `Lake` lib so this is unecessary
2021-09-30 02:20:41 -04:00
tydeu
3b78652547 refactor: prefer build rather than fetch terminology 2021-09-27 02:50:45 -04:00
tydeu
032be7ee2e refactor: generalize buildRBTop 2021-09-27 02:40:24 -04:00
tydeu
a093a38459 refactor: rename package.lean to lakefile.lean 2021-09-26 18:52:31 -04:00
tydeu
6a9997c7ad chore: -O3 not -03 2021-09-25 23:59:13 -04:00
tydeu
ff1e63c719 refactor: default leancArgs to -03, -DNDEBUG (like leanpkg) 2021-09-25 23:57:31 -04:00
tydeu
3f534e1155 refactor: use DSL in examples 2021-09-25 23:53:34 -04:00
tydeu
2e5b4d2221 feat: add simple DSL for package configurations 2021-09-25 23:40:31 -04:00
tydeu
63ad2d7765 chore: bump to v3.0.0-pre 2021-09-25 22:59:15 -04:00
tydeu
a9c0210ef3 refactor: use import Lake in package configurations 2021-09-25 19:36:00 -04:00
tydeu
efadebd5ef refactor: move main into Lake.Main which is not imported by Lake 2021-09-25 19:18:10 -04:00
tydeu
1d052a1b39 fix: update examples/git commit hash 2021-09-25 18:38:42 -04:00
tydeu
4af8135172 refactor: remove the package version field
Reason: It is unused. See https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/.5BRFC.5D.20name.2Fversion.20package.20fields/near/254114011 for more discussion of topic.
2021-09-25 18:31:33 -04:00
tydeu
ba8067f3bd refactor: don't use globs to determine local modules + cleanup
Reasion: globs should be submodules of the roots
2021-09-24 01:11:29 -04:00
tydeu
0f0ea57ef5 chore: some cleanup and reorg 2021-09-23 23:12:51 -04:00
tydeu
5b37f1c5c5 feat: split moduleRoot into libRoots and libGlobs
Reason: provide finer grain control over library modules
2021-09-23 21:04:29 -04:00
Mario Carneiro
5007ceae69 feat: add module Glob API 2021-09-23 11:33:10 -04:00
tydeu
6d4360a04d release: 2.1.0 2021-09-22 15:43:07 -04:00
tydeu
194247bb32 chore: bump Lean version 2021-09-22 12:19:51 -04:00
Sebastian Ullrich
abd617b9a5 test: use $LAKE everywhere 2021-09-21 12:17:27 -04:00
tydeu
dfa959ba30 test: add clean* targets to Makefile
closes leanprover/lake#13
2021-09-20 18:14:50 -04:00
Sebastian Ullrich
9b80f69e54 chore: add proper shebang to build.sh & port to sh 2021-09-20 12:53:55 -04:00
tydeu
b4150f61c7 chore: cleanup fromLeanFileUnsafe code 2021-09-19 23:41:14 -04:00
tydeu
1432bd91bb chore: fix ffi-dep shell script permissions 2021-09-19 20:09:56 -04:00
tydeu
9bdd0202b7 test: add ffi-dep example and fix ffi example
see leanprover/lake#8
2021-09-19 20:01:55 -04:00
tydeu
1c0c5a84a4 refactor: merge rootDir into srcDir 2021-09-19 19:59:07 -04:00
tydeu
06a6b9a88c feat: add pure Packager variant 2021-09-19 19:58:30 -04:00
tydeu
9f90c9bb66 feat: don't overwite existing files on init + test
closes leanprover/lake#10
2021-09-17 16:26:25 -04:00
tydeu
fdb9915bcc feat: print usage on bare lake
closes  leanprover/lake#9
2021-09-17 14:54:33 -04:00
tydeu
4b7a98bc38 chore: replace removeDirAll with the proper function 2021-09-16 21:48:21 -04:00
tydeu
b158f1fd8b chore: bump Lean version 2021-09-16 21:43:21 -04:00
tydeu
50a23a3aa5 refactor: print last error message on build failure + cleanup 2021-09-16 18:36:07 -04:00
tydeu
6a3d299378 fix: log trace computation errors at FileTarget
resolves leanprover/lake#7
2021-09-16 18:33:38 -04:00
tydeu
8b83d80956 chore: add mising (Active)Target.with* utilities 2021-09-16 17:03:15 -04:00
tydeu
bf4db86bdd feat: search path now first checks IO.appPath for lean 2021-09-16 16:26:06 -04:00
tydeu
b4dcad59fa test: add alternate binRoot example (called main) 2021-09-16 15:13:11 -04:00
tydeu
3c1185dc9c chore: document package configuration + other minor cleanup 2021-09-16 07:49:56 -04:00
tydeu
f39b1b8378 chore: remove unused MonadLiftT Id instance 2021-09-14 11:18:16 -04:00
tydeu
dd120dbc5a feat: use lean-toolchain file to specify Lean version for package 2021-09-13 15:57:33 -04:00
tydeu
276163afd7 chore: bump to v2.1.0-pre 2021-09-13 15:48:26 -04:00
tydeu
c97eac1e82 release: 2.0.1 2021-09-13 14:57:20 -04:00
tydeu
9285fb6f1d chore: update Lean version 2021-09-13 14:52:19 -04:00
tydeu
58eff66799 chore: merge build-*.sh into build.sh + cleanup README 2021-09-13 14:34:56 -04:00
tydeu
ce46960416 ci: continue even if build upload fails 2021-09-13 13:48:02 -04:00
tydeu
8e8ea4da33 ci: add GitHub Actions workflow 2021-09-13 13:34:03 -04:00
tydeu
eca73809e6 chore: bin/Hello -> bin/hello 2021-09-13 13:28:54 -04:00
tydeu
e3ec2b9e39 chore: revert casing change and instead output lower-cased bin 2021-09-13 13:21:35 -04:00
tydeu
4e61320225 chore: bin/lake -> bin/Lake
Reason: casing matters on Linux
2021-09-13 12:55:36 -04:00
tydeu
e441c40a3d chore: fix typo in Makefile 2021-09-13 12:52:37 -04:00
tydeu
60c749ab1d test: tweak & expand test Makefile 2021-09-13 12:22:11 -04:00
tydeu
0188eb84df chore: add .gitattributes file 2021-09-13 11:55:02 -04:00
tydeu
5caa12c0b0 chore: fix shell script permissions 2021-09-13 11:40:05 -04:00
tydeu
69102b1812 feat: add Hash/MTime -> BuildTrace Coe instances 2021-09-13 09:54:36 -04:00
tydeu
8d3e72d742 release: 2.0 2021-09-05 20:17:23 -04:00
tydeu
f1865d4290 test: remove meanigful version information from bootstrap test 2021-09-05 20:15:46 -04:00
tydeu
22ee974ac8 chore: bump Lean version 2021-09-05 20:04:44 -04:00
tydeu
103e8ab61c test: convert examples' main test.sh into a Makefile 2021-09-05 19:54:39 -04:00
tydeu
f92afee9b4 fix: args bug with CLI 2021-09-05 19:47:13 -04:00
tydeu
d6d395619f chore: cleanup solveDeps 2021-09-05 19:03:41 -04:00
tydeu
09af870b71 feat: add config option for separate binary module root 2021-09-05 19:01:09 -04:00
tydeu
8601c0fe78 refactor: purify BuildModule somewhat + associated cleanup 2021-09-05 18:05:45 -04:00
tydeu
6863bb8095 refactor: ModuleTarget -> ActiveModuleTarget 2021-09-05 16:30:28 -04:00
tydeu
4b9a765cfb refactor PackageTarget -> ActivePackageTarget 2021-09-05 16:29:18 -04:00
tydeu
d4ba706198 refactor: purify BuildBin.lean 2021-09-05 15:37:16 -04:00
tydeu
92696d48f6 feat: use olean instead of lean hash for module targets 2021-09-05 01:01:40 -04:00
tydeu
720ecbd568 refactor: more cleanup (primarly Trace.lean) 2021-09-05 00:31:23 -04:00
tydeu
7129433066 fix: typo in foldArrayAsync 2021-09-04 20:41:03 -04:00
tydeu
3e1cdda87e refactor: make PackageConfig take normal targets 2021-09-04 18:53:21 -04:00
tydeu
0a3457e973 refactor: minor cleanup / tweaks 2021-09-04 18:41:20 -04:00
tydeu
dba37698c8 refactor: rename LakeTrace to BuildTrace 2021-09-04 17:49:08 -04:00
tydeu
80416677d8 refactor: compute trace duing build 2021-09-04 17:45:56 -04:00
tydeu
2d3bec2209 feat: add proper CLI 2021-08-22 11:17:18 -04:00
tydeu
1825e095e1 refactore: rename ModuleM 2021-08-22 03:51:44 -04:00
tydeu
332af4c262 refactor: check hash after verifying module artifact exists 2021-08-22 03:40:09 -04:00
tydeu
4ce8716b99 feat: build and print-paths now build only oleans 2021-08-22 03:23:43 -04:00
tydeu
ac1cc9e62c chore: cleanup 2021-08-22 03:06:33 -04:00
tydeu
80a9685164 refactor add ModuleTargetMap abbreviation 2021-08-22 00:16:18 -04:00
tydeu
ce1ee3c36d refactor: move build failed message into runBuild 2021-08-22 00:07:17 -04:00
tydeu
43d1dfe72c refactor: cleanup opaque target interfaces 2021-08-21 23:52:34 -04:00
tydeu
c843f0b112 chore: cleanup 2021-08-21 22:43:27 -04:00
tydeu
64634dbc32 refactor: change target abstraction (again) 2021-08-21 21:05:52 -04:00
tydeu
d12c4241bf fix: use BuildM in PackageConfig 2021-08-21 20:17:48 -04:00
tydeu
56a78f6eeb feat: use deps' extra lib targets when building parent bin 2021-08-20 01:48:10 -04:00
tydeu
8f7e32d09a refactor: add build monad 2021-08-19 23:21:23 -04:00
tydeu
a371e181d5 refactor: more API tweaks 2021-08-19 12:13:29 -04:00
tydeu
8b74108f6e refactor: remove FilesTarget 2021-08-19 12:05:44 -04:00
tydeu
28320f80ee refactor: minor API tweaks 2021-08-19 12:05:28 -04:00
tydeu
0bfebc1975 refactor: reorganize Async.lean 2021-08-18 21:30:41 -04:00
tydeu
f9d6f57725 refactor: split Build into BuildModule and BuildPackage 2021-08-18 14:46:54 -04:00
tydeu
66a6246136 chore: fix typo 2021-08-18 12:48:58 -04:00
tydeu
81a84d21de feat: add command to verify Lean version 2021-08-17 11:24:32 -04:00
tydeu
dd6634544d misc: add shell scripts for timing Lake builds 2021-08-17 10:34:18 -04:00
tydeu
31abd420ad chore: update Lean version
Some examples (ex. `hello`) may now segfault. See https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Problems.20when.20updating.20Lean/near/249599195.
2021-08-17 10:33:15 -04:00
tydeu
d49c64453d refactor: build with leanmake instead of leanpkg 2021-08-16 09:23:51 -04:00
tydeu
f977ee8b34 refactor: improve async abstraction 2021-08-15 20:41:55 -04:00
tydeu
2757e844dd refactor: add trace abstraction 2021-08-15 20:13:17 -04:00
tydeu
c8b558a2d1 refactor: remove 'build' from Target/Trace/Task file names 2021-08-15 19:16:12 -04:00
tydeu
ddf02cb339 refactor: merge build target into lake target 2021-08-15 19:04:28 -04:00
tydeu
23dd052dc9 refactor: remove BuildTask 2021-08-15 17:14:13 -04:00
tydeu
c1f61d6716 feat add config setting for specificying extra lib targets 2021-08-15 16:12:45 -04:00
tydeu
4f75dd99d1 reefactor: improve async API 2021-08-09 05:04:38 -04:00
tydeu
d0fbc93143 refactor: improve Hash traces 2021-08-06 01:58:41 -04:00
tydeu
609ee22971 refactor: LeanTrace/Target -> LakeTrace/Target 2021-08-06 01:17:17 -04:00
tydeu
81d7511792 refactor: post-async Target API touch-ups 2021-08-06 00:44:46 -04:00
tydeu
859b04bf7f refactor: generalize Target/ActiveTarget beyond IO 2021-08-05 00:45:50 -04:00
tydeu
aa1ca9c4b7 feat: improve Target API 2021-08-04 14:07:28 -04:00
tydeu
a541f2054e refactor: IO BuildTarget task / protect pure 2021-08-04 01:31:47 -04:00
tydeu
ba52b36ef8 chore: more code cleanup 2021-08-01 18:46:48 -04:00
tydeu
3643b8e424 refactor: make Task and task a monad 2021-08-01 18:46:33 -04:00
tydeu
6a6afcd7c0 refactor: spawn ActiveBuildTarget from BuildTarget 2021-08-01 16:50:53 -04:00
tydeu
b8e85f40cd refactor: move afterTarget* into ActiveBuildTarget 2021-08-01 15:40:11 -04:00
tydeu
2d78f4db36 feat: add non-activve targets 2021-08-01 15:17:43 -04:00
tydeu
a52d95b575 refactor: ActiveBuildTarget.buildTask -> task 2021-08-01 14:27:11 -04:00
tydeu
1f51241a8e chore: minor code cleanup 2021-08-01 14:08:00 -04:00
tydeu
293c19d24f feat: include Lean version in Lake usage header 2021-07-31 19:29:26 -04:00
tydeu
448cac6804 chore: bump Lean version 2021-07-28 16:30:48 -04:00
tydeu
ce1f2f4964 feat: add lake clean command 2021-07-28 14:01:44 -04:00
tydeu
d8ac18a807 refactor: add buildDir setting and make bin/lib/ir subdirs of it 2021-07-28 12:23:37 -04:00
tydeu
cce0b3cce5 refactor: minor example tweaks 2021-07-28 10:30:36 -04:00
tydeu
f06b1bbb5c test: add bootstrap example 2021-07-28 10:20:42 -04:00
tydeu
38b260d60f feat: setting to specify alt root dir for package 2021-07-28 09:52:08 -04:00
tydeu
1b5b4edec6 fix: throw error if external process fails 2021-07-28 09:43:38 -04:00
tydeu
29e75cedc6 refactor: add lean_packages to initial package .gitignore 2021-07-28 09:19:40 -04:00
tydeu
91d3df58cd test: add git example 2021-07-28 09:10:14 -04:00
tydeu
bc8c39e802 feat: can depend on subdirectories of dependencies 2021-07-28 09:08:39 -04:00
tydeu
4ae14ac849 refactor: rename 'ext' example to 'ffi' 2021-07-27 07:24:45 -04:00
tydeu
1dabd00d4c test: add new/init example/test 2021-07-26 07:48:49 -04:00
tydeu
bea059796f fix: init git repo in package dir
Fixes leanprover/lake#1
2021-07-26 07:46:41 -04:00
tydeu
b730aacbc8 refactor: BuildTagret -> ActiveBuildTarget 2021-07-24 09:23:46 -04:00
tydeu
0dfd07ed9d chore: add ext example to examples test 2021-07-24 09:08:43 -04:00
tydeu
54bdf64d25 test: add simple extension example 2021-07-24 08:40:46 -04:00
tydeu
0d288b9bd3 feat: add MTimeBuildTarget -> LeanTarget function 2021-07-24 08:40:33 -04:00
tydeu
5770529e09 feat: add non-leanc compile o/bin functions 2021-07-24 08:08:36 -04:00
tydeu
c3e602cedf refactor: moreDepsTarget -> buildMoreDepsTarget 2021-07-24 07:37:39 -04:00
tydeu
67341f478d refactor:: move some magic constants into defs 2021-07-24 07:36:58 -04:00
tydeu
53b95fb455 fix: actually use lib name in the file name 2021-07-17 13:28:40 -04:00
tydeu
81cb2f6ca8 refactor: use modToFilePath in srcRoot and oleanRoot 2021-07-17 13:27:33 -04:00
tydeu
e99d7aab95 refactor: default libName to moduleRoot and don't escape it 2021-07-17 13:09:23 -04:00
tydeu
9e5505b6ca feat: add new and run commands 2021-07-17 13:02:39 -04:00
tydeu
93c9543976 feat: add convenience functions for constructing a LeanTrace 2021-07-15 13:04:31 -04:00
tydeu
b14eef6e06 refactor: split out top / lib / bin build from Build.lean 2021-07-15 12:50:54 -04:00
tydeu
3b2c91f396 refactor: functions for building a specified module root 2021-07-15 12:40:23 -04:00
tydeu
f8a31011a6 feat: add more package configuration settings 2021-07-15 12:21:52 -04:00
tydeu
31fa37dbfe refactor: remove Monad Task instance (for now) 2021-07-14 14:53:52 -04:00
tydeu
e040804678 refactor: split task and trace from target into separate files 2021-07-14 13:35:42 -04:00
tydeu
3ef381bb6c refactor: merge Proc into Compile and cleanup Build 2021-07-14 12:46:07 -04:00
tydeu
758021f03a feat: add hash checking for builds 2021-07-13 20:11:15 -04:00
tydeu
115fdbea98 refactor: simplify mtime checking code 2021-07-13 16:18:42 -04:00
tydeu
4844f8c459 refactor: once again use to lean target mtime in fetch 2021-07-13 13:40:05 -04:00
tydeu
511f34fd53 refactor: simplify Compile.lean 2021-07-12 21:15:08 -04:00
tydeu
c08812e9e1 refactor: merge fetchLeanTarget into fetchAfterDirectLocalImports 2021-07-12 19:40:37 -04:00
tydeu
3b3beec0d4 refactor: clean up buildRBTop and related code 2021-07-11 19:00:51 -04:00
tydeu
d4e3a4f79e fix: bin build now properly waits for dep libs 2021-07-10 23:02:31 -04:00
tydeu
3ad82dcc42 chore: minor code cleanup 2021-07-10 22:40:34 -04:00
tydeu
b290c1ad28 refactor: generalized buildModule and cleaned up `printPaths 2021-07-10 21:19:01 -04:00
tydeu
70d258049e refactor: generalize mtime checking 2021-07-10 16:01:18 -04:00
tydeu
6161d7f2d9 refactor: generalize BuildTarget traces 2021-07-10 13:39:51 -04:00
tydeu
9ce5fa6a6d refactor: generalize build error catching 2021-07-10 13:04:18 -04:00
tydeu
1ccebe9b89 chore: improve shell scripts 2021-07-10 12:36:13 -04:00
tydeu
d1674a6ba0 refactor: rename helloDeps test to deps 2021-07-10 12:23:20 -04:00
tydeu
9da32ce7eb chore: add Packager test 2021-07-10 12:21:52 -04:00
tydeu
042353d862 feat: allow cli arguments to be passed to package.lean 2021-07-10 12:03:49 -04:00
tydeu
16534d3be6 chore: update Lean version 2021-07-09 21:03:16 -04:00
tydeu
ea4cbfae73 feat: deps build in parallel + lib/bin check mtime 2021-07-09 20:49:39 -04:00
tydeu
f97f69b749 refactor: BuildInfo -> BuildTarget 2021-07-09 00:36:46 -04:00
tydeu
a4622f61ca doc: update help command text 2021-07-08 20:58:25 -04:00
tydeu
981db940e8 feat: build packages without make 2021-07-08 19:46:10 -04:00
tydeu
9034b6b79b chore: bump to v2.0-pre 2021-07-08 17:42:17 -04:00
Mac Malone
22dc542445 Release 1.0 2021-06-14 01:42:16 -04:00
Mac Malone
9aa78a5361 More README edits 2021-06-14 01:36:19 -04:00
Mac Malone
f7a858c0de Add search path heading to README 2021-06-14 01:08:35 -04:00
Mac Malone
b7b0217241 Bump Lean version 2021-06-14 01:08:05 -04:00
Mac Malone
2aa3c1e0cb Add test script to hello example 2021-06-14 00:29:09 -04:00
Mac Malone
4532901112 Refactor helloDeps example to have two deps 2021-06-12 22:28:59 -04:00
Mac Malone
9138d37781 Fix dep lib separator 2021-06-12 22:27:19 -04:00
Mac Malone
c0d9917f7c Update to Lean nightly 06-13 2021-06-12 22:01:17 -04:00
Mac Malone
f512a9a934 Auto link dep libs for bin (+ more pkg path helpers) 2021-06-12 21:34:34 -04:00
Mac Malone
ecfd65ffb7 Clean up buildModule code and integrate cycle fix 2021-06-12 20:00:07 -04:00
Mac Malone
93f5368162 Rename build state/result to BuildState/BuildResult 2021-06-11 17:15:31 -04:00
Mac Malone
9b1d958f9c Fixed a typo in the README 2021-06-08 17:40:02 -04:00
Mac Malone
68f0eb16bd Minor LeanConfig code cleanup 2021-06-08 17:18:27 -04:00
Mac Malone
6fad405294 Intelligently initialize Lean search path 2021-06-08 17:17:58 -04:00
Mac Malone
7791b49be9 Add shell scripts for building Lake and its examples 2021-06-07 22:23:54 -04:00
Mac Malone
96870779a2 Add Lake build/run instructions to README 2021-06-07 17:03:51 -04:00
Mac Malone
af7e167dea Bump to v1.0-pre 2021-06-07 06:00:18 -04:00
Mac Malone
8c39a65609 Move .lake-lock into the build directory 2021-06-07 05:55:13 -04:00
Mac Malone
c5c46798fb Extend README 2021-06-07 05:46:08 -04:00
Mac Malone
6fc398133d Rename Leanpkg2 to Lake 2021-06-07 05:42:42 -04:00
Mac Malone
12537427c2 Fix some errors when running leanpkg2 in executable form 2021-06-07 05:30:17 -04:00
Mac Malone
7770d4b421 Removed leftover hack for TOML 2021-06-07 02:38:23 -04:00
Mac Malone
76183aa6d1 Remove TOML code 2021-06-06 23:30:32 -04:00
Mac Malone
0f6b07e434 Remove unused examples/helloDeps/a/leanpkg.toml 2021-06-06 23:06:19 -04:00
Mac Malone
2ba39f56f0 The solved dependency list no longer includes the root package 2021-06-06 23:04:52 -04:00
Mac Malone
6317ab22e7 Only build dependency lib if bin is passed to leanpkg buld 2021-06-06 22:50:40 -04:00
Mac Malone
99d458c646 Update init to produce package.lean 2021-06-06 21:56:58 -04:00
Mac Malone
d066872549 CLI now uses configuration from package.lean' 2021-06-06 21:40:11 -04:00
Mac Malone
8efd56d131 Properly lowercase Package.lean configurations 2021-06-06 19:33:12 -04:00
Mac Malone
6b999dcb21 Refactored away the old notion of a manifest 2021-06-06 19:27:18 -04:00
Mac Malone
3cc0c3e370 Package.lean => package.lean 2021-06-06 16:09:26 -04:00
Mac Malone
07e804ad16 Cleanup TOML manifest code 2021-06-03 16:58:55 -04:00
Mac Malone
3ca6b0bf51 Minor code style cleanup 2021-06-03 15:17:46 -04:00
Mac Malone
bf15f71568 Removed Manifest.path 2021-06-02 18:55:47 -04:00
Mac Malone
158838bf63 Fix local depdir calculation 2021-06-02 18:25:30 -04:00
Mac Malone
9544f3dad8 Refactor materlize / git code 2021-06-02 18:19:31 -04:00
Mac Malone
f2041789b7 Renamed Manifest.lean to Pakcage.lean 2021-06-02 16:02:22 -04:00
Mac Malone
d5d8ff588a Solver now returns Package 2021-06-02 15:21:36 -04:00
Mac Malone
a462864d78 Add cleaner script for 'helloDeps' example 2021-06-02 15:21:07 -04:00
Mac Malone
436d3213de Now built off Lean master 2021-05-30 17:30:33 -04:00
Mac Malone
543656c24b Merge Configure into Build 2021-05-29 22:57:24 -04:00
Mac Malone
ef0135ac9e Add working example expackage with a (local) dependency 2021-05-29 21:29:33 -04:00
Mac Malone
44b9ad2a30 Assorted code cleanup and reogranization 2021-05-29 12:42:05 -04:00
Mac Malone
ea9382643e Builds with buildModules now work as well 2021-05-29 11:27:31 -04:00
Mac Malone
82b368e838 Add README 2021-05-29 09:07:48 -04:00
Mac Malone
84ae7466a4 Update Authors 2021-05-29 09:07:42 -04:00
Mac Malone
93732bc7db Add LICENSE 2021-05-29 09:02:26 -04:00
Mac Malone
404d32c730 Port over Leanpkg and get an example building 2021-05-29 08:54:48 -04:00
Mac Malone
a24d7d593a Initial Commit 2021-05-28 17:13:55 -04:00
540 changed files with 11584 additions and 461 deletions

View File

@@ -67,13 +67,13 @@ jobs:
os: ubuntu-latest
CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Debug
# exclude seriously slow tests
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest'
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest|benchtest'
- name: Linux fsanitize
os: ubuntu-latest
# turn off custom allocator & symbolic functions to make LSAN do its magic
CMAKE_OPTIONS: -DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address,undefined -DLEANC_EXTRA_FLAGS='-fsanitize=address,undefined -fsanitize-link-c++-runtime' -DSMALL_ALLOCATOR=OFF -DBSYMBOLIC=OFF
# exclude seriously slow/problematic tests (laketests crash)
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest'
CTEST_OPTIONS: -E 'interactivetest|leanpkgtest|laketest|benchtest'
- name: macOS
os: macos-latest
release: true
@@ -105,7 +105,7 @@ jobs:
binary-check: ldd
- name: Linux aarch64
os: ubuntu-latest
CMAKE_OPTIONS: -DCMAKE_PREFIX_PATH=$GMP -DLEAN_INSTALL_SUFFIX=-linux_aarch64
CMAKE_OPTIONS: -DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64
release: true
cross: true
shell: nix-shell --arg pkgsDist "import (fetchTarball \"channel:nixos-19.03\") {{ localSystem.config = \"aarch64-unknown-linux-gnu\"; }}" --run "bash -euxo pipefail {0}"

4
.gitmodules vendored
View File

@@ -1,4 +0,0 @@
[submodule "lake"]
path = src/lake
url = https://github.com/leanprover/lake.git
ignore = untracked

View File

@@ -1,5 +1,5 @@
This is the repository for **Lean 4**, which is currently being released as milestone releases towards a first stable release.
[Lean 3](https://github.com/leanprover/lean) is still the latest stable release.
This is the repository for **Lean 4**, which is being actively developed and published as nightly releases.
Stable point releases are planned for a later date after establishing a robust release process.
# About

View File

@@ -818,7 +818,7 @@ v4.0.0-m4 (23 March 2022)
initialize my_ext : SimpExtension ← registerSimpAttr `my_simp "my own simp attribute"
```
If you don't neet to acces `my_ext`, you can also use the macro
If you don't need to access `my_ext`, you can also use the macro
```lean
import Lean

View File

@@ -4,6 +4,7 @@
- [Tour of Lean](./tour.md)
- [Setting Up Lean](./quickstart.md)
- [Extended Setup Notes](./setup.md)
- [Nix Setup](./setup/nix.md)
- [Theorem Proving in Lean](./tpil.md)
- [Functional Programming in Lean](fplean.md)
- [Examples](./examples.md)

View File

@@ -57,3 +57,10 @@ You might find that debugging through elan, e.g. via `gdb lean`, disables some
things like symbol autocompletion because at first only the elan proxy binary
is loaded. You can instead pass the explicit path to `bin/lean` in your build
folder to gdb, or use `gdb $(elan which lean)`.
It is also possible to generate releases that others can use,
simply by pushing a tag to your fork of the Lean 4 github repository
(and waiting about an hour; check the `Actions` tab for completion).
If you push `my-tag` to a fork in your github account `my_name`,
you can then put `my_name/lean4:my-tag` in your `lean-toolchain` file in a project using `lake`.
(You must use a tag name that does not start with a numeral, or contain `_`).

View File

@@ -83,7 +83,7 @@ Work on two adjacent stages at the same time without the need for repeatedly upd
```bash
# open an editor that will use only committed changes (so first commit them when changing files)
nix run .#HEAD-as-stage1.emacs-dev&
# open a second editor that will use those commited changes as stage 0
# open a second editor that will use those committed changes as stage 0
# (so don't commit changes done here until you are done and ran a final `update-stage0-commit`)
nix run .#HEAD-as-stage0.emacs-dev&
```

View File

@@ -212,7 +212,7 @@ so you get a nice zipped list like this:
-- [(1, 4), (2, 5), (3, 6)]
/-!
And of couse, as you would expect, there is an `unzip` also:
And of course, as you would expect, there is an `unzip` also:
-/
#eval List.unzip (List.zip [1, 2, 3] [4, 5, 6])
@@ -286,7 +286,7 @@ But you will need to understand full Monads before this will make sense.
Diving a bit deeper, (you can skip this and jump to the [Applicative
Laws](laws.lean.md#what-are-the-applicative-laws) if don't want to dive into this implementation detail right
now). But, if you write a simple `Option` example `(.*.) <$> some 4 <*> some 5` that produces `some 20`
using `Seq.seq` you will see somthing interesting:
using `Seq.seq` you will see something interesting:
-/
#eval Seq.seq ((.*.) <$> some 4) (fun (_ : Unit) => some 5) -- some 20

View File

@@ -18,9 +18,11 @@ See quick [walkthrough demo video](https://www.youtube.com/watch?v=yZo6k48L0VY).
```
info: syncing channel updates for 'nightly'
info: latest update on nightly, lean version nightly-2021-12-05
info: latest update on nightly, lean version nightly-2023-06-27
info: downloading component 'lean'
```
If there is no popup, you probably have Elan installed already.
You may want to make sure that your default toolchain is Lean 4 in this case by running `elan default leanprover/lean4:nightly` and reopen the file, as the next step will fail otherwise.
1. While it is installing, you can paste the following Lean program into the new file:
@@ -37,6 +39,8 @@ You are set up!
## Create a Lean Project
*If your goal is to contribute to [mathlib4](https://github.com/leanprover-community/mathlib4) or use it as a depdency, please see its readme for specific instructions on how to do that.*
You can now create a Lean project in a new folder. Run `lake init foo` from "View > Terminal" to create a package, followed by `lake build` to get an executable version of your Lean program.
On Linux/macOS, you first have to follow the instructions printed by the Lean installation or log out and in again for the Lean executables to be available in you terminal.

View File

@@ -2,7 +2,7 @@
### Tier 1
Platforms built & tested by our CI, available as nightly & stable releases via elan (see above)
Platforms built & tested by our CI, available as nightly releases via elan (see below)
* x86-64 Linux with glibc 2.27+
* x86-64 macOS 10.15+
@@ -10,13 +10,13 @@ Platforms built & tested by our CI, available as nightly & stable releases via e
### Tier 2
Platforms cross-compiled but not tested by our CI, available as nightly & stable releases
Platforms cross-compiled but not tested by our CI, available as nightly releases
Releases may be silently broken due to the lack of automated testing.
Issue reports and fixes are welcome.
* aarch64 Linux with glibc 2.27+
* aarch64 (M1) macOS
* aarch64 (Apple Silicon) macOS
<!--
### Tier 3
@@ -26,26 +26,17 @@ Platforms that are known to work from manual testing, but do not come with CI or
# Setting Up Lean
There are currently two ways to set up a Lean 4 development environment:
* [basic setup](./setup.md#basic-setup) (Linux/macOS/Windows): uses [`elan`](https://github.com/leanprover/elan) + your preinstalled editor
* [Nix setup](./setup.md#nix-setup) (Linux/macOS/WSL): uses the [Nix](https://nixos.org/nix/) package manager for installing all dependencies localized to your project
See also the [quickstart](./quickstart.md) instructions for using the basic setup with VS Code as the editor.
## Basic Setup
See also the [quickstart](./quickstart.md) instructions for a standard setup with VS Code as the editor.
Release builds for all supported platforms are available at <https://github.com/leanprover/lean4/releases>.
Instead of downloading these and setting up the paths manually, however, it is recommended to use the Lean version manager [`elan`](https://github.com/leanprover/elan) instead:
```sh
$ elan self update # in case you haven't updated elan in a while
# download & activate latest Lean 4 release (https://github.com/leanprover/lean4/releases)
$ elan default leanprover/lean4:stable
# alternatively, use the latest nightly build (https://github.com/leanprover/lean4-nightly/releases)
# download & activate latest Lean 4 nightly release (https://github.com/leanprover/lean4-nightly/releases)
$ elan default leanprover/lean4:nightly
```
### `lake`
## `lake`
Lean 4 comes with a package manager named `lake`.
Use `lake init foo` to initialize a Lean package `foo` in the current directory, and `lake build` to typecheck and build it as well as all its dependencies. Use `lake help` to learn about further commands.
@@ -65,80 +56,8 @@ After running `lake build` you will see a binary named `./build/bin/foo` and whe
Hello, world!
```
### Editing
## Editing
Lean implements the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) that can be used for interactive development in [Emacs](https://github.com/leanprover/lean4-mode), [VS Code](https://github.com/leanprover-community/vscode-lean4), and possibly other editors.
Changes must be saved to be visible in other files, which must then be invalidated using an editor command (see links above).
## Nix Setup
The alternative setup based on Nix provides a perfectly reproducible development environment for your project from the Lean version down to the editor and Lean extension.
However, it is still experimental and subject to change; in particular, it is heavily based on an unreleased version of Nix enabling [Nix Flakes](https://www.tweag.io/blog/2020-05-25-flakes/). The setup has been tested on NixOS, other Linux distributions, and macOS.
After installing (any version of) Nix (<https://nixos.org/download.html>), you can easily open a shell with the particular pre-release version of Nix needed by and tested with our setup (called the "Lean shell" from here on):
```bash
$ nix-shell https://github.com/leanprover/lean4/archive/master.tar.gz -A nix
```
While this shell is sufficient for executing the steps below, it is recommended to also set the following options in `/etc/nix/nix.conf` (`nix.extraOptions` in NixOS):
```
max-jobs = auto # Allow building multiple derivations in parallel
keep-outputs = true # Do not garbage-collect build time-only dependencies (e.g. clang)
# Allow fetching build results from the Lean Cachix cache
trusted-substituters = https://lean4.cachix.org/
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= lean4.cachix.org-1:mawtxSxcaiWE24xCXXgh3qnvlTkyU7evRRnGeAhD4Wk=
```
On a multi-user installation of Nix (the default), you need to restart the Nix daemon afterwards:
```bash
sudo pkill nix-daemon
```
The [Cachix](https://cachix.org/) integration will magically beam any build steps already executed by the CI right onto your machine when calling Nix commands in the shell opened above.
It can be set up analogously as a cache for your own project.
Note: Your system Nix might print warnings about not knowing some of the settings used by the Lean shell Nix, which can be ignored.
### Basic Commands
From a Lean shell, run
```bash
$ nix flake new mypkg -t github:leanprover/lean4
```
to create a new Lean package in directory `mypkg` using the latest commit of Lean 4.
Such packages follow the same directory layout as described in the basic setup above, except for a `lakefile.lean` replaced by a `flake.nix` file set up so you can run Nix commands on it, for example:
```bash
$ nix build # build package and all dependencies
$ nix build .#executable # compile `main` definition into executable (after you've added one)
$ nix run .#emacs-dev # open a pinned version of Emacs with lean4-mode fully set up
$ nix run .#emacs-dev MyPackage.lean # arguments can be passed as well, e.g. the file to open
$ nix run .#vscode-dev MyPackage.lean # ditto, using VS Code
```
Note that if you rename `MyPackage.lean`, you also have to adjust the `name` attribute in `flake.nix` accordingly.
Also note that if you turn the package into a Git repository, only tracked files will be visible to Nix.
As in the basic setup, changes need to be saved to be visible in other files, which have then to be invalidated via an editor command.
If you don't want to or cannot start the pinned editor from Nix, e.g. because you're running Lean inside WSL/a container/on a different machine, you can manually point your editor at the `lean` wrapper script the commands above use internally:
```bash
$ nix build .#lean-dev -o result-lean-dev
```
The resulting `./result-lean-dev/bin/lean` script essentially runs `nix run .#lean` in the current project's root directory when you open a Lean file or use the "refresh dependencies" command such that the correct Lean version for that project is executed.
This includes selecting the correct stage of Lean (which it will compile on the fly, though without progress output) if you are [working on Lean itself](./make/nix.md#editor-integration).
Package dependencies can be added as further input flakes and passed to the `deps` list of `buildLeanPackage`. Example: <https://github.com/Kha/testpkg2/blob/master/flake.nix#L5>
For hacking, it can be useful to temporarily override an input with a local checkout/different version of a dependency:
```bash
$ nix build --override-input somedep path/to/somedep
```
On a build error, Nix will show the last 10 lines of the output by default. You can pass `-L` to `nix build` to show all lines, or pass the shown `*.drv` path to `nix log` to show the full log after the fact.
Keeping all outputs ever built on a machine alive can accumulate to quite impressive amounts of disk space, so you might want to trigger the Nix GC when `/nix/store/` has grown too large:
```bash
nix-collect-garbage
```
This will remove everything not reachable from "GC roots" such as the `./result` symlink created by `nix build`.
Note that the package information in `flake.nix` is currently completely independent from `lakefile.lean` used in the basic setup.
Unifying the two formats is TBD.

71
doc/setup/nix.md Normal file
View File

@@ -0,0 +1,71 @@
# Nix Setup
An alternative setup based on Nix provides a perfectly reproducible development environment for your project from the Lean version down to the editor and Lean extension.
However, it is still experimental and subject to change; in particular, it is heavily based on an unreleased version of Nix enabling [Nix Flakes](https://www.tweag.io/blog/2020-05-25-flakes/). The setup has been tested on NixOS, other Linux distributions, and macOS.
After installing (any version of) Nix (<https://nixos.org/download.html>), you can easily open a shell with the particular pre-release version of Nix needed by and tested with our setup (called the "Lean shell" from here on):
```bash
$ nix-shell https://github.com/leanprover/lean4/archive/master.tar.gz -A nix
```
While this shell is sufficient for executing the steps below, it is recommended to also set the following options in `/etc/nix/nix.conf` (`nix.extraOptions` in NixOS):
```
max-jobs = auto # Allow building multiple derivations in parallel
keep-outputs = true # Do not garbage-collect build time-only dependencies (e.g. clang)
# Allow fetching build results from the Lean Cachix cache
trusted-substituters = https://lean4.cachix.org/
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= lean4.cachix.org-1:mawtxSxcaiWE24xCXXgh3qnvlTkyU7evRRnGeAhD4Wk=
```
On a multi-user installation of Nix (the default), you need to restart the Nix daemon afterwards:
```bash
sudo pkill nix-daemon
```
The [Cachix](https://cachix.org/) integration will magically beam any build steps already executed by the CI right onto your machine when calling Nix commands in the shell opened above.
It can be set up analogously as a cache for your own project.
Note: Your system Nix might print warnings about not knowing some of the settings used by the Lean shell Nix, which can be ignored.
## Basic Commands
From a Lean shell, run
```bash
$ nix flake new mypkg -t github:leanprover/lean4
```
to create a new Lean package in directory `mypkg` using the latest commit of Lean 4.
Such packages follow the same directory layout as described in the standard setup, except for a `lakefile.lean` replaced by a `flake.nix` file set up so you can run Nix commands on it, for example:
```bash
$ nix build # build package and all dependencies
$ nix build .#executable # compile `main` definition into executable (after you've added one)
$ nix run .#emacs-dev # open a pinned version of Emacs with lean4-mode fully set up
$ nix run .#emacs-dev MyPackage.lean # arguments can be passed as well, e.g. the file to open
$ nix run .#vscode-dev MyPackage.lean # ditto, using VS Code
```
Note that if you rename `MyPackage.lean`, you also have to adjust the `name` attribute in `flake.nix` accordingly.
Also note that if you turn the package into a Git repository, only tracked files will be visible to Nix.
As in the standard setup, changes need to be saved to be visible in other files, which have then to be invalidated via an editor command.
If you don't want to or cannot start the pinned editor from Nix, e.g. because you're running Lean inside WSL/a container/on a different machine, you can manually point your editor at the `lean` wrapper script the commands above use internally:
```bash
$ nix build .#lean-dev -o result-lean-dev
```
The resulting `./result-lean-dev/bin/lean` script essentially runs `nix run .#lean` in the current project's root directory when you open a Lean file or use the "refresh dependencies" command such that the correct Lean version for that project is executed.
This includes selecting the correct stage of Lean (which it will compile on the fly, though without progress output) if you are [working on Lean itself](./make/nix.md#editor-integration).
Package dependencies can be added as further input flakes and passed to the `deps` list of `buildLeanPackage`. Example: <https://github.com/Kha/testpkg2/blob/master/flake.nix#L5>
For hacking, it can be useful to temporarily override an input with a local checkout/different version of a dependency:
```bash
$ nix build --override-input somedep path/to/somedep
```
On a build error, Nix will show the last 10 lines of the output by default. You can pass `-L` to `nix build` to show all lines, or pass the shown `*.drv` path to `nix log` to show the full log after the fact.
Keeping all outputs ever built on a machine alive can accumulate to quite impressive amounts of disk space, so you might want to trigger the Nix GC when `/nix/store/` has grown too large:
```bash
nix-collect-garbage
```
This will remove everything not reachable from "GC roots" such as the `./result` symlink created by `nix build`.
Note that the package information in `flake.nix` is currently completely independent from `lakefile.lean` used in the standard setup.
Unifying the two formats is TBD.

View File

@@ -1,5 +1,5 @@
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
stdenv, lib, cmake, gmp, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
stdenv, lib, cmake, gmp, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
... } @ args:
with builtins;
rec {
@@ -88,7 +88,7 @@ rec {
src = src + "/src";
roots = [ { mod = args.name; glob = "andSubmodules"; } ];
fullSrc = src;
srcPrefix = "src";
srcPath = "$PWD/src:$PWD/src/lake";
inherit debug;
} // args);
Init' = build { name = "Init"; deps = []; };
@@ -101,13 +101,25 @@ rec {
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
Init = attachSharedLib leanshared Init';
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Init ]; };
stdlib = [ Init Lean ];
Lake = build {
name = "Lake";
src = src + "/src/lake";
deps = [ Init Lean ];
};
Lake-Main = build {
name = "Lake.Main";
roots = [ "Lake.Main" ];
executableName = "lake";
deps = [ Lake ];
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
src = src + "/src/lake";
};
stdlib = [ Init 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; };
extlib = stdlib; # TODO: add Lake
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${leancpp}/lib/lean";
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${Lake.staticLib} -L${leancpp}/lib/lean";
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"} \
@@ -116,7 +128,8 @@ rec {
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
-o $out/$libName
'';
mods = Init.mods // Lean.mods;
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${leanshared} "$@"
'';
@@ -129,9 +142,9 @@ rec {
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 extlib)} ${leanshared}/* $out/lib/lean/
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${leanshared}/* $out/lib/lean/
# put everything in a single final derivation so `IO.appDir` references work
cp ${lean}/bin/lean ${leanc}/bin/leanc $out/bin
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
'';
@@ -140,30 +153,30 @@ rec {
cacheRoots = linkFarmFromDrvs "cacheRoots" [
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
# .o files are not a runtime dependency on macOS because of lack of thin archives
Lean.oTree
Lean.oTree Lake.oTree
];
test = buildCMake {
name = "lean-test-${desc}";
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
buildInputs = [ gmp perl ];
buildInputs = [ gmp perl git ];
preConfigure = ''
cd src
'';
extraCMakeFlags = [ "-DLLVM=OFF" ];
postConfigure = ''
patchShebangs ../../tests
patchShebangs ../../tests ../lake
rm -r bin lib include share
ln -sf ${lean-all}/* .
'';
buildPhase = ''
ctest --output-on-failure -E 'leancomptest_(doc_example|foreign)|laketest|leanpkgtest' -j$NIX_BUILD_CORES
ctest --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
'';
installPhase = ''
touch $out
'';
};
update-stage0 =
let cTree = symlinkJoin { name = "cs"; paths = map (l: l.cTree) stdlib; }; in
let cTree = symlinkJoin { name = "cs"; paths = [ Init.cTree Lean.cTree ]; }; in
writeShellScriptBin "update-stage0" ''
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/update-stage0"}
'';

View File

@@ -3,7 +3,7 @@
runCommand, darwin, mkShell, ... }:
let lean-final' = lean-final; in
lib.makeOverridable (
{ name, src, fullSrc ? src, srcPrefix ? "",
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
# Lean dependencies. Each entry should be an output of buildLeanPackage.
deps ? [ lean.Lean ],
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
@@ -210,7 +210,6 @@ with builtins; let
loadDynlibPaths = map pathOfSharedLib (loadDynlibsOfDeps deps);
}}'
'';
makePrintPathsFor = deps: mods: printPaths deps // mapAttrs (_: mod: makePrintPathsFor (deps ++ [mod]) mods) mods;
expandGlob = g:
if typeOf g == "string" then [g]
else if g.glob == "one" then [g.mod]
@@ -270,6 +269,7 @@ in rec {
ln -sf ${iTree}/* $dest/build/lib
'';
makePrintPathsFor = deps: mods: printPaths deps // mapAttrs (_: mod: makePrintPathsFor (deps ++ [mod]) mods) mods;
print-paths = makePrintPathsFor [] (mods' // externalModMap);
# `lean` wrapper that dynamically runs Nix for the actual `lean` executable so the same editor can be
# used for multiple projects/after upgrading the `lean` input/for editing both stage 1 and the tests
@@ -297,7 +297,7 @@ in rec {
devShell = mkShell {
buildInputs = [ nix ];
shellHook = ''
export LEAN_SRC_PATH="$PWD/${srcPrefix}"
export LEAN_SRC_PATH="${srcPath}"
'';
};
})

View File

@@ -34,8 +34,11 @@ $CP llvm/lib/clang/*/include/{std*,__std*,limits}.h stage1/include/clang
(cd llvm; $CP --parents lib/clang/*/lib/*/libclang_rt.osx.a ../stage1)
# libSystem stub, includes libc
cp $SDK/usr/lib/libSystem.tbd stage1/lib/libc
# use for linking, use system libs for running
gcp llvm/lib/lib{c++,c++abi,unwind}.dylib stage1/lib/libc
# use for linking, use system lib for running
gcp llvm/lib/libc++.dylib stage1/lib/libc
# make sure we search for the library in /usr/lib instead of the rpath, which should not contain `/usr/lib`
# and apparently since Sonoma does not do so implicitly either
install_name_tool -id /usr/lib/libc++.dylib stage1/lib/libc/libc++.dylib
echo -n " -DLLVM=ON -DLLVM_CONFIG=$PWD/llvm-host/bin/llvm-config" # manually point to `llvm-config` location
echo -n " -DLEAN_STANDALONE=ON"
# do not change C++ compiler; libc++ etc. being system libraries means there's no danger of conflicts,

View File

@@ -3,8 +3,8 @@ set -euo pipefail
rm -r stage0 || true
# don't copy untracked files
for f in $(git ls-files src); do
[[ $f != src/lake && $f != src/Leanc.lean ]] || continue
# `:!` is git glob flavor for exclude patterns
for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
if [[ $f == *.lean ]]; then
f=${f#src/}
f=${f%.lean}.c

View File

@@ -293,7 +293,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
find_package(ZLIB REQUIRED)
message(STATUS "ZLIB_LIBRARY: ${ZLIB_LIBRARY}")
cmake_path(GET ZLIB_LIBRARY PARENT_PATH ZLIB_LIBRARY_PARENT_PATH)
string(APPEND LEAN_EXTRA_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
string(APPEND LEANSHARED_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
endif()
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lleanrt")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
@@ -301,6 +301,7 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
else()
string(APPEND LEANC_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
endif()
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lLake")
set(LEAN_CXX_STDLIB "-lstdc++" CACHE STRING "C++ stdlib linker flags")

View File

@@ -1480,7 +1480,7 @@ end
section Exact
variable {α : Sort u}
variable {α : Sort u}
private def rel {s : Setoid α} (q₁ q₂ : Quotient s) : Prop :=
Quotient.liftOn₂ q₁ q₂

View File

@@ -269,7 +269,15 @@ unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad
/-- Reference implementation for `mapM` -/
@[implemented_by mapMUnsafe]
def mapM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α m β) (as : Array α) : m (Array β) :=
as.foldlM (fun bs a => do let b f a; pure (bs.push b)) (mkEmpty as.size)
-- Note: we cannot use `foldlM` here for the reference implementation because this calls
-- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
let rec map (i : Nat) (r : Array β) : m (Array β) := do
if hlt : i < as.size then
map (i+1) (r.push ( f as[i]))
else
pure r
map 0 (mkEmpty as.size)
termination_by map => as.size - i
@[inline]
def mapIdxM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (as : Array α) (f : Fin as.size α m β) : m (Array β) :=

View File

@@ -58,3 +58,7 @@ instance : Hashable Int where
instance (P : Prop) : Hashable P where
hash _ := 0
/-- An opaque (low-level) hash operation used to implement hashing for pointers. -/
@[always_inline, inline] def hash64 (u : UInt64) : UInt64 :=
mixHash u 11

View File

@@ -269,8 +269,8 @@ def natAbs (m : @& Int) : Nat :=
#eval (12 : Int) / (7 : Int) -- 1
#eval (12 : Int) / (-7 : Int) -- -1
#eval (-12 : Int) / (7 : Int) -- -2
#eval (-12 : Int) / (-7 : Int) -- 2
#eval (-12 : Int) / (7 : Int) -- -1
#eval (-12 : Int) / (-7 : Int) -- 1
```
Implemented by efficient native code. -/

View File

@@ -247,7 +247,7 @@ termination_by _ => s.endPos.1 - i.1
def splitOnAux (s sep : String) (b : Pos) (i : Pos) (j : Pos) (r : List String) : List String :=
if h : s.atEnd i then
let r := if sep.atEnd j then ""::(s.extract b (i - j))::r else (s.extract b i)::r
let r := (s.extract b i)::r
r.reverse
else
have := Nat.sub_lt_sub_left (Nat.gt_of_not_le (mt decide_eq_true h)) (lt_next s _)

View File

@@ -65,7 +65,7 @@ syntax unifConstraint := term patternIgnore(" =?= " <|> " ≟ ") term
syntax unifConstraintElem := colGe unifConstraint ", "?
syntax (docComment)? attrKind "unif_hint" (ppSpace ident)? (ppSpace bracketedBinder)*
" where " withPosition(unifConstraintElem*) patternIgnore("|-" <|> " ") unifConstraint : command
" where " withPosition(unifConstraintElem*) patternIgnore(atomic("|" noWs "-") <|> "") unifConstraint : command
macro_rules
| `($[$doc?:docComment]? $kind:attrKind unif_hint $(n)? $bs* where $[$cs₁ $cs₂]* |- $t₁ $t₂) => do

View File

@@ -608,7 +608,7 @@ parameter.
For example, the `Coe` class is defined as:
```
class Coe (α : semiOutParam (Type u)) (β : Type v)
class Coe (α : semiOutParam (Sort u)) (β : Sort v)
```
This means that all `Coe` instances should provide a concrete value for `α`
(i.e., not an assignable metavariable). An instance like `Coe Nat Int` or `Coe
@@ -1471,7 +1471,7 @@ set_option bootstrap.genMatcherCode false in
/--
The power operation on natural numbers.
This definition is overridden in the compiler to efficiently
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see `Nat`). The definition provided
here is the logical model.
-/

View File

@@ -156,3 +156,6 @@ theorem Bool.or_assoc (a b c : Bool) : (a || b || c) = (a || (b || c)) := by
@[simp] theorem decide_False : decide False = false := rfl
@[simp] theorem decide_True : decide True = true := rfl
@[simp] theorem bne_iff_ne [BEq α] [LawfulBEq α] (a b : α) : a != b a b := by
simp [bne]; rw [ beq_iff_eq a b]; simp [-beq_iff_eq]

View File

@@ -8,26 +8,26 @@ import Init.Meta
import Init.SizeOf
import Init.Data.Nat.Linear
@[simp] theorem Fin.sizeOf (a : Fin n) : sizeOf a = a.val + 1 := by
@[simp] protected theorem Fin.sizeOf (a : Fin n) : sizeOf a = a.val + 1 := by
cases a; simp_arith
@[simp] theorem UInt8.sizeOf (a : UInt8) : sizeOf a = a.toNat + 2 := by
@[simp] protected theorem UInt8.sizeOf (a : UInt8) : sizeOf a = a.toNat + 2 := by
cases a; simp_arith [UInt8.toNat]
@[simp] theorem UInt16.sizeOf (a : UInt16) : sizeOf a = a.toNat + 2 := by
@[simp] protected theorem UInt16.sizeOf (a : UInt16) : sizeOf a = a.toNat + 2 := by
cases a; simp_arith [UInt16.toNat]
@[simp] theorem UInt32.sizeOf (a : UInt32) : sizeOf a = a.toNat + 2 := by
@[simp] protected theorem UInt32.sizeOf (a : UInt32) : sizeOf a = a.toNat + 2 := by
cases a; simp_arith [UInt32.toNat]
@[simp] theorem UInt64.sizeOf (a : UInt64) : sizeOf a = a.toNat + 2 := by
@[simp] protected theorem UInt64.sizeOf (a : UInt64) : sizeOf a = a.toNat + 2 := by
cases a; simp_arith [UInt64.toNat]
@[simp] theorem USize.sizeOf (a : USize) : sizeOf a = a.toNat + 2 := by
@[simp] protected theorem USize.sizeOf (a : USize) : sizeOf a = a.toNat + 2 := by
cases a; simp_arith [USize.toNat]
@[simp] theorem Char.sizeOf (a : Char) : sizeOf a = a.toNat + 3 := by
@[simp] protected theorem Char.sizeOf (a : Char) : sizeOf a = a.toNat + 3 := by
cases a; simp_arith [Char.toNat]
@[simp] theorem Subtype.sizeOf {α : Sort u_1} {p : α Prop} (s : Subtype p) : sizeOf s = sizeOf s.val + 1 := by
@[simp] protected theorem Subtype.sizeOf {α : Sort u_1} {p : α Prop} (s : Subtype p) : sizeOf s = sizeOf s.val + 1 := by
cases s; simp_arith

View File

@@ -294,6 +294,14 @@ end Handle
@[extern "lean_io_remove_dir"] opaque removeDir : @& FilePath IO Unit
@[extern "lean_io_create_dir"] opaque createDir : @& FilePath IO Unit
/--
Moves a file or directory `old` to the new location `new`.
This function coincides with the [POSIX `rename` function](https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html),
see there for more information.
-/
@[extern "lean_io_rename"] opaque rename (old new : @& FilePath) : IO Unit
end FS
@[extern "lean_io_getenv"] opaque getEnv (var : @& String) : BaseIO (Option String)
@@ -536,6 +544,8 @@ structure SpawnArgs extends StdioConfig where
cwd : Option FilePath := none
/-- Add or remove environment variables for the process. -/
env : Array (String × Option String) := #[]
/-- Start process in new session and process group using `setsid`. Currently a no-op on non-POSIX platforms. -/
setsid : Bool := false
-- TODO(Sebastian): constructor must be private
structure Child (cfg : StdioConfig) where
@@ -547,6 +557,10 @@ structure Child (cfg : StdioConfig) where
@[extern "lean_io_process_child_wait"] opaque Child.wait {cfg : @& StdioConfig} : @& Child cfg IO UInt32
/-- Terminates the child process using the SIGTERM signal or a platform analogue.
If the process was started using `SpawnArgs.setsid`, terminates the entire process group instead. -/
@[extern "lean_io_process_child_kill"] opaque Child.kill {cfg : @& StdioConfig} : @& Child cfg IO Unit
/--
Extract the `stdin` field from a `Child` object, allowing them to be freed independently.
This operation is necessary for closing the child process' stdin while still holding on to a process handle,

View File

@@ -304,7 +304,7 @@ syntax locationWildcard := " *"
A hypothesis location specification consists of 1 or more hypothesis references
and optionally `⊢` denoting the goal.
-/
syntax locationHyp := (ppSpace colGt term:max)+ ppSpace patternIgnore("" <|> "|-")?
syntax locationHyp := (ppSpace colGt term:max)+ ppSpace patternIgnore( atomic("|" noWs "-") <|> "")?
/--
Location specifications are used by many tactics that can operate on either the

View File

@@ -184,15 +184,9 @@ protected theorem caseStrongInductionOn
end Nat
def Measure {α : Sort u} : (α Nat) α α Prop :=
InvImage (fun a b => a < b)
abbrev measure {α : Sort u} (f : α Nat) : WellFoundedRelation α :=
invImage f Nat.lt_wfRel
def SizeOfRef (α : Sort u) [SizeOf α] : α α Prop :=
Measure sizeOf
abbrev sizeOfWFRel {α : Sort u} [SizeOf α] : WellFoundedRelation α :=
measure sizeOf

View File

@@ -16,6 +16,10 @@ def maxCtorFields := getMaxCtorFields ()
opaque getMaxCtorScalarsSize : Unit Nat
def maxCtorScalarsSize := getMaxCtorScalarsSize ()
@[extern c inline "lean_box(LeanMaxCtorTag)"]
opaque getMaxCtorTag : Unit Nat
def maxCtorTag := getMaxCtorTag ()
@[extern c inline "lean_box(sizeof(size_t))"]
opaque getUSizeSize : Unit Nat
def usizeSize := getUSizeSize ()
@@ -113,6 +117,8 @@ def checkExpr (ty : IRType) : Expr → M Unit
| Expr.ap x ys => checkObjVar x *> checkArgs ys
| Expr.fap f ys => checkFullApp f ys
| Expr.ctor c ys => do
if c.cidx > maxCtorTag && (c.size > 0 || c.usize > 0 || c.ssize > 0) then
throw s!"tag for constructor '{c.name}' is too big, this is a limitation of the current runtime"
if c.size > maxCtorFields then
throw s!"constructor '{c.name}' has too many fields"
if c.ssize + c.usize * usizeSize > maxCtorScalarsSize then
@@ -175,7 +181,7 @@ end Checker
def checkDecl (decls : Array Decl) (decl : Decl) : CompilerM Unit := do
let env getEnv
match (Checker.checkDecl decl { env := env, decls := decls }).run' {} with
| .error msg => throw s!"IR check failed at '{decl.name}', error: {msg}"
| .error msg => throw s!"compiler IR check failed at '{decl.name}', error: {msg}"
| _ => pure ()
def checkDecls (decls : Array Decl) : CompilerM Unit :=

View File

@@ -687,9 +687,13 @@ def emitDeclInit (d : Decl) : M Unit := do
let env getEnv
let n := d.name
if isIOUnitInitFn env n then
if isIOUnitBuiltinInitFn env n then
emit "if (builtin) {"
emit "res = "; emitCName n; emitLn "(lean_io_mk_world());"
emitLn "if (lean_io_result_is_error(res)) return res;"
emitLn "lean_dec_ref(res);"
if isIOUnitBuiltinInitFn env n then
emit "}"
else if d.params.size == 0 then
match getInitFnNameFor? env d.name with
| some initFn =>

View File

@@ -415,24 +415,38 @@ def emitFnDeclAux (mod : LLVM.Module llvmctx)
let env getEnv
-- bollu: if we have a declaration with no parameters, then we emit it as a global pointer.
-- bollu: Otherwise, we emit it as a function
let global
if ps.isEmpty then
let retty (toLLVMType decl.resultType)
let global LLVM.getOrAddGlobal mod cppBaseName retty
if !isExternal then
LLVM.setInitializer global ( LLVM.getUndef retty)
pure global
else
let retty (toLLVMType decl.resultType)
let mut argtys := #[]
for p in ps do
-- if it is extern, then we must not add irrelevant args
if !(isExternC env decl.name) || !p.ty.isIrrelevant then
argtys := argtys.push ( toLLVMType p.ty)
-- TODO (bollu): simplify this API, this code of `closureMaxArgs` is duplicated in multiple places.
if argtys.size > closureMaxArgs && isBoxedName decl.name then
argtys := #[ LLVM.pointerType ( LLVM.voidPtrType llvmctx)]
let fnty LLVM.functionType retty argtys (isVarArg := false)
LLVM.getOrAddFunction mod cppBaseName fnty
-- we must now set symbol visibility for global.
if ps.isEmpty then
let retty (toLLVMType decl.resultType)
let global LLVM.getOrAddGlobal mod cppBaseName retty
if !isExternal then
LLVM.setInitializer global ( LLVM.getUndef retty)
return global
else
let retty (toLLVMType decl.resultType)
let mut argtys := #[]
for p in ps do
-- if it is extern, then we must not add irrelevant args
if !(isExternC env decl.name) || !p.ty.isIrrelevant then
argtys := argtys.push ( toLLVMType p.ty)
-- TODO (bollu): simplify this API, this code of `closureMaxArgs` is duplicated in multiple places.
if argtys.size > closureMaxArgs && isBoxedName decl.name then
argtys := #[ LLVM.pointerType ( LLVM.voidPtrType llvmctx)]
let fnty LLVM.functionType retty argtys (isVarArg := false)
LLVM.getOrAddFunction mod cppBaseName fnty
if isClosedTermName env decl.name then LLVM.setVisibility global LLVM.Visibility.hidden -- static
else if isExternal then pure () -- extern (Recall that C/LLVM funcs are extern linkage by default.)
else LLVM.setDLLStorageClass global LLVM.DLLStorageClass.export -- LEAN_EXPORT
else if !isExternal
-- An extern decl might be linked in from a different translation unit.
-- Thus, we cannot export an external declaration as we do not define it,
-- only declare its presence.
-- So, we only export non-external definitions.
then LLVM.setDLLStorageClass global LLVM.DLLStorageClass.export
return global
def emitFnDecl (decl : Decl) (isExternal : Bool) : M llvmctx Unit := do
let cppBaseName toCName decl.name
@@ -1137,6 +1151,14 @@ def emitDeclAux (mod : LLVM.Module llvmctx) (builder : LLVM.Builder llvmctx) (d
argtys := argtys.push ( toLLVMType x.ty)
let fnty LLVM.functionType retty argtys (isVarArg := false)
let llvmfn LLVM.getOrAddFunction mod name fnty
-- set linkage and visibility
-- TODO: consider refactoring these into a separate concept (e.g. 'setLinkageAndVisibility')
-- Find the spots where this refactor needs to happen by grepping for 'LEAN_EXPORT'
-- in the C backend
if xs.size == 0 then
LLVM.setVisibility llvmfn LLVM.Visibility.hidden -- "static "
else
LLVM.setDLLStorageClass llvmfn LLVM.DLLStorageClass.export -- LEAN_EXPORT: make symbol visible to the interpreter
withReader (fun llvmctx => { llvmctx with mainFn := f, mainParams := xs }) do
set { var2val := default, jp2bb := default : EmitLLVM.State llvmctx } -- flush variable map
let bb LLVM.appendBasicBlockInContext llvmctx llvmfn "entry"
@@ -1247,10 +1269,12 @@ def emitInitFn (mod : LLVM.Module llvmctx) (builder : LLVM.Builder llvmctx) : M
let initFnTy LLVM.functionType ( LLVM.voidPtrType llvmctx) #[ ( LLVM.i8Type llvmctx), ( LLVM.voidPtrType llvmctx)] (isVarArg := false)
let initFn LLVM.getOrAddFunction mod (mkModuleInitializationFunctionName modName) initFnTy
LLVM.setDLLStorageClass initFn LLVM.DLLStorageClass.export -- LEAN_EXPORT
let entryBB LLVM.appendBasicBlockInContext llvmctx initFn "entry"
LLVM.positionBuilderAtEnd builder entryBB
let ginit?ty := LLVM.i1Type llvmctx
let ginit?slot LLVM.getOrAddGlobal mod (modName.mangle ++ "_G_initialized") ginit?ty
LLVM.setVisibility ginit?slot LLVM.Visibility.hidden -- static
LLVM.setInitializer ginit?slot ( LLVM.constFalse llvmctx)
let ginit?v LLVM.buildLoad2 builder ginit?ty ginit?slot "init_v"
buildIfThen_ builder "isGInitialized" ginit?v

View File

@@ -294,6 +294,28 @@ opaque disposeTargetMachine (tm : TargetMachine ctx) : BaseIO Unit
opaque disposeModule (m : Module ctx) : BaseIO Unit
-- https://github.com/llvm/llvm-project/blob/c3e073bcbdc523b0f758d44a89a6333e38bff863/llvm/include/llvm-c/Core.h#L198
structure Visibility where
private mk :: val : UInt64
def Visibility.default : Visibility := { val := 0 }
def Visibility.hidden : Visibility := { val := 1 }
def Visibility.protected : Visibility := { val := 2 }
@[extern "lean_llvm_set_visibility"]
opaque setVisibility {ctx : Context} (value : Value ctx) (visibility : Visibility) : BaseIO Unit
-- https://github.com/llvm/llvm-project/blob/c3e073bcbdc523b0f758d44a89a6333e38bff863/llvm/include/llvm-c/Core.h#L210
structure DLLStorageClass where
private mk :: val : UInt64
def DLLStorageClass.default : DLLStorageClass := { val := 0 }
def DLLStorageClass.import : DLLStorageClass := { val := 1 }
def DLLStorageClass.export : DLLStorageClass := { val := 2 }
@[extern "lean_llvm_set_dll_storage_class"]
opaque setDLLStorageClass {ctx : Context} (value : Value ctx) (dllStorageClass : DLLStorageClass) : BaseIO Unit
-- Helper to add a function if it does not exist, and to return the function handle if it does.
def getOrAddFunction(m : Module ctx) (name : String) (type : LLVMType ctx) : BaseIO (Value ctx) := do
match ( getNamedFunction m name) with

View File

@@ -79,7 +79,7 @@ inductive SpecArgKind where
structure SpecInfo where
mutualDecls : List Name
argKinds : SpecArgKind
argKinds : List SpecArgKind
deriving Inhabited
structure SpecState where

View File

@@ -38,7 +38,7 @@ private def mkIdx {sz : Nat} (hash : UInt64) (h : sz.isPowerOfTwo) : { u : USize
if h' : u.toNat < sz then
u, h'
else
0, by simp [USize.toNat, OfNat.ofNat, USize.ofNat, Fin.ofNat']; rw [Nat.zero_mod]; apply Nat.pos_of_isPowerOfTwo h
0, by simp [USize.toNat, OfNat.ofNat, USize.ofNat, Fin.ofNat']; apply Nat.pos_of_isPowerOfTwo h
@[inline] def reinsertAux (hashFn : α UInt64) (data : HashMapBucket α β) (a : α) (b : β) : HashMapBucket α β :=
let i, h := mkIdx (hashFn a) data.property

View File

@@ -34,7 +34,7 @@ private def mkIdx {sz : Nat} (hash : UInt64) (h : sz.isPowerOfTwo) : { u : USize
if h' : u.toNat < sz then
u, h'
else
0, by simp [USize.toNat, OfNat.ofNat, USize.ofNat, Fin.ofNat']; rw [Nat.zero_mod]; apply Nat.pos_of_isPowerOfTwo h
0, by simp [USize.toNat, OfNat.ofNat, USize.ofNat, Fin.ofNat']; apply Nat.pos_of_isPowerOfTwo h
@[inline] def reinsertAux (hashFn : α UInt64) (data : HashSetBucket α) (a : α) : HashSetBucket α :=
let i, h := mkIdx (hashFn a) data.property

View File

@@ -11,7 +11,7 @@ namespace Lean.Elab
register_builtin_option autoImplicit : Bool := {
defValue := true
descr := "Unbound local variables in declaration headers become implicit arguments. In \"relaxed\" mode (default), any atomic identifier is eligible, otherwise only a lower case or greek letter followed by numeric digits are eligible. For example, `def f (x : Vector α n) : Vector α n :=` automatically introduces the implicit variables {α n}."
descr := "Unbound local variables in declaration headers become implicit arguments. In \"relaxed\" mode (default), any atomic identifier is eligible, otherwise only single character followed by numeric digits are eligible. For example, `def f (x : Vector α n) : Vector α n :=` automatically introduces the implicit variables {α n}."
}
register_builtin_option relaxedAutoImplicit : Bool := {
@@ -39,7 +39,7 @@ Therefore, we do consider identifier with macro scopes anymore.
def isValidAutoBoundImplicitName (n : Name) (relaxed : Bool) : Bool :=
match n with
| .str .anonymous s => s.length > 0 && (relaxed || ((isGreek s.front || s.front.isLower) && isValidAutoBoundSuffix s))
| .str .anonymous s => s.length > 0 && (relaxed || isValidAutoBoundSuffix s)
| _ => false
def isValidAutoBoundLevelName (n : Name) (relaxed : Bool) : Bool :=

View File

@@ -182,7 +182,10 @@ register_builtin_option checkBinderAnnotations : Bool := {
/-- Throw an error if `type` is not a valid local instance. -/
private partial def checkLocalInstanceParameters (type : Expr) : TermElabM Unit := do
let .forallE n d b bi whnf type | return ()
if !b.hasLooseBVar 0 then
-- We allow instance arguments so that local instances of the form
-- `variable [∀ (a : α) [P a], Q a]`
-- are accepted, per https://github.com/leanprover/lean4/issues/2311
if bi != .instImplicit && !b.hasLooseBVar 0 then
throwError "invalid parametric local instance, parameter with type{indentExpr d}\ndoes not have forward dependencies, type class resolution cannot use this kind of local instance because it will not be able to infer a value for this parameter."
withLocalDecl n bi d fun x => checkLocalInstanceParameters (b.instantiate1 x)

View File

@@ -52,14 +52,19 @@ private def popScopes (numScopes : Nat) : CommandElabM Unit :=
for _ in [0:numScopes] do
popScope
private def checkAnonymousScope : List Scope Bool
| { header := "", .. } :: _ => true
| _ => false
private def checkAnonymousScope : List Scope Option Name
| { header := "", .. } :: _ => none
| { header := h, .. } :: _ => some h
| _ => some .anonymous -- should not happen
private def checkEndHeader : Name List Scope Bool
| .anonymous, _ => true
| .str p s, { header := h, .. } :: scopes => h == s && checkEndHeader p scopes
| _, _ => false
private def checkEndHeader : Name List Scope Option Name
| .anonymous, _ => none
| .str p s, { header := h, .. } :: scopes =>
if h == s then
(.str · s) <$> checkEndHeader p scopes
else
some h
| _, _ => some .anonymous -- should not happen
@[builtin_command_elab «namespace»] def elabNamespace : CommandElab := fun stx =>
match stx with
@@ -94,12 +99,12 @@ private def checkEndHeader : Name → List Scope → Bool
throwError "invalid 'end', insufficient scopes"
match header? with
| none =>
unless checkAnonymousScope scopes do
throwError "invalid 'end', name is missing"
if let some name := checkAnonymousScope scopes then
throwError "invalid 'end', name is missing (expected {name})"
| some header =>
unless checkEndHeader header scopes do
if let some name := checkEndHeader header scopes then
addCompletionInfo <| CompletionInfo.endSection stx (scopes.map fun scope => scope.header)
throwError "invalid 'end', name mismatch"
throwError "invalid 'end', name mismatch (expected {if name == `«» then `nothing else name})"
private partial def elabChoiceAux (cmds : Array Syntax) (i : Nat) : CommandElabM Unit :=
if h : i < cmds.size then

View File

@@ -304,7 +304,7 @@ builtin_initialize registerTraceClass `Elab.input
`elabCommand` wrapper that should be used for the initial invocation, not for recursive calls after
macro expansion etc.
-/
def elabCommandTopLevel (stx : Syntax) : CommandElabM Unit := withRef stx do
def elabCommandTopLevel (stx : Syntax) : CommandElabM Unit := withRef stx do profileitM Exception "elaboration" ( getOptions) do
let initMsgs modifyGet fun st => (st.messages, { st with messages := {} })
let initInfoTrees getResetInfoTrees
-- We should *not* factor out `elabCommand`'s `withLogging` to here since it would make its error

View File

@@ -209,11 +209,11 @@ private structure AnalyzeResult where
max? : Option Expr := none
hasUncomparable : Bool := false -- `true` if there are two types `α` and `β` where we don't have coercions in any direction.
private def isUnknow : Expr Bool
private def isUnknown : Expr Bool
| .mvar .. => true
| .app f _ => isUnknow f
| .letE _ _ _ b _ => isUnknow b
| .mdata _ b => isUnknow b
| .app f _ => isUnknown f
| .letE _ _ _ b _ => isUnknown b
| .mdata _ b => isUnknown b
| _ => false
private def analyze (t : Tree) (expectedType? : Option Expr) : TermElabM AnalyzeResult := do
@@ -222,7 +222,7 @@ private def analyze (t : Tree) (expectedType? : Option Expr) : TermElabM Analyze
| none => pure none
| some expectedType =>
let expectedType instantiateMVars expectedType
if isUnknow expectedType then pure none else pure (some expectedType)
if isUnknown expectedType then pure none else pure (some expectedType)
(go t *> get).run' { max? }
where
go (t : Tree) : StateRefT AnalyzeResult TermElabM Unit := do
@@ -233,7 +233,7 @@ where
| .unop _ _ arg => go arg
| .term _ _ val =>
let type instantiateMVars ( inferType val)
unless isUnknow type do
unless isUnknown type do
match ( get).max? with
| none => modify fun s => { s with max? := type }
| some max =>
@@ -246,7 +246,10 @@ where
trace[Elab.binop] "uncomparable types: {max}, {type}"
modify fun s => { s with hasUncomparable := true }
private def mkBinOp (f : Expr) (lhs rhs : Expr) : TermElabM Expr := do
private def mkBinOp (lazy : Bool) (f : Expr) (lhs rhs : Expr) : TermElabM Expr := do
let mut rhs := rhs
if lazy then
rhs mkFunUnit rhs
elabAppArgs f #[] #[Arg.expr lhs, Arg.expr rhs] (expectedType? := none) (explicit := false) (ellipsis := false) (resultIsOutParamSupport := false)
private def mkUnOp (f : Expr) (arg : Expr) : TermElabM Expr := do
@@ -258,11 +261,7 @@ private def toExprCore (t : Tree) : TermElabM Expr := do
modifyInfoState (fun s => { s with trees := s.trees ++ trees }); return e
| .binop ref lazy f lhs rhs =>
withRef ref <| withInfoContext' ref (mkInfo := mkTermInfo .anonymous ref) do
let lhs toExprCore lhs
let mut rhs toExprCore rhs
if lazy then
rhs mkFunUnit rhs
mkBinOp f lhs rhs
mkBinOp lazy f ( toExprCore lhs) ( toExprCore rhs)
| .unop ref f arg =>
withRef ref <| withInfoContext' ref (mkInfo := mkTermInfo .anonymous ref) do
mkUnOp f ( toExprCore arg)
@@ -359,7 +358,7 @@ mutual
return .binop ref lazy f ( go lhs f true false) ( go rhs f false false)
else
let r withRef ref do
mkBinOp f ( toExpr lhs none) ( toExpr rhs none)
mkBinOp lazy f ( toExpr lhs none) ( toExpr rhs none)
let infoTrees getResetInfoTrees
return .term ref infoTrees r
| .unop ref f arg =>
@@ -367,7 +366,7 @@ mutual
| .term ref trees e =>
let type instantiateMVars ( inferType e)
trace[Elab.binop] "visiting {e} : {type} =?= {maxType}"
if isUnknow type then
if isUnknown type then
if let some f := f? then
if ( hasHeterogeneousDefaultInstances f maxType lhs) then
-- See comment at `hasHeterogeneousDefaultInstances`

View File

@@ -62,7 +62,7 @@ def processCommand : FrontendM Bool := do
modify fun s => { s with commands := s.commands.push cmd }
setParserState ps
setMessages messages
profileitM IO.Error "elaboration" scope.opts <| elabCommandAtFrontend cmd
elabCommandAtFrontend cmd
pure (Parser.isTerminalCommand cmd)
partial def processCommands : FrontendM Unit := do

View File

@@ -120,8 +120,7 @@ private def addNonRecAux (preDef : PreDefinition) (compile : Bool) (all : List N
if preDef.modifiers.isNoncomputable then
modifyEnv fun env => addNoncomputable env preDef.declName
if compile && shouldGenCodeFor preDef then
unless ( compileDecl decl) do
return ()
discard <| compileDecl decl
if applyAttrAfterCompilation then
applyAttributesOf #[preDef] AttributeApplicationTime.afterCompilation
@@ -157,8 +156,7 @@ def addAndCompileUnsafe (preDefs : Array PreDefinition) (safety := DefinitionSaf
for preDef in preDefs do
addTermInfo' preDef.ref ( mkConstWithLevelParams preDef.declName) (isBinder := true)
applyAttributesOf preDefs AttributeApplicationTime.afterTypeChecking
unless ( compileDecl decl) do
return ()
discard <| compileDecl decl
applyAttributesOf preDefs AttributeApplicationTime.afterCompilation
return ()

View File

@@ -73,7 +73,7 @@ private def ensureNoUnassignedMVarsAtPreDef (preDef : PreDefinition) : TermElabM
This method beta-reduces them to make sure they can be eliminated by the well-founded recursion module. -/
private def betaReduceLetRecApps (preDefs : Array PreDefinition) : MetaM (Array PreDefinition) :=
preDefs.mapM fun preDef => do
let value transform preDef.value fun e => do
let value Core.transform preDef.value fun e => do
if e.isApp && e.getAppFn.isLambda && e.getAppArgs.all fun arg => arg.getAppFn.isConst && preDefs.any fun preDef => preDef.declName == arg.getAppFn.constName! then
return .visit e.headBeta
else
@@ -106,7 +106,12 @@ def addPreDefinitions (preDefs : Array PreDefinition) (hints : TerminationHints)
for preDefs in cliques do
trace[Elab.definition.scc] "{preDefs.map (·.declName)}"
if preDefs.size == 1 && isNonRecursive preDefs[0]! then
let preDef := preDefs[0]!
/-
We must erase `recApp` annotations even when `preDef` is not recursive
because it may use another recursive declaration in the same mutual block.
See issue #2321
-/
let preDef eraseRecAppSyntax preDefs[0]!
if preDef.modifiers.isNoncomputable then
addNonRec preDef
else

View File

@@ -85,7 +85,14 @@ def structuralRecursion (preDefs : Array PreDefinition) : TermElabM Unit :=
let preDefNonRec eraseRecAppSyntax preDefNonRec
let preDef eraseRecAppSyntax preDefs[0]!
state.addMatchers.forM liftM
registerEqnsInfo preDef recArgPos
unless preDef.kind.isTheorem do
unless ( isProp preDef.type) do
/-
Don't save predefinition info for equation generator
for theorems and definitions that are propositions.
See issue #2327
-/
registerEqnsInfo preDef recArgPos
mapError (addNonRec preDefNonRec (applyAttrAfterCompilation := false)) fun msg =>
m!"structural recursion failed, produced type incorrect term{indentD msg}"
addAndCompilePartialRec #[preDef]

View File

@@ -208,11 +208,18 @@ def mkEqns (declName : Name) (info : EqnInfo) : MetaM (Array Name) :=
builtin_initialize eqnInfoExt : MapDeclarationExtension EqnInfo mkMapDeclarationExtension
def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name) (fixedPrefixSize : Nat) : CoreM Unit := do
let declNames := preDefs.map (·.declName)
modifyEnv fun env =>
preDefs.foldl (init := env) fun env preDef =>
eqnInfoExt.insert env preDef.declName { preDef with declNames, declNameNonRec, fixedPrefixSize }
def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name) (fixedPrefixSize : Nat) : MetaM Unit := do
/-
See issue #2327.
Remark: we could do better for mutual declarations that mix theorems and definitions. However, this is a rare
combination, and we would have add support for it in the equation generator. I did not check which assumptions are made there.
-/
unless preDefs.all fun p => p.kind.isTheorem do
unless ( preDefs.allM fun p => isProp p.type) do
let declNames := preDefs.map (·.declName)
modifyEnv fun env =>
preDefs.foldl (init := env) fun env preDef =>
eqnInfoExt.insert env preDef.declName { preDef with declNames, declNameNonRec, fixedPrefixSize }
def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
if let some info := eqnInfoExt.find? ( getEnv) declName then

View File

@@ -6,6 +6,7 @@ Authors: Leonardo de Moura, Sebastian Ullrich
import Lean.Meta.Tactic.Generalize
import Lean.Meta.Check
import Lean.Meta.Tactic.Intro
import Lean.Elab.Binders
import Lean.Elab.Tactic.ElabTerm
import Lean.Elab.Tactic.Location
@@ -14,15 +15,27 @@ open Meta
@[builtin_tactic Lean.Parser.Tactic.generalize] def evalGeneralize : Tactic := fun stx =>
withMainContext do
let args stx[1].getSepArgs.mapM fun arg => do
let hName? := if arg[0].isNone then none else some arg[0][0].getId
let mut xIdents := #[]
let mut hIdents := #[]
let mut args := #[]
for arg in stx[1].getSepArgs do
let hName? if arg[0].isNone then
pure none
else
hIdents := hIdents.push arg[0][0]
pure (some arg[0][0].getId)
let expr elabTerm arg[1] none
return { hName?, expr, xName? := arg[3].getId : GeneralizeArg }
xIdents := xIdents.push arg[3]
args := args.push { hName?, expr, xName? := arg[3].getId : GeneralizeArg }
let hyps match expandOptLocation stx[2] with
| .targets hyps _ => getFVarIds hyps
| .wildcard => pure ( getLCtx).getFVarIds
liftMetaTactic fun mvarId => do
let (_, _, mvarId) mvarId.generalizeHyp args hyps
return [mvarId]
let mvarId getMainGoal
mvarId.withContext do
let (_, newVars, mvarId) mvarId.generalizeHyp args hyps
mvarId.withContext do
for v in newVars, id in xIdents ++ hIdents do
Term.addLocalVarInfo id (.fvar v)
replaceMainGoal [mvarId]
end Lean.Elab.Tactic

View File

@@ -11,20 +11,16 @@ import Lean.Elab.Tactic.Config
namespace Lean.Elab.Tactic
open Meta
def rewriteTarget (stx : Syntax) (symm : Bool) (config : Rewrite.Config) : TacticM Unit := do
Term.withSynthesize <| withMainContext do
let e elabTerm stx none true
let r ( getMainGoal).rewrite ( getMainTarget) e symm (config := config)
let mvarId' ( getMainGoal).replaceTargetEq r.eNew r.eqProof
replaceMainGoal (mvarId' :: r.mvarIds)
def rewriteTarget (e : Expr) (symm : Bool) (config : Rewrite.Config) : TacticM Unit := do
let r ( getMainGoal).rewrite ( getMainTarget) e symm (config := config)
let mvarId' ( getMainGoal).replaceTargetEq r.eNew r.eqProof
replaceMainGoal (mvarId' :: r.mvarIds)
def rewriteLocalDecl (stx : Syntax) (symm : Bool) (fvarId : FVarId) (config : Rewrite.Config) : TacticM Unit := do
Term.withSynthesize <| withMainContext do
let e elabTerm stx none true
let localDecl fvarId.getDecl
let rwResult ( getMainGoal).rewrite localDecl.type e symm (config := config)
let replaceResult ( getMainGoal).replaceLocalDecl fvarId rwResult.eNew rwResult.eqProof
replaceMainGoal (replaceResult.mvarId :: rwResult.mvarIds)
def rewriteLocalDecl (e : Expr) (symm : Bool) (fvarId : FVarId) (config : Rewrite.Config) : TacticM Unit := do
let localDecl fvarId.getDecl
let rwResult ( getMainGoal).rewrite localDecl.type e symm (config := config)
let replaceResult ( getMainGoal).replaceLocalDecl fvarId rwResult.eNew rwResult.eqProof
replaceMainGoal (replaceResult.mvarId :: rwResult.mvarIds)
def withRWRulesSeq (token : Syntax) (rwRulesSeqStx : Syntax) (x : (symm : Bool) (term : Syntax) TacticM Unit) : TacticM Unit := do
let lbrak := rwRulesSeqStx[0]
@@ -62,9 +58,11 @@ declare_config_elab elabRewriteConfig Rewrite.Config
let cfg elabRewriteConfig stx[1]
let loc := expandOptLocation stx[3]
withRWRulesSeq stx[0] stx[2] fun symm term => do
withLocation loc
(rewriteLocalDecl term symm · cfg)
(rewriteTarget term symm cfg)
(throwTacticEx `rewrite · "did not find instance of the pattern in the current goal")
Term.withSynthesize <| withMainContext do
let e elabTerm term none true
withLocation loc
(rewriteLocalDecl e symm · cfg)
(rewriteTarget e symm cfg)
(throwTacticEx `rewrite · "did not find instance of the pattern in the current goal")
end Lean.Elab.Tactic

View File

@@ -8,11 +8,18 @@ import Lean.Meta.Closure
namespace Lean.Meta
namespace AbstractNestedProofs
def getLambdaBody (e : Expr) : Expr :=
match e with
| .lam _ _ b _ => getLambdaBody b
| _ => e
def isNonTrivialProof (e : Expr) : MetaM Bool := do
if !( isProof e) then
pure false
else
e.withApp fun f args =>
-- We consider proofs such as `fun x => f x a` as trivial.
-- For example, we don't want to abstract the body of `def rfl`
(getLambdaBody e).withApp fun f args =>
pure $ !f.isAtomic || args.any fun arg => !arg.isAtomic
structure Context where
@@ -31,7 +38,7 @@ private def mkAuxLemma (e : Expr) : M Expr := do
/- We turn on zeta-expansion to make sure we don't need to perform an expensive `check` step to
identify which let-decls can be abstracted. If we design a more efficient test, we can avoid the eager zeta expasion step.
It a benchmark created by @selsam, The extra `check` step was a bottleneck. -/
mkAuxDefinitionFor lemmaName e (zeta := true)
mkAuxTheoremFor lemmaName e (zeta := true)
partial def visit (e : Expr) : M Expr := do
if e.isAtomic then

View File

@@ -366,4 +366,39 @@ def mkAuxDefinitionFor (name : Name) (value : Expr) (zeta : Bool := false) : Met
let type := type.headBeta
mkAuxDefinition name type value (zeta := zeta)
/--
Create an auxiliary theorem with the given name, type and value. It is similar to `mkAuxDefinition`.
-/
def mkAuxTheorem (name : Name) (type : Expr) (value : Expr) (zeta : Bool := false) : MetaM Expr := do
let result Closure.mkValueTypeClosure type value zeta
let env getEnv
let decl :=
if env.hasUnsafe result.type || env.hasUnsafe result.value then
-- `result` contains unsafe code, thus we cannot use a theorem.
Declaration.defnDecl {
name
levelParams := result.levelParams.toList
type := result.type
value := result.value
hints := ReducibilityHints.opaque
safety := DefinitionSafety.unsafe
}
else
Declaration.thmDecl {
name
levelParams := result.levelParams.toList
type := result.type
value := result.value
}
addDecl decl
return mkAppN (mkConst name result.levelArgs.toList) result.exprArgs
/--
Similar to `mkAuxTheorem`, but infers the type of `value`.
-/
def mkAuxTheoremFor (name : Name) (value : Expr) (zeta : Bool := false) : MetaM Expr := do
let type inferType value
let type := type.headBeta
mkAuxTheorem name type value zeta
end Lean.Meta

View File

@@ -182,6 +182,31 @@ private partial def isNumeral (e : Expr) : Bool :=
else if fName == ``Nat.zero && e.getAppNumArgs == 0 then true
else false
private partial def toNatLit? (e : Expr) : Option Literal :=
if isNumeral e then
if let some n := loop e then
some (.natVal n)
else
none
else
none
where
loop (e : Expr) : OptionT Id Nat := do
let f := e.getAppFn
match f with
| .lit (.natVal n) => return n
| .const fName .. =>
if fName == ``Nat.succ && e.getAppNumArgs == 1 then
let r loop e.appArg!
return r+1
else if fName == ``OfNat.ofNat && e.getAppNumArgs == 3 then
loop (e.getArg! 1)
else if fName == ``Nat.zero && e.getAppNumArgs == 0 then
return 0
else
failure
| _ => failure
private def isNatType (e : Expr) : MetaM Bool :=
return ( whnf e).isConstOf ``Nat
@@ -207,16 +232,14 @@ private def isOffset (fName : Name) (e : Expr) : MetaM Bool := do
TODO: add hook for users adding their own functions for controlling `shouldAddAsStar`
Different `DiscrTree` users may populate this set using, for example, attributes.
Remark: we currently tag `Nat.zero` and "offset" terms to avoid having to add special
support for `Expr.lit` and offset terms.
Remark: we currently tag "offset" terms as star to avoid having to add special
support for offset terms.
Example, suppose the discrimination tree contains the entry
`Nat.succ ?m |-> v`, and we are trying to retrieve the matches for `Expr.lit (Literal.natVal 1) _`.
In this scenario, we want to retrieve `Nat.succ ?m |-> v` -/
In this scenario, we want to retrieve `Nat.succ ?m |-> v`
-/
private def shouldAddAsStar (fName : Name) (e : Expr) : MetaM Bool := do
if fName == ``Nat.zero then
return true
else
isOffset fName e
isOffset fName e
def mkNoindexAnnotation (e : Expr) : Expr :=
mkAnnotation `noindex e
@@ -313,9 +336,12 @@ private def pushArgs (root : Bool) (todo : Array Expr) (e : Expr) : MetaM (Key s
let todo pushArgsAux info.paramInfo (nargs-1) e todo
return (k, todo)
match fn with
| .lit v => return (.lit v, todo)
| .const c _ =>
| .lit v =>
return (.lit v, todo)
| .const c _ =>
unless root do
if let some v := toNatLit? e then
return (.lit v, todo)
if ( shouldAddAsStar c e) then
return (.star, todo)
let nargs := e.getAppNumArgs
@@ -376,8 +402,24 @@ private partial def createNodes (keys : Array (Key s)) (v : α) (i : Nat) : Trie
else
.node #[v] #[]
/--
If `vs` contains an element `v'` such that `v == v'`, then replace `v'` with `v`.
Otherwise, push `v`.
See issue #2155
Recall that `BEq α` may not be Lawful.
-/
private def insertVal [BEq α] (vs : Array α) (v : α) : Array α :=
if vs.contains v then vs else vs.push v
loop 0
where
loop (i : Nat) : Array α :=
if h : i < vs.size then
if v == vs[i] then
vs.set i,h v
else
loop (i+1)
else
vs.push v
termination_by loop i => vs.size - i
private partial def insertAux [BEq α] (keys : Array (Key s)) (v : α) : Nat Trie α s Trie α s
| i, .node vs cs =>
@@ -410,6 +452,10 @@ def insert [BEq α] (d : DiscrTree α s) (e : Expr) (v : α) : MetaM (DiscrTree
private def getKeyArgs (e : Expr) (isMatch root : Bool) : MetaM (Key s × Array Expr) := do
let e reduceDT e root (simpleReduce := s)
unless root do
-- See pushArgs
if let some v := toNatLit? e then
return (.lit v, #[])
match e.getAppFn with
| .lit v => return (.lit v, #[])
| .const c _ =>

View File

@@ -158,9 +158,13 @@ def mkInjectiveTheorems (declName : Name) : MetaM Unit := do
-- See https://github.com/leanprover/lean4/issues/2188
withLCtx {} {} do
for ctor in info.ctors do
let ctorVal getConstInfoCtor ctor
if ctorVal.numFields > 0 then
mkInjectiveTheorem ctorVal
mkInjectiveEqTheorem ctorVal
withTraceNode `Meta.injective (fun _ => return m!"{ctor}") do
let ctorVal getConstInfoCtor ctor
if ctorVal.numFields > 0 then
mkInjectiveTheorem ctorVal
mkInjectiveEqTheorem ctorVal
builtin_initialize
registerTraceClass `Meta.injective
end Lean.Meta

View File

@@ -73,7 +73,7 @@ structure Instances where
def addInstanceEntry (d : Instances) (e : InstanceEntry) : Instances :=
match e.globalName? with
| some n => { d with discrTree := d.discrTree.insertCore e.keys e, instanceNames := d.instanceNames.insert n e }
| some n => { d with discrTree := d.discrTree.insertCore e.keys e, instanceNames := d.instanceNames.insert n e, erased := d.erased.erase n }
| none => { d with discrTree := d.discrTree.insertCore e.keys e }
def Instances.eraseCore (d : Instances) (declName : Name) : Instances :=

View File

@@ -471,42 +471,43 @@ register_builtin_option genSizeOf : Bool := {
register_builtin_option genSizeOfSpec : Bool := {
defValue := true
descr := "generate `SizeOf` specificiation theorems for automatically generated instances"
descr := "generate `SizeOf` specification theorems for automatically generated instances"
}
def mkSizeOfInstances (typeName : Name) : MetaM Unit := do
if ( getEnv).contains ``SizeOf && genSizeOf.get ( getOptions) && !( isInductivePredicate typeName) then
let indInfo getConstInfoInduct typeName
unless indInfo.isUnsafe do
let (fns, recMap) mkSizeOfFns typeName
for indTypeName in indInfo.all, fn in fns do
let indInfo getConstInfoInduct indTypeName
forallTelescopeReducing indInfo.type fun xs _ =>
let params := xs[:indInfo.numParams]
withInstImplicitAsImplict params do
let indices := xs[indInfo.numParams:]
mkLocalInstances params fun localInsts => do
let us := indInfo.levelParams.map mkLevelParam
let indType := mkAppN (mkConst indTypeName us) xs
let sizeOfIndType mkAppM ``SizeOf #[indType]
withLocalDeclD `m indType fun m => do
let v mkLambdaFVars #[m] <| mkAppN (mkConst fn us) (params ++ localInsts ++ indices ++ #[m])
let sizeOfMk mkAppM ``SizeOf.mk #[v]
let instDeclName := indTypeName ++ `_sizeOf_inst
let instDeclType mkForallFVars (xs ++ localInsts) sizeOfIndType
let instDeclValue mkLambdaFVars (xs ++ localInsts) sizeOfMk
trace[Meta.sizeOf] ">> {instDeclName} : {instDeclType}"
addDecl <| Declaration.defnDecl {
name := instDeclName
levelParams := indInfo.levelParams
type := instDeclType
value := instDeclValue
safety := .safe
hints := .abbrev
}
addInstance instDeclName AttributeKind.global (eval_prio default)
if genSizeOfSpec.get ( getOptions) then
mkSizeOfSpecTheorems indInfo.all.toArray fns recMap
withTraceNode `Meta.sizeOf (fun _ => return m!"{typeName}") do
let indInfo getConstInfoInduct typeName
unless indInfo.isUnsafe do
let (fns, recMap) mkSizeOfFns typeName
for indTypeName in indInfo.all, fn in fns do
let indInfo getConstInfoInduct indTypeName
forallTelescopeReducing indInfo.type fun xs _ =>
let params := xs[:indInfo.numParams]
withInstImplicitAsImplict params do
let indices := xs[indInfo.numParams:]
mkLocalInstances params fun localInsts => do
let us := indInfo.levelParams.map mkLevelParam
let indType := mkAppN (mkConst indTypeName us) xs
let sizeOfIndType mkAppM ``SizeOf #[indType]
withLocalDeclD `m indType fun m => do
let v mkLambdaFVars #[m] <| mkAppN (mkConst fn us) (params ++ localInsts ++ indices ++ #[m])
let sizeOfMk mkAppM ``SizeOf.mk #[v]
let instDeclName := indTypeName ++ `_sizeOf_inst
let instDeclType mkForallFVars (xs ++ localInsts) sizeOfIndType
let instDeclValue mkLambdaFVars (xs ++ localInsts) sizeOfMk
trace[Meta.sizeOf] ">> {instDeclName} : {instDeclType}"
addDecl <| Declaration.defnDecl {
name := instDeclName
levelParams := indInfo.levelParams
type := instDeclType
value := instDeclValue
safety := .safe
hints := .abbrev
}
addInstance instDeclName AttributeKind.global (eval_prio default)
if genSizeOfSpec.get ( getOptions) then
mkSizeOfSpecTheorems indInfo.all.toArray fns recMap
builtin_initialize
registerTraceClass `Meta.sizeOf

View File

@@ -27,6 +27,11 @@ structure ApplyConfig where
-/
synthAssignedInstances := true
/--
If `allowSynthFailures` is `true`, then `apply` will return instance implicit arguments
for which typeclass search failed as new goals.
-/
allowSynthFailures := false
/--
If `approx := true`, then we turn on `isDefEq` approximations. That is, we use
the `approxDefEq` combinator.
-/
@@ -47,15 +52,18 @@ def getExpectedNumArgs (e : Expr) : MetaM Nat := do
private def throwApplyError {α} (mvarId : MVarId) (eType : Expr) (targetType : Expr) : MetaM α :=
throwTacticEx `apply mvarId m!"failed to unify{indentExpr eType}\nwith{indentExpr targetType}"
def synthAppInstances (tacticName : Name) (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo) (synthAssignedInstances : Bool) : MetaM Unit :=
def synthAppInstances (tacticName : Name) (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo)
(synthAssignedInstances : Bool) (allowSynthFailures : Bool) : MetaM Unit :=
newMVars.size.forM fun i => do
if binderInfos[i]!.isInstImplicit then
let mvar := newMVars[i]!
if synthAssignedInstances || !( mvar.mvarId!.isAssigned) then
let mvarType inferType mvar
let mvarVal synthInstance mvarType
unless ( isDefEq mvar mvarVal) do
throwTacticEx tacticName mvarId "failed to assign synthesized instance"
try
let mvarVal synthInstance mvarType
unless ( isDefEq mvar mvarVal) do
throwTacticEx tacticName mvarId "failed to assign synthesized instance"
catch e => unless allowSynthFailures do throw e
def appendParentTag (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo) : MetaM Unit := do
let parentTag mvarId.getTag
@@ -76,8 +84,9 @@ If `synthAssignedInstances` is `true`, then `apply` will synthesize instance imp
even if they have assigned by `isDefEq`, and then check whether the synthesized value matches the
one inferred. The `congr` tactic sets this flag to false.
-/
def postprocessAppMVars (tacticName : Name) (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo) (synthAssignedInstances := true) : MetaM Unit := do
synthAppInstances tacticName mvarId newMVars binderInfos synthAssignedInstances
def postprocessAppMVars (tacticName : Name) (mvarId : MVarId) (newMVars : Array Expr) (binderInfos : Array BinderInfo)
(synthAssignedInstances := true) (allowSynthFailures := false) : MetaM Unit := do
synthAppInstances tacticName mvarId newMVars binderInfos synthAssignedInstances allowSynthFailures
-- TODO: default and auto params
appendParentTag mvarId newMVars binderInfos
@@ -163,7 +172,7 @@ def _root_.Lean.MVarId.apply (mvarId : MVarId) (e : Expr) (cfg : ApplyConfig :=
let (_, _, eType) forallMetaTelescopeReducing eType (some rangeNumArgs.start)
throwApplyError mvarId eType targetType
let (newMVars, binderInfos) go rangeNumArgs.start
postprocessAppMVars `apply mvarId newMVars binderInfos cfg.synthAssignedInstances
postprocessAppMVars `apply mvarId newMVars binderInfos cfg.synthAssignedInstances cfg.allowSynthFailures
let e instantiateMVars e
mvarId.assign (mkAppN e newMVars)
let newMVars newMVars.filterM fun mvar => not <$> mvar.mvarId!.isAssigned

View File

@@ -155,12 +155,24 @@ private def toCtorWhenStructure (inductName : Name) (major : Expr) : MetaM Expr
return result
| _ => return major
-- Helper predicate that returns `true` for inductive predicates used to define functions by well-founded recursion.
private def isWFRec (declName : Name) : Bool :=
declName == ``Acc.rec || declName == ``WellFounded.rec
/-- Auxiliary function for reducing recursor applications. -/
private def reduceRec (recVal : RecursorVal) (recLvls : List Level) (recArgs : Array Expr) (failK : Unit MetaM α) (successK : Expr MetaM α) : MetaM α :=
let majorIdx := recVal.getMajorIdx
if h : majorIdx < recArgs.size then do
let major := recArgs.get majorIdx, h
let mut major whnf major
let mut major if isWFRec recVal.name && ( getTransparency) == TransparencyMode.default then
-- If recursor is `Acc.rec` or `WellFounded.rec` and transparency is default,
-- then we bump transparency to .all to make sure we can unfold defs defined by WellFounded recursion.
-- We use this trick because we abstract nested proofs occurring in definitions.
-- Alternative design: do not abstract nested proofs used to justify well-founded recursion.
withTransparency .all <| whnf major
else
whnf major
if recVal.k then
major toCtorWhenK recVal major
major := major.toCtorIfLit
@@ -302,7 +314,7 @@ end
| .lam .. => return e
| .sort .. => return e
| .lit .. => return e
| .bvar .. => unreachable!
| .bvar .. => panic! "loose bvar in expression"
| .letE .. => k e
| .const .. => k e
| .app .. => k e
@@ -708,7 +720,8 @@ mutual
if smartUnfolding.get ( getOptions) && ( getEnv).contains (mkSmartUnfoldingNameFor declName) then
return none
else
let (some (cinfo@(ConstantInfo.defnInfo _))) getConstNoEx? declName | pure none
let some cinfo getConstNoEx? declName | pure none
unless cinfo.hasValue do return none
deltaDefinition cinfo lvls
(fun _ => pure none)
(fun e => pure (some e))

View File

@@ -750,18 +750,18 @@ partial def identFnAux (startPos : String.Pos) (tk : Option Token) (r : Name) :
parse r c s
else
mkIdResult startPos tk r c s
else if isIdFirst curr then
let startPart := i
let s := takeWhileFn isIdRest c (s.next input i)
let stopPart := s.pos
let r := .str r (input.extract startPart stopPart)
if isIdCont input s then
let s := s.next input s.pos
parse r c s
else if isIdFirst curr then
let startPart := i
let s := takeWhileFn isIdRest c (s.next input i)
let stopPart := s.pos
let r := .str r (input.extract startPart stopPart)
if isIdCont input s then
let s := s.next input s.pos
parse r c s
else
mkIdResult startPos tk r c s
else
mkIdResult startPos tk r c s
else
mkTokenAndFixPos startPos tk c s
mkTokenAndFixPos startPos tk c s
parse r
private def isIdFirstOrBeginEscape (c : Char) : Bool :=

View File

@@ -177,7 +177,7 @@ inductive AliasValue (α : Type) where
abbrev AliasTable (α) := NameMap (AliasValue α)
def registerAliasCore {α} (mapRef : IO.Ref (AliasTable α)) (aliasName : Name) (value : AliasValue α) : IO Unit := do
unless ( IO.initializing) do throw "aliases can only be registered during initialization"
unless ( initializing) do throw "aliases can only be registered during initialization"
if ( mapRef.get).contains aliasName then
throw s!"alias '{aliasName}' has already been declared"
mapRef.modify (·.insert aliasName value)

View File

@@ -49,7 +49,7 @@ def makePopup : WithRpcRef InfoWithCtx → RequestM (RequestTask InfoPopup)
| i => RequestM.asTask do
i.ctx.runMetaM i.info.lctx do
let type? match ( i.info.type?) with
| some type => some <$> ppExprTagged type
| some type => some <$> (ppExprTagged =<< instantiateMVars type)
| none => pure none
let exprExplicit? match i.info with
| Elab.Info.ofTermInfo ti =>

View File

@@ -93,7 +93,7 @@ def registerBuiltinRpcProcedure (method : Name) paramType respType
[RpcEncodable paramType] [RpcEncodable respType]
(handler : paramType RequestM (RequestTask respType)) : IO Unit := do
let errMsg := s!"Failed to register builtin RPC call handler for '{method}'"
unless ( IO.initializing) do
unless ( initializing) do
throw <| IO.userError s!"{errMsg}: only possible during initialization"
if (builtinRpcProcedures.get).contains method then
throw <| IO.userError s!"{errMsg}: already registered"

View File

@@ -210,6 +210,9 @@ section ServerM
-- If writeLspMessage from above errors we will block here, but the main task will
-- quit eventually anyways if that happens
let exitCode fw.proc.wait
-- Remove surviving descendant processes, if any, such as from nested builds.
-- On Windows, we instead rely on elan doing this.
try fw.proc.kill catch _ => pure ()
match exitCode with
| 0 =>
-- Worker was terminated
@@ -241,6 +244,8 @@ section ServerM
toStdioConfig := workerCfg
cmd := st.workerPath.toString
args := #["--worker"] ++ st.args.toArray ++ #[m.uri]
-- open session for `kill` above
setsid := true
}
let pendingRequestsRef IO.mkRef (RBMap.empty : PendingRequestMap)
-- The task will never access itself, so this is fine

View File

@@ -11,7 +11,13 @@ namespace Lean
/-- A position of a subexpression in an expression.
See docstring of `SubExpr` for more detail.-/
We use a simple encoding scheme for expression positions `Pos`:
every `Expr` constructor has at most 3 direct expression children. Considering an expression's type
to be one extra child as well, we can injectively map a path of `childIdxs` to a natural number
by computing the value of the 4-ary representation `1 :: childIdxs`, since n-ary representations
without leading zeros are unique. Note that `pos` is initialized to `1` (case `childIdxs == []`).
See also `SubExpr`. -/
def SubExpr.Pos := Nat
namespace SubExpr.Pos
@@ -145,18 +151,12 @@ instance : FromJson Pos := ⟨fun j => fromJson? j >>= Pos.fromString?⟩
end SubExpr.Pos
/-- An expression and the position of a subexpression within this expression.
Subexpressions are encoded as the current subexpression `e` and a
position `p : Pos` denoting `e`'s position with respect to the root expression.
We use a simple encoding scheme for expression positions `Pos`:
every `Expr` constructor has at most 3 direct expression children. Considering an expression's type
to be one extra child as well, we can injectively map a path of `childIdxs` to a natural number
by computing the value of the 4-ary representation `1 :: childIdxs`, since n-ary representations
without leading zeros are unique. Note that `pos` is initialized to `1` (case `childIdxs == []`).-/
/-- A subexpression of some root expression. Both its value and its position
within the root are stored. -/
structure SubExpr where
/-- The subexpression. -/
expr : Expr
/-- The position of the subexpression within the root expression. -/
pos : SubExpr.Pos
deriving Inhabited
@@ -164,7 +164,7 @@ namespace SubExpr
def mkRoot (e : Expr) : SubExpr := e, Pos.root
/-- Returns true if the selected subexpression is the topmost one.-/
/-- Returns true if the selected subexpression is the topmost one. -/
def isRoot (s : SubExpr) : Bool := s.pos.isRoot
/-- Map from subexpr positions to values. -/

View File

@@ -198,26 +198,29 @@ If `nFields` is set, we take that many fields from the end and keep the remainin
as one name. For example, `` `foo.bla.boo `` with `(nFields := 1)` ↦ `` [`foo.bla, `boo] ``. -/
def identComponents (stx : Syntax) (nFields? : Option Nat := none) : List Syntax :=
match stx with
| ident (SourceInfo.original lead pos trail _) rawStr val _ =>
| ident si@(SourceInfo.original lead pos trail _) rawStr val _ => Id.run do
let val := val.eraseMacroScopes
-- With original info, we assume that `rawStr` represents `val`.
let nameComps := nameComps val nFields?
let rawComps := splitNameLit rawStr
let rawComps :=
if let some nFields := nFields? then
let nPrefix := rawComps.length - nFields
let prefixSz := rawComps.take nPrefix |>.foldl (init := 0) fun acc (ss : Substring) => acc + ss.bsize + 1
let prefixSz := prefixSz - 1 -- The last component has no dot
rawStr.extract 0 prefixSz :: rawComps.drop nPrefix
else
rawComps
assert! nameComps.length == rawComps.length
nameComps.zip rawComps |>.map fun (id, ss) =>
let off := ss.startPos - rawStr.startPos
let lead := if off == 0 then lead else "".toSubstring
let trail := if ss.stopPos == rawStr.stopPos then trail else "".toSubstring
let info := original lead (pos + off) trail (pos + off + ss.bsize)
ident info ss id []
if !rawComps.isEmpty then
let rawComps :=
if let some nFields := nFields? then
let nPrefix := rawComps.length - nFields
let prefixSz := rawComps.take nPrefix |>.foldl (init := 0) fun acc (ss : Substring) => acc + ss.bsize + 1
let prefixSz := prefixSz - 1 -- The last component has no dot
rawStr.extract 0 prefixSz :: rawComps.drop nPrefix
else
rawComps
if nameComps.length == rawComps.length then
return nameComps.zip rawComps |>.map fun (id, ss) =>
let off := ss.startPos - rawStr.startPos
let lead := if off == 0 then lead else "".toSubstring
let trail := if ss.stopPos == rawStr.stopPos then trail else "".toSubstring
let info := original lead (pos + off) trail (pos + off + ss.bsize)
ident info ss id []
-- if re-parsing failed, just give them all the same span
nameComps.map fun n => ident si n.toString.toSubstring n []
| ident si _ val _ =>
let val := val.eraseMacroScopes
/- With non-original info:

View File

@@ -4,52 +4,36 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Expr
import Lean.Util.PtrSet
namespace Lean
namespace Expr
namespace FindImpl
abbrev cacheSize : USize := 8192 - 1
unsafe abbrev FindM := StateT (PtrSet Expr) Id
structure State where
keys : Array Expr -- Remark: our "unsafe" implementation relies on the fact that `()` is not a valid Expr
@[inline] unsafe def checkVisited (e : Expr) : OptionT FindM Unit := do
if ( get).contains e then
failure
modify fun s => s.insert e
abbrev FindM := StateT State Id
unsafe def visited (e : Expr) (size : USize) : FindM Bool := do
let s get
let h := ptrAddrUnsafe e
let i := h % size
let k := s.keys.uget i lcProof
if ptrAddrUnsafe k == h then
pure true
else
modify fun s => { keys := s.keys.uset i e lcProof }
pure false
unsafe def findM? (p : Expr Bool) (size : USize) (e : Expr) : OptionT FindM Expr :=
unsafe def findM? (p : Expr Bool) (e : Expr) : OptionT FindM Expr :=
let rec visit (e : Expr) := do
if ( visited e size) then
failure
else if p e then
checkVisited e
if p e then
pure e
else match e with
| Expr.forallE _ d b _ => visit d <|> visit b
| Expr.lam _ d b _ => visit d <|> visit b
| Expr.mdata _ b => visit b
| Expr.letE _ t v b _ => visit t <|> visit v <|> visit b
| Expr.app f a => visit f <|> visit a
| Expr.proj _ _ b => visit b
| _ => failure
| .forallE _ d b _ => visit d <|> visit b
| .lam _ d b _ => visit d <|> visit b
| .mdata _ b => visit b
| .letE _ t v b _ => visit t <|> visit v <|> visit b
| .app f a => visit f <|> visit a
| .proj _ _ b => visit b
| _ => failure
visit e
unsafe def initCache : State :=
{ keys := mkArray cacheSize.toNat (cast lcProof ()) }
unsafe def findUnsafe? (p : Expr Bool) (e : Expr) : Option Expr :=
Id.run <| findM? p cacheSize e |>.run' initCache
Id.run <| findM? p e |>.run' mkPtrSet
end FindImpl
@@ -59,13 +43,13 @@ def find? (p : Expr → Bool) (e : Expr) : Option Expr :=
if p e then
some e
else match e with
| Expr.forallE _ d b _ => find? p d <|> find? p b
| Expr.lam _ d b _ => find? p d <|> find? p b
| Expr.mdata _ b => find? p b
| Expr.letE _ t v b _ => find? p t <|> find? p v <|> find? p b
| Expr.app f a => find? p f <|> find? p a
| Expr.proj _ _ b => find? p b
| _ => none
| .forallE _ d b _ => find? p d <|> find? p b
| .lam _ d b _ => find? p d <|> find? p b
| .mdata _ b => find? p b
| .letE _ t v b _ => find? p t <|> find? p v <|> find? p b
| .app f a => find? p f <|> find? p a
| .proj _ _ b => find? p b
| _ => none
/-- Return true if `e` occurs in `t` -/
def occurs (e : Expr) (t : Expr) : Bool :=
@@ -81,32 +65,31 @@ inductive FindStep where
namespace FindExtImpl
unsafe def findM? (p : Expr FindStep) (size : USize) (e : Expr) : OptionT FindImpl.FindM Expr :=
unsafe def findM? (p : Expr FindStep) (e : Expr) : OptionT FindImpl.FindM Expr :=
visit e
where
visitApp (e : Expr) :=
match e with
| Expr.app f a .. => visitApp f <|> visit a
| .app f a .. => visitApp f <|> visit a
| e => visit e
visit (e : Expr) := do
if ( FindImpl.visited e size) then
failure
else match p e with
| FindStep.done => failure
| FindStep.found => pure e
| FindStep.visit =>
FindImpl.checkVisited e
match p e with
| .done => failure
| .found => pure e
| .visit =>
match e with
| Expr.forallE _ d b _ => visit d <|> visit b
| Expr.lam _ d b _ => visit d <|> visit b
| Expr.mdata _ b => visit b
| Expr.letE _ t v b _ => visit t <|> visit v <|> visit b
| Expr.app .. => visitApp e
| Expr.proj _ _ b => visit b
| _ => failure
| .forallE _ d b _ => visit d <|> visit b
| .lam _ d b _ => visit d <|> visit b
| .mdata _ b => visit b
| .letE _ t v b _ => visit t <|> visit v <|> visit b
| .app .. => visitApp e
| .proj _ _ b => visit b
| _ => failure
unsafe def findUnsafe? (p : Expr FindStep) (e : Expr) : Option Expr :=
Id.run <| findM? p FindImpl.cacheSize e |>.run' FindImpl.initCache
Id.run <| findM? p e |>.run' mkPtrSet
end FindExtImpl

34
src/Lean/Util/PtrSet.lean Normal file
View File

@@ -0,0 +1,34 @@
/-
Copyright (c) 2023 Leonardo de Moura. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.Data.HashSet
namespace Lean
structure Ptr (α : Type u) where
value : α
unsafe instance : Hashable (Ptr α) where
hash a := hash64 (ptrAddrUnsafe a).toUInt64
unsafe instance : BEq (Ptr α) where
beq a b := ptrAddrUnsafe a == ptrAddrUnsafe b
/--
Set of pointers. It is a low-level auxiliary datastructure used for traversing DAGs.
-/
unsafe def PtrSet (α : Type) :=
HashSet (Ptr α)
unsafe def mkPtrSet {α : Type} (capacity : Nat := 64) : PtrSet α :=
mkHashSet capacity
unsafe abbrev PtrSet.insert (s : PtrSet α) (a : α) : PtrSet α :=
HashSet.insert s { value := a }
unsafe abbrev PtrSet.contains (s : PtrSet α) (a : α) : Bool :=
HashSet.contains s { value := a }
end Lean

View File

@@ -193,7 +193,7 @@ def withTraceNode [MonadExcept ε m] [MonadLiftT BaseIO m] (cls : Name) (msg : E
modifyTraces (oldTraces ++ ·)
return ( MonadExcept.ofExcept res)
let ref getRef
let mut m msg res
let mut m try msg res catch _ => pure m!"<exception thrown while producing trace node message>"
if profiler.get opts || aboveThresh then
m := m!"[{secs}s] {m}"
addTraceNode oldTraces cls ref m collapsed

View File

@@ -17,8 +17,8 @@ Author: Leonardo de Moura
#include "initialize/init.h"
namespace lean {
extern "C" object* initialize_Init(object* w);
extern "C" object* initialize_Lean(object* w);
extern "C" object* initialize_Init(uint8_t, object* w);
extern "C" object* initialize_Lean(uint8_t, object* w);
/* Initializes the Lean runtime. Before executing any code which uses the Lean package,
you must first call this function, and then `lean::io_mark_end_initialization`. Inbetween
@@ -26,8 +26,9 @@ these two calls, you may also have to run additional initializers for your own m
extern "C" LEAN_EXPORT void lean_initialize() {
save_stack_info();
initialize_util_module();
consume_io_result(initialize_Init(io_mk_world()));
consume_io_result(initialize_Lean(io_mk_world()));
uint8_t builtin = 1;
consume_io_result(initialize_Init(builtin, io_mk_world()));
consume_io_result(initialize_Lean(builtin, io_mk_world()));
initialize_kernel_module();
init_default_print_fn();
initialize_library_core_module();

View File

@@ -29,6 +29,7 @@ static expr * g_nat_succ = nullptr;
static expr * g_nat_add = nullptr;
static expr * g_nat_sub = nullptr;
static expr * g_nat_mul = nullptr;
static expr * g_nat_pow = nullptr;
static expr * g_nat_mod = nullptr;
static expr * g_nat_div = nullptr;
static expr * g_nat_beq = nullptr;
@@ -601,6 +602,7 @@ optional<expr> type_checker::reduce_nat(expr const & e) {
if (f == *g_nat_add) return reduce_bin_nat_op(nat_add, e);
if (f == *g_nat_sub) return reduce_bin_nat_op(nat_sub, e);
if (f == *g_nat_mul) return reduce_bin_nat_op(nat_mul, e);
if (f == *g_nat_pow) return reduce_bin_nat_op(nat_pow, e);
if (f == *g_nat_mod) return reduce_bin_nat_op(nat_mod, e);
if (f == *g_nat_div) return reduce_bin_nat_op(nat_div, e);
if (f == *g_nat_beq) return reduce_bin_nat_pred(nat_eq, e);
@@ -1146,6 +1148,8 @@ void initialize_type_checker() {
mark_persistent(g_nat_sub->raw());
g_nat_mul = new expr(mk_constant(name{"Nat", "mul"}));
mark_persistent(g_nat_mul->raw());
g_nat_pow = new expr(mk_constant(name{"Nat", "pow"}));
mark_persistent(g_nat_pow->raw());
g_nat_div = new expr(mk_constant(name{"Nat", "div"}));
mark_persistent(g_nat_div->raw());
g_nat_mod = new expr(mk_constant(name{"Nat", "mod"}));
@@ -1171,6 +1175,7 @@ void finalize_type_checker() {
delete g_nat_add;
delete g_nat_sub;
delete g_nat_mul;
delete g_nat_pow;
delete g_nat_div;
delete g_nat_mod;
delete g_nat_beq;

Submodule src/lake deleted from 2e5aad4a78

1
src/lake/.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.sh text eol=lf

72
src/lake/.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,72 @@
name: CI
on: [ push, pull_request ]
jobs:
skip_check:
name: Skip Check
continue-on-error: true
runs-on: ubuntu-latest
outputs:
should_skip: ${{ steps.skip_check.outputs.should_skip }}
steps:
- id: skip_check
uses: fkirc/skip-duplicate-actions@v4
with:
concurrent_skipping: 'same_content_newer'
paths_ignore: '["README.md", "LICENSE"]'
build:
needs: skip_check
name: ${{ matrix.name || 'Build' }}
if: ${{ needs.skip_check.outputs.should_skip != 'true' }}
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.shell || 'sh' }}
strategy:
matrix:
include:
- name: Ubuntu
os: ubuntu-latest
- name: MacOS
os: macos-latest
- name: Windows
os: windows-latest
shell: msys2 {0}
# complete all jobs
fail-fast: false
steps:
- name: Install MSYS2 (Windows)
if: matrix.os == 'windows-latest'
uses: msys2/setup-msys2@v2
with:
path-type: inherit
install: curl unzip make diffutils mingw-w64-x86_64-gcc mingw-w64-x86_64-gmp
- name: Install Elan
shell: bash -euo pipefail {0}
run: |
curl -sSfL https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh | sh -s -- -y --default-toolchain none
echo "$HOME/.elan/bin" >> $GITHUB_PATH
- name: Checkout
uses: actions/checkout@v2
- name: Check Lean
run: lean --version
- name: Build & Time
run: ./time.sh -j4
- name: Upload Build
continue-on-error: true
uses: actions/upload-artifact@v2
with:
name: ${{ matrix.os }}
path: build
- name: Check Lake
run: make check-lake
- name: Test Lake
run: make test-ci
- name: Time Bootstrap
run: make time-bootstrap
- name: Check Bootstrap
run: make check-bootstrap
- name: Test Bootstrapped Lake
run: make test-bootstrapped -j4

5
src/lake/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/build
produced.out
result*
# Do not commit the flake lockfile to avoid having to maintain it
flake.lock

70
src/lake/LICENSE Normal file
View File

@@ -0,0 +1,70 @@
Apache License 2.0 (Apache)
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
2. You must cause any modified files to carry prominent notices stating that You changed the files; and
3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.

10
src/lake/Lake.lean Normal file
View File

@@ -0,0 +1,10 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build
import Lake.Config
import Lake.DSL
import Lake.Version
import Lake.CLI.Actions

12
src/lake/Lake/Build.lean Normal file
View File

@@ -0,0 +1,12 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Monad
import Lake.Build.Actions
import Lake.Build.Index
import Lake.Build.Module
import Lake.Build.Package
import Lake.Build.Library
import Lake.Build.Imports

View File

@@ -0,0 +1,123 @@
/-
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Sebastian Ullrich, Mac Malone
-/
import Lake.Util.Proc
import Lake.Util.NativeLib
import Lake.Build.Context
namespace Lake
open System
def createParentDirs (path : FilePath) : IO Unit := do
if let some dir := path.parent then IO.FS.createDirAll dir
def compileLeanModule (name : String) (leanFile : FilePath)
(oleanFile? ileanFile? cFile? : Option FilePath)
(leanPath : SearchPath := []) (rootDir : FilePath := ".")
(dynlibs : Array FilePath := #[]) (dynlibPath : SearchPath := {})
(leanArgs : Array String := #[]) (lean : FilePath := "lean")
: BuildM Unit := do
logStep s!"Building {name}"
let mut args := leanArgs ++
#[leanFile.toString, "-R", rootDir.toString]
if let some oleanFile := oleanFile? then
createParentDirs oleanFile
args := args ++ #["-o", oleanFile.toString]
if let some ileanFile := ileanFile? then
createParentDirs ileanFile
args := args ++ #["-i", ileanFile.toString]
if let some cFile := cFile? then
createParentDirs cFile
args := args ++ #["-c", cFile.toString]
for dynlib in dynlibs do
args := args.push s!"--load-dynlib={dynlib}"
proc {
args
cmd := lean.toString
env := #[
("LEAN_PATH", leanPath.toString),
(sharedLibPathEnvVar, ( getSearchPath sharedLibPathEnvVar) ++ dynlibPath |>.toString)
]
}
def compileO (name : String) (oFile srcFile : FilePath)
(moreArgs : Array String := #[]) (compiler : FilePath := "cc") : BuildM Unit := do
logStep s!"Compiling {name}"
createParentDirs oFile
proc {
cmd := compiler.toString
args := #["-c", "-o", oFile.toString, srcFile.toString] ++ moreArgs
}
def compileStaticLib (name : String) (libFile : FilePath)
(oFiles : Array FilePath) (ar : FilePath := "ar") : BuildM Unit := do
logStep s!"Creating {name}"
createParentDirs libFile
proc {
cmd := ar.toString
args := #["rcs", libFile.toString] ++ oFiles.map toString
}
def compileSharedLib (name : String) (libFile : FilePath)
(linkArgs : Array String) (linker : FilePath := "cc") : BuildM Unit := do
logStep s!"Linking {name}"
createParentDirs libFile
proc {
cmd := linker.toString
args := #["-shared", "-o", libFile.toString] ++ linkArgs
}
def compileExe (name : String) (binFile : FilePath) (linkFiles : Array FilePath)
(linkArgs : Array String := #[]) (linker : FilePath := "cc") : BuildM Unit := do
logStep s!"Linking {name}"
createParentDirs binFile
proc {
cmd := linker.toString
args := #["-o", binFile.toString] ++ linkFiles.map toString ++ linkArgs
}
/-- Download a file using `curl`, clobbering any existing file. -/
def download (name : String) (url : String) (file : FilePath) : LogIO PUnit := do
logInfo s!"Downloading {name}"
if ( file.pathExists) then
IO.FS.removeFile file
else
createParentDirs file
let args :=
if ( getIsVerbose) then #[] else #["-s"]
proc (quiet := true) {
cmd := "curl"
args := args ++ #["-f", "-o", file.toString, "-L", url]
}
/-- Unpack an archive `file` using `tar` into the directory `dir`. -/
def untar (name : String) (file : FilePath) (dir : FilePath) (gzip := true) : LogIO PUnit := do
logInfo s!"Unpacking {name}"
let mut opts := "-x"
if ( getIsVerbose) then
opts := opts.push 'v'
if gzip then
opts := opts.push 'z'
proc {
cmd := "tar",
args := #[opts, "-f", file.toString, "-C", dir.toString]
}
/-- Pack a directory `dir` using `tar` into the archive `file`. -/
def tar (name : String) (dir : FilePath) (file : FilePath)
(gzip := true) (excludePaths : Array FilePath := #[]) : LogIO PUnit := do
logInfo s!"Packing {name}"
createParentDirs file
let mut args := #["-c"]
if gzip then
args := args.push "-z"
if ( getIsVerbose) then
args := args.push "-v"
for path in excludePaths do
args := args.push s!"--exclude={path}"
proc {
cmd := "tar"
args := args ++ #["-f", file.toString, "-C", dir.toString, "."]
}

View File

@@ -0,0 +1,118 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Job
import Lake.Build.Actions
import Lake.Build.Monad
open System
namespace Lake
/-! # General Utilities -/
@[inline] def inputFile (path : FilePath) : SchedulerM (BuildJob FilePath) :=
Job.async <| (path, ·) <$> computeTrace path
@[inline] def buildUnlessUpToDate [CheckExists ι] [GetMTime ι] (info : ι)
(depTrace : BuildTrace) (traceFile : FilePath) (build : JobM PUnit) : JobM PUnit := do
let isOldMode getIsOldMode
let upToDate
if isOldMode then
depTrace.checkAgainstTime info
else
depTrace.checkAgainstFile info traceFile
unless upToDate do
build
unless isOldMode do
depTrace.writeToFile traceFile
@[inline] def buildFileUnlessUpToDate (file : FilePath)
(depTrace : BuildTrace) (build : BuildM PUnit) : BuildM BuildTrace := do
let traceFile := FilePath.mk <| file.toString ++ ".trace"
buildUnlessUpToDate file depTrace traceFile build
computeTrace file
@[inline] def buildFileAfterDep
(file : FilePath) (dep : BuildJob α) (build : α BuildM PUnit)
(extraDepTrace : BuildM _ := pure BuildTrace.nil) : SchedulerM (BuildJob FilePath) :=
dep.bindSync fun depInfo depTrace => do
let depTrace := depTrace.mix ( extraDepTrace)
let trace buildFileUnlessUpToDate file depTrace <| build depInfo
return (file, trace)
@[inline] def buildFileAfterDepList
(file : FilePath) (deps : List (BuildJob α)) (build : List α BuildM PUnit)
(extraDepTrace : BuildM _ := pure BuildTrace.nil) : SchedulerM (BuildJob FilePath) := do
buildFileAfterDep file ( BuildJob.collectList deps) build extraDepTrace
@[inline] def buildFileAfterDepArray
(file : FilePath) (deps : Array (BuildJob α)) (build : Array α BuildM PUnit)
(extraDepTrace : BuildM _ := pure BuildTrace.nil) : SchedulerM (BuildJob FilePath) := do
buildFileAfterDep file ( BuildJob.collectArray deps) build extraDepTrace
/-! # Common Builds -/
def buildO (name : String)
(oFile : FilePath) (srcJob : BuildJob FilePath)
(args : Array String := #[]) (compiler : FilePath := "cc") : SchedulerM (BuildJob FilePath) :=
buildFileAfterDep oFile srcJob (extraDepTrace := computeHash args) fun srcFile => do
compileO name oFile srcFile args compiler
def buildLeanO (name : String)
(oFile : FilePath) (srcJob : BuildJob FilePath)
(args : Array String := #[]) : SchedulerM (BuildJob FilePath) :=
buildFileAfterDep oFile srcJob (extraDepTrace := computeHash args) fun srcFile => do
compileO name oFile srcFile args ( getLeanc)
def buildStaticLib (libFile : FilePath)
(oFileJobs : Array (BuildJob FilePath)) : SchedulerM (BuildJob FilePath) :=
let name := libFile.fileName.getD libFile.toString
buildFileAfterDepArray libFile oFileJobs fun oFiles => do
compileStaticLib name libFile oFiles ( getLeanAr)
def buildLeanSharedLib
(libFile : FilePath) (linkJobs : Array (BuildJob FilePath))
(linkArgs : Array String := #[]) : SchedulerM (BuildJob FilePath) :=
let name := libFile.fileName.getD libFile.toString
buildFileAfterDepArray libFile linkJobs
(extraDepTrace := computeHash linkArgs) fun links => do
compileSharedLib name libFile (links.map toString ++ linkArgs) ( getLeanc)
def buildLeanExe
(exeFile : FilePath) (linkJobs : Array (BuildJob FilePath))
(linkArgs : Array String := #[]) : SchedulerM (BuildJob FilePath) :=
let name := exeFile.fileName.getD exeFile.toString
buildFileAfterDepArray exeFile linkJobs
(extraDepTrace := computeHash linkArgs) fun links => do
compileExe name exeFile links linkArgs ( getLeanc)
def buildLeanSharedLibOfStatic (staticLibJob : BuildJob FilePath)
(linkArgs : Array String := #[]) : SchedulerM (BuildJob FilePath) :=
staticLibJob.bindSync fun staticLib staticTrace => do
let dynlib := staticLib.withExtension sharedLibExt
let baseArgs :=
if System.Platform.isOSX then
#[s!"-Wl,-force_load,{staticLib}"]
else
#["-Wl,--whole-archive", staticLib.toString, "-Wl,--no-whole-archive"]
let args := baseArgs ++ linkArgs
let depTrace := staticTrace.mix ( computeHash args)
let trace buildFileUnlessUpToDate dynlib depTrace do
let name := dynlib.fileName.getD dynlib.toString
compileSharedLib name dynlib args ( getLeanc)
return (dynlib, trace)
def computeDynlibOfShared
(sharedLibTarget : BuildJob FilePath) : SchedulerM (BuildJob Dynlib) :=
sharedLibTarget.bindSync fun sharedLib trace => do
if let some stem := sharedLib.fileStem then
if Platform.isWindows then
return ({path := sharedLib, name := stem}, trace)
else if stem.startsWith "lib" then
return ({path := sharedLib, name := stem.drop 3}, trace)
else
error s!"shared library `{sharedLib}` does not start with `lib`; this is not supported on Unix"
else
error s!"shared library `{sharedLib}` has no file name"

View File

@@ -0,0 +1,58 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Util.Log
import Lake.Util.Task
import Lake.Util.Error
import Lake.Util.OptionIO
import Lake.Config.Context
import Lake.Build.Trace
import Lake.Build.Store
import Lake.Build.Topological
open System
namespace Lake
/-- A Lake context with some additional caching for builds. -/
structure BuildContext extends Context where
leanTrace : BuildTrace
oldMode : Bool := false
startedBuilds : IO.Ref Nat
finishedBuilds : IO.Ref Nat
/-- A transformer to equip a monad with a `BuildContext`. -/
abbrev BuildT := ReaderT BuildContext
/-- The monad for the Lake build manager. -/
abbrev SchedulerM := BuildT <| LogT BaseIO
/-- The core monad for Lake builds. -/
abbrev BuildM := BuildT LogIO
/-- A transformer to equip a monad with a Lake build store. -/
abbrev BuildStoreT := StateT BuildStore
/-- A Lake build cycle. -/
abbrev BuildCycle := Cycle BuildKey
/-- A transformer for monads that may encounter a build cycle. -/
abbrev BuildCycleT := CycleT BuildKey
/-- A recursive build of a Lake build store that may encounter a cycle. -/
abbrev RecBuildM := BuildCycleT <| BuildStoreT BuildM
instance [Pure m] : MonadLift LakeM (BuildT m) where
monadLift x := fun ctx => pure <| x.run ctx.toContext
@[inline] def BuildM.run (ctx : BuildContext) (self : BuildM α) : LogIO α :=
self ctx
def BuildM.catchFailure (f : Unit BaseIO α) (self : BuildM α) : SchedulerM α :=
fun ctx logMethods => self ctx logMethods |>.catchFailure f
def logStep (message : String) : BuildM Unit := do
let done ( read).finishedBuilds.get
let started ( read).startedBuilds.get
logInfo s!"[{done}/{started}] {message}"

View File

@@ -0,0 +1,131 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Key
import Lake.Util.Family
open Lean
namespace Lake
--------------------------------------------------------------------------------
/-! ## Build Data Subtypes -/
--------------------------------------------------------------------------------
/--
The open type family which maps a module facet's name to its build data
in the Lake build store. For example, a transitive × direct import pair
for the `lean.imports` facet or an active build target for `lean.c`.
It is an open type, meaning additional mappings can be add lazily
as needed (via `module_data`).
-/
opaque ModuleData (facet : Name) : Type
/--
The open type family which maps a package facet's name to its build data
in the Lake build store. For example, a transitive dependencies of the package
for the facet `deps`.
It is an open type, meaning additional mappings can be add lazily
as needed (via `package_data`).
-/
opaque PackageData (facet : Name) : Type
/--
The open type family which maps a (builtin) Lake target's (e.g., `extern_lib`)
facet to its associated build data. For example, an active build target for
the `externLib.static` facet.
It is an open type, meaning additional mappings can be add lazily
as needed (via `target_data`).
-/
opaque TargetData (facet : Name) : Type
/-
The open type family which maps a library facet's name to its build data
in the Lake build store. For example, an active build target for the `static`
facet.
It is an open type, meaning additional mappings can be add lazily
as needed (via `library_data`).
-/
abbrev LibraryData (facet : Name) := TargetData (`leanLib ++ facet)
instance [h : FamilyOut LibraryData facet α] : FamilyDef TargetData (`leanLib ++ facet) α :=
by simp [h.family_key_eq_type]
instance [h : FamilyOut TargetData (`leanLib ++ facet) α] : FamilyDef LibraryData facet α :=
h.family_key_eq_type
/--
The open type family which maps a custom target (package × target name) to
its build data in the Lake build store.
It is an open type, meaning additional mappings can be add lazily
as needed (via `custom_data`).
-/
opaque CustomData (target : Name × Name) : Type
--------------------------------------------------------------------------------
/-! ## Build Data -/
--------------------------------------------------------------------------------
/--
A mapping between a build key and its associated build data in the store.
It is a simple type function composed of the separate open type families for
modules facets, package facets, Lake target facets, and custom targets.
-/
abbrev BuildData : BuildKey Type
| .moduleFacet _ f => ModuleData f
| .packageFacet _ f => PackageData f
| .targetFacet _ _ f => TargetData f
| .customTarget p t => CustomData (p, t)
instance (priority := low) : FamilyDef BuildData (.moduleFacet m f) (ModuleData f) := rfl
instance (priority := low) : FamilyDef BuildData (.packageFacet p f) (PackageData f) := rfl
instance (priority := low) : FamilyDef BuildData (.targetFacet p t f) (TargetData f) := rfl
instance (priority := low) : FamilyDef BuildData (.customTarget p t) (CustomData (p,t)) := rfl
--------------------------------------------------------------------------------
/-! ## Macros for Declaring Build Data -/
--------------------------------------------------------------------------------
/-- Macro for declaring new `PackageData`. -/
scoped macro (name := packageDataDecl) doc?:optional(Parser.Command.docComment)
"package_data " id:ident " : " ty:term : command => do
let dty := mkCIdentFrom ( getRef) ``PackageData
let key := Name.quoteFrom id id.getId
`($[$doc?]? family_def $id : $dty $key := $ty)
/-- Macro for declaring new `ModuleData`. -/
scoped macro (name := moduleDataDecl) doc?:optional(Parser.Command.docComment)
"module_data " id:ident " : " ty:term : command => do
let dty := mkCIdentFrom ( getRef) ``ModuleData
let key := Name.quoteFrom id id.getId
`($[$doc?]? family_def $id : $dty $key := $ty)
/-- Macro for declaring new `TargetData` for libraries. -/
scoped macro (name := libraryDataDecl) doc?:optional(Parser.Command.docComment)
"library_data " id:ident " : " ty:term : command => do
let dty := mkCIdentFrom ( getRef) ``TargetData
let key := Name.quoteFrom id id.getId
let id := mkIdentFrom id <| id.getId.modifyBase (`leanLib ++ ·)
`($[$doc?]? family_def $id : $dty (`leanLib ++ $key) := $ty)
/-- Macro for declaring new `TargetData`. -/
scoped macro (name := targetDataDecl) doc?:optional(Parser.Command.docComment)
"target_data " id:ident " : " ty:term : command => do
let dty := mkCIdentFrom ( getRef) ``TargetData
let key := Name.quoteFrom id id.getId
`($[$doc?]? family_def $id : $dty $key := $ty)
/-- Macro for declaring new `CustomData`. -/
scoped macro (name := customDataDecl) doc?:optional(Parser.Command.docComment)
"custom_data " pkg:ident tgt:ident " : " ty:term : command => do
let dty := mkCIdentFrom ( getRef) ``CustomData
let id := mkIdentFrom tgt (pkg.getId ++ tgt.getId)
let pkg := Name.quoteFrom pkg pkg.getId
let tgt := Name.quoteFrom pkg tgt.getId
`($[$doc?]? family_def $id : $dty ($pkg, $tgt) := $ty)

View File

@@ -0,0 +1,34 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Common
namespace Lake
/-- Get the Lean executable in the workspace with the configuration's name. -/
@[inline] def LeanExeConfig.get (self : LeanExeConfig)
[Monad m] [MonadError m] [MonadLake m] : m LeanExe := do
let some exe findLeanExe? self.name
| error "Lean executable '{self.name}' does not exist in the workspace"
return exe
/-- Fetch the build of the Lean executable. -/
@[inline] def LeanExeConfig.fetch
(self : LeanExeConfig) : IndexBuildM (BuildJob FilePath) := do
( self.get).exe.fetch
/-! # Build Executable -/
protected def LeanExe.recBuildExe
(self : LeanExe) : IndexBuildM (BuildJob FilePath) := do
let imports self.root.transImports.fetch
let mut linkJobs := #[ self.root.o.fetch]
for mod in imports do for facet in mod.nativeFacets do
linkJobs := linkJobs.push <| fetch <| mod.facet facet.name
let deps := ( fetch <| self.pkg.facet `deps).push self.pkg
for dep in deps do for lib in dep.externLibs do
linkJobs := linkJobs.push <| lib.static.fetch
buildLeanExe self.file linkJobs self.linkArgs

View File

@@ -0,0 +1,126 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Job
import Lake.Build.Data
/-!
# Simple Builtin Facet Declarations
This module contains the definitions of most of the builtin facets.
The others are defined `Build.Info`. The facets there require configuration
definitions (e.g., `Module`), and some of the facets here are used in said
definitions.
-/
namespace Lake
export System (SearchPath FilePath)
/-- A dynamic/shared library for linking. -/
structure Dynlib where
/-- Library file path. -/
path : FilePath
/-- Library name without platform-specific prefix/suffix (for `-l`). -/
name : String
/-- Optional library directory (for `-L`). -/
def Dynlib.dir? (self : Dynlib) : Option FilePath :=
self.path.parent
/-! ## Module Facets -/
/-- A module facet name along with proof of its data type. -/
structure ModuleFacet (α) where
/-- The name of the module facet. -/
name : Name
/-- Proof that module's facet build result is of type α. -/
data_eq : ModuleData name = α
deriving Repr
instance (facet : ModuleFacet α) : FamilyDef ModuleData facet.name α :=
facet.data_eq
instance [FamilyOut ModuleData facet α] : CoeDep Name facet (ModuleFacet α) :=
facet, FamilyOut.family_key_eq_type
/--
The facet which builds all of a module's dependencies
(i.e., transitive local imports and `--load-dynlib` shared libraries).
Returns the list of shared libraries to load along with their search path.
-/
abbrev Module.depsFacet := `deps
module_data deps : BuildJob (SearchPath × Array FilePath)
/--
The core compilation / elaboration of the Lean file via `lean`,
which produce the Lean binaries of the module (i.e., `olean`, `ilean`, `c`).
Its trace just includes its dependencies.
-/
abbrev Module.leanBinFacet := `bin
module_data bin : BuildJob Unit
/--
The `leanBinFacet` combined with the module's trace
(i.e., the trace of its `olean` and `ilean`).
It is the facet used for building a Lean import of a module.
-/
abbrev Module.importBinFacet := `importBin
module_data importBin : BuildJob Unit
/-- The `olean` file produced by `lean` -/
abbrev Module.oleanFacet := `olean
module_data olean : BuildJob FilePath
/-- The `ilean` file produced by `lean` -/
abbrev Module.ileanFacet := `ilean
module_data ilean : BuildJob FilePath
/-- The C file built from the Lean file via `lean` -/
abbrev Module.cFacet := `c
module_data c : BuildJob FilePath
/-- The object file built from `lean.c` -/
abbrev Module.oFacet := `o
module_data o : BuildJob FilePath
/-! ## Package Facets -/
/-- The package's cloud build release. -/
abbrev Package.releaseFacet := `release
package_data release : BuildJob Unit
/-- The package's `extraDepTarget` mixed with its transitive dependencies'. -/
abbrev Package.extraDepFacet := `extraDep
package_data extraDep : BuildJob Unit
/-! ## Target Facets -/
/-- A Lean library's Lean libraries. -/
abbrev LeanLib.leanFacet := `lean
library_data lean : BuildJob Unit
/-- A Lean library's static binary. -/
abbrev LeanLib.staticFacet := `static
library_data static : BuildJob FilePath
/-- A Lean library's shared binary. -/
abbrev LeanLib.sharedFacet := `shared
library_data shared : BuildJob FilePath
/-- A Lean binary executable. -/
abbrev LeanExe.exeFacet := `leanExe
target_data leanExe : BuildJob FilePath
/-- A external library's static binary. -/
abbrev ExternLib.staticFacet := `externLib.static
target_data externLib.static : BuildJob FilePath
/-- A external library's shared binary. -/
abbrev ExternLib.sharedFacet := `externLib.shared
target_data externLib.shared : BuildJob FilePath
/-- A external library's dynlib. -/
abbrev ExternLib.dynlibFacet := `externLib.dynlib
target_data externLib.dynlib : BuildJob Dynlib

View File

@@ -0,0 +1,70 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Index
/-!
Definitions to support `lake print-paths` builds.
-/
open System
namespace Lake
/--
Construct an `Array` of `Module`s for the workspace-local modules of
a `List` of import strings.
-/
def Workspace.processImportList
(imports : List String) (self : Workspace) : Array Module := Id.run do
let mut localImports := #[]
for imp in imports do
if let some mod := self.findModule? imp.toName then
localImports := localImports.push mod
return localImports
/--
Recursively build a set of imported modules and return their build jobs,
the build jobs of their precompiled modules and the build jobs of said modules'
external libraries.
-/
def recBuildImports (imports : Array Module)
: IndexBuildM (Array (BuildJob Unit) × Array (BuildJob Dynlib) × Array (BuildJob Dynlib)) := do
let mut modJobs := #[]
let mut precompileImports := OrdModuleSet.empty
for mod in imports do
if mod.shouldPrecompile then
precompileImports := precompileImports.appendArray ( mod.transImports.fetch) |>.insert mod
else
precompileImports := precompileImports.appendArray ( mod.precompileImports.fetch)
modJobs := modJobs.push <| mod.leanBin.fetch
let pkgs := precompileImports.foldl (·.insert ·.pkg) OrdPackageSet.empty |>.toArray
let externJobs pkgs.concatMapM (·.externLibs.mapM (·.dynlib.fetch))
let precompileJobs precompileImports.toArray.mapM (·.dynlib.fetch)
return (modJobs, precompileJobs, externJobs)
/--
Builds the workspace-local modules of list of imports.
Used by `lake print-paths` to build modules for the Lean server.
Returns the set of module dynlibs built (so they can be loaded by the server).
Builds only module `.olean` and `.ilean` files if the package is configured
as "Lean-only". Otherwise, also builds `.c` files.
-/
def buildImportsAndDeps (imports : List String) : BuildM (Array FilePath) := do
let ws getWorkspace
if imports.isEmpty then
-- build the package's (and its dependencies') `extraDepTarget`
ws.root.extraDep.build >>= (·.materialize)
return #[]
else
-- build local imports from list
let mods := ws.processImportList imports
let (modJobs, precompileJobs, externLibJobs)
recBuildImports mods |>.run.run
modJobs.forM (·.await)
let modLibs precompileJobs.mapM (·.await <&> (·.path))
let externLibs externLibJobs.mapM (·.await <&> (·.path))
-- NOTE: Lean wants the external library symbols before module symbols
return externLibs ++ modLibs

View File

@@ -0,0 +1,108 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Executable
import Lake.Build.Topological
/-!
# The Lake Build Index
The Lake build index is the complete map of Lake build keys to
Lake build functions, which is used by Lake to build any Lake build info.
This module leverages the index to perform topologically-based recursive builds.
-/
open Lean
namespace Lake
/--
Converts a conveniently typed target facet build function into its
dynamically typed equivalent.
-/
@[macro_inline] def mkTargetFacetBuild (facet : Name) (build : IndexBuildM α)
[h : FamilyOut TargetData facet α] : IndexBuildM (TargetData facet) :=
cast (by rw [ h.family_key_eq_type]) build
def ExternLib.recBuildStatic (lib : ExternLib) : IndexBuildM (BuildJob FilePath) := do
lib.config.getJob <$> fetch (lib.pkg.target lib.staticTargetName)
def ExternLib.recBuildShared (lib : ExternLib) : IndexBuildM (BuildJob FilePath) := do
buildLeanSharedLibOfStatic ( lib.static.fetch) lib.linkArgs
def ExternLib.recComputeDynlib (lib : ExternLib) : IndexBuildM (BuildJob Dynlib) := do
computeDynlibOfShared ( lib.shared.fetch)
/-!
## Topologically-based Recursive Build Using the Index
-/
/-- Recursive build function for anything in the Lake build index. -/
def recBuildWithIndex : (info : BuildInfo) IndexBuildM (BuildData info.key)
| .moduleFacet mod facet => do
if let some config := ( getWorkspace).findModuleFacetConfig? facet then
config.build mod
else
error s!"do not know how to build module facet `{facet}`"
| .packageFacet pkg facet => do
if let some config := ( getWorkspace).findPackageFacetConfig? facet then
config.build pkg
else
error s!"do not know how to build package facet `{facet}`"
| .target pkg target =>
if let some config := pkg.findTargetConfig? target then
config.build pkg
else
error s!"could not build `{target}` of `{pkg.name}` -- target not found"
| .libraryFacet lib facet => do
if let some config := ( getWorkspace).findLibraryFacetConfig? facet then
config.build lib
else
error s!"do not know how to build library facet `{facet}`"
| .leanExe exe =>
mkTargetFacetBuild LeanExe.exeFacet exe.recBuildExe
| .staticExternLib lib =>
mkTargetFacetBuild ExternLib.staticFacet lib.recBuildStatic
| .sharedExternLib lib =>
mkTargetFacetBuild ExternLib.sharedFacet lib.recBuildShared
| .dynlibExternLib lib =>
mkTargetFacetBuild ExternLib.dynlibFacet lib.recComputeDynlib
/--
Run the given recursive build using the Lake build index
and a topological / suspending scheduler.
-/
def IndexBuildM.run (build : IndexBuildM α) : RecBuildM α :=
build <| recFetchMemoize BuildInfo.key recBuildWithIndex
/--
Recursively build the given info using the Lake build index
and a topological / suspending scheduler.
-/
def buildIndexTop' (info : BuildInfo) : RecBuildM (BuildData info.key) :=
recFetchMemoize BuildInfo.key recBuildWithIndex info
/--
Recursively build the given info using the Lake build index
and a topological / suspending scheduler and return the dynamic result.
-/
@[macro_inline] def buildIndexTop (info : BuildInfo)
[FamilyOut BuildData info.key α] : RecBuildM α := do
cast (by simp) <| buildIndexTop' info
/-- Build the given Lake target in a fresh build store. -/
@[inline] def BuildInfo.build
(self : BuildInfo) [FamilyOut BuildData self.key α] : BuildM α :=
buildIndexTop self |>.run
export BuildInfo (build)
/-! ### Lean Executable Builds -/
@[inline] protected def LeanExe.build (self : LeanExe) : BuildM (BuildJob FilePath) :=
self.exe.build
@[inline] protected def LeanExe.fetch (self : LeanExe) : IndexBuildM (BuildJob FilePath) :=
self.exe.fetch

View File

@@ -0,0 +1,269 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Config.LeanExe
import Lake.Config.ExternLib
import Lake.Build.Facets
import Lake.Util.EquipT
/-!
# Build Info
This module defines the Lake build info type and related utilities.
Build info is what is the data passed to a Lake build function to facilitate
the build.
-/
namespace Lake
/-- The type of Lake's build info. -/
inductive BuildInfo
| moduleFacet (module : Module) (facet : Name)
| packageFacet (package : Package) (facet : Name)
| libraryFacet (lib : LeanLib) (facet : Name)
| leanExe (exe : LeanExe)
| staticExternLib (lib : ExternLib)
| sharedExternLib (lib : ExternLib)
| dynlibExternLib (lib : ExternLib)
| target (package : Package) (target : Name)
--------------------------------------------------------------------------------
/-! ## Build Info & Keys -/
--------------------------------------------------------------------------------
/-! ### Build Key Helper Constructors -/
abbrev Module.facetBuildKey (facet : Name) (self : Module) : BuildKey :=
.moduleFacet self.keyName facet
abbrev Package.facetBuildKey (facet : Name) (self : Package) : BuildKey :=
.packageFacet self.name facet
abbrev Package.targetBuildKey (target : Name) (self : Package) : BuildKey :=
.customTarget self.name target
abbrev LeanLib.facetBuildKey (self : LeanLib) (facet : Name) : BuildKey :=
.targetFacet self.pkg.name self.name (`leanLib ++ facet)
abbrev LeanExe.buildKey (self : LeanExe) : BuildKey :=
.targetFacet self.pkg.name self.name exeFacet
abbrev ExternLib.staticBuildKey (self : ExternLib) : BuildKey :=
.targetFacet self.pkg.name self.name staticFacet
abbrev ExternLib.sharedBuildKey (self : ExternLib) : BuildKey :=
.targetFacet self.pkg.name self.name sharedFacet
abbrev ExternLib.dynlibBuildKey (self : ExternLib) : BuildKey :=
.targetFacet self.pkg.name self.name dynlibFacet
/-! ### Build Info to Key -/
/-- The key that identifies the build in the Lake build store. -/
abbrev BuildInfo.key : (self : BuildInfo) BuildKey
| moduleFacet m f => m.facetBuildKey f
| packageFacet p f => p.facetBuildKey f
| libraryFacet l f => l.facetBuildKey f
| leanExe x => x.buildKey
| staticExternLib l => l.staticBuildKey
| sharedExternLib l => l.sharedBuildKey
| dynlibExternLib l => l.dynlibBuildKey
| target p t => p.targetBuildKey t
/-! ### Instances for deducing data types of `BuildInfo` keys -/
instance [FamilyOut ModuleData f α]
: FamilyDef BuildData (BuildInfo.key (.moduleFacet m f)) α where
family_key_eq_type := by unfold BuildData; simp
instance [FamilyOut PackageData f α]
: FamilyDef BuildData (BuildInfo.key (.packageFacet p f)) α where
family_key_eq_type := by unfold BuildData; simp
instance (priority := low) {p : NPackage n} : FamilyDef BuildData
(.customTarget p.toPackage.name t) (CustomData (n,t)) := by simp
instance {p : NPackage n} [FamilyOut CustomData (n, t) α]
: FamilyDef BuildData (BuildInfo.key (.target p.toPackage t)) α where
family_key_eq_type := by unfold BuildData; simp
instance [FamilyOut TargetData (`leanLib ++ f) α]
: FamilyDef BuildData (BuildInfo.key (.libraryFacet l f)) α where
family_key_eq_type := by unfold BuildData; simp
instance [FamilyOut TargetData LeanExe.exeFacet α]
: FamilyDef BuildData (BuildInfo.key (.leanExe x)) α where
family_key_eq_type := by unfold BuildData; simp
instance [FamilyOut TargetData ExternLib.staticFacet α]
: FamilyDef BuildData (BuildInfo.key (.staticExternLib l)) α where
family_key_eq_type := by unfold BuildData; simp
instance [FamilyOut TargetData ExternLib.sharedFacet α]
: FamilyDef BuildData (BuildInfo.key (.sharedExternLib l)) α where
family_key_eq_type := by unfold BuildData; simp
instance [FamilyOut TargetData ExternLib.dynlibFacet α]
: FamilyDef BuildData (BuildInfo.key (.dynlibExternLib l)) α where
family_key_eq_type := by unfold BuildData; simp
--------------------------------------------------------------------------------
/-! ## Recursive Building -/
--------------------------------------------------------------------------------
/-- A build function for any element of the Lake build index. -/
abbrev IndexBuildFn (m : Type Type v) :=
-- `DBuildFn BuildInfo (BuildData ·.key) m` with less imports
(info : BuildInfo) m (BuildData info.key)
/-- A transformer to equip a monad with a build function for the Lake index. -/
abbrev IndexT (m : Type Type v) := EquipT (IndexBuildFn m) m
/-- The monad for build functions that are part of the index. -/
abbrev IndexBuildM := IndexT RecBuildM
/-- Fetch the result associated with the info using the Lake build index. -/
@[inline] def BuildInfo.fetch (self : BuildInfo) [FamilyOut BuildData self.key α] : IndexBuildM α :=
fun build => cast (by simp) <| build self
export BuildInfo (fetch)
--------------------------------------------------------------------------------
/-! ## Build Info & Facets -/
--------------------------------------------------------------------------------
/-!
### Complex Builtin Facet Declarations
Additional builtin facets missing from `Build.Facets`.
These are defined here because they need configuration definitions
(e.g., `Module`), whereas the facets there are needed by the configuration
definitions.
-/
/-- The direct local imports of the Lean module. -/
abbrev Module.importsFacet := `lean.imports
module_data lean.imports : Array Module
/-- The transitive local imports of the Lean module. -/
abbrev Module.transImportsFacet := `lean.transImports
module_data lean.transImports : Array Module
/-- The transitive local imports of the Lean module. -/
abbrev Module.precompileImportsFacet := `lean.precompileImports
module_data lean.precompileImports : Array Module
/-- Shared library for `--load-dynlib`. -/
abbrev Module.dynlibFacet := `dynlib
module_data dynlib : BuildJob Dynlib
/-- A Lean library's Lean modules. -/
abbrev LeanLib.modulesFacet := `modules
library_data modules : Array Module
/-- The package's complete array of transitive dependencies. -/
abbrev Package.depsFacet := `deps
package_data deps : Array Package
/-!
### Facet Build Info Helper Constructors
Definitions to easily construct `BuildInfo` values for module, package,
and target facets.
-/
namespace Module
/-- Build info for the module's specified facet. -/
abbrev facet (facet : Name) (self : Module) : BuildInfo :=
.moduleFacet self facet
@[inherit_doc importsFacet] abbrev imports (self : Module) :=
self.facet importsFacet
@[inherit_doc transImportsFacet] abbrev transImports (self : Module) :=
self.facet transImportsFacet
@[inherit_doc precompileImportsFacet] abbrev precompileImports (self : Module) :=
self.facet precompileImportsFacet
@[inherit_doc depsFacet] abbrev deps (self : Module) :=
self.facet depsFacet
@[inherit_doc leanBinFacet] abbrev leanBin (self : Module) :=
self.facet leanBinFacet
@[inherit_doc importBinFacet] abbrev importBin (self : Module) :=
self.facet importBinFacet
@[inherit_doc oleanFacet] abbrev olean (self : Module) :=
self.facet oleanFacet
@[inherit_doc ileanFacet] abbrev ilean (self : Module) :=
self.facet ileanFacet
@[inherit_doc cFacet] abbrev c (self : Module) :=
self.facet cFacet
@[inherit_doc oFacet] abbrev o (self : Module) :=
self.facet oFacet
@[inherit_doc dynlibFacet] abbrev dynlib (self : Module) :=
self.facet dynlibFacet
end Module
/-- Build info for the package's specified facet. -/
abbrev Package.facet (facet : Name) (self : Package) : BuildInfo :=
.packageFacet self facet
@[inherit_doc releaseFacet]
abbrev Package.release (self : Package) : BuildInfo :=
self.facet releaseFacet
@[inherit_doc extraDepFacet]
abbrev Package.extraDep (self : Package) : BuildInfo :=
self.facet extraDepFacet
/-- Build info for a custom package target. -/
abbrev Package.target (target : Name) (self : Package) : BuildInfo :=
.target self target
/-- Build info of the Lean library's Lean binaries. -/
abbrev LeanLib.facet (self : LeanLib) (facet : Name) : BuildInfo :=
.libraryFacet self facet
@[inherit_doc modulesFacet]
abbrev LeanLib.modules (self : LeanLib) : BuildInfo :=
self.facet modulesFacet
@[inherit_doc leanFacet]
abbrev LeanLib.lean (self : LeanLib) : BuildInfo :=
self.facet leanFacet
@[inherit_doc staticFacet]
abbrev LeanLib.static (self : LeanLib) : BuildInfo :=
self.facet staticFacet
@[inherit_doc sharedFacet]
abbrev LeanLib.shared (self : LeanLib) : BuildInfo :=
self.facet sharedFacet
/-- Build info of the Lean executable. -/
abbrev LeanExe.exe (self : LeanExe) : BuildInfo :=
.leanExe self
/-- Build info of the external library's static binary. -/
abbrev ExternLib.static (self : ExternLib) : BuildInfo :=
.staticExternLib self
/-- Build info of the external library's shared binary. -/
abbrev ExternLib.shared (self : ExternLib) : BuildInfo :=
.sharedExternLib self
/-- Build info of the external library's dynlib. -/
abbrev ExternLib.dynlib (self : ExternLib) : BuildInfo :=
.dynlibExternLib self

View File

@@ -0,0 +1,112 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Util.Async
import Lake.Build.Trace
import Lake.Build.Context
open System
namespace Lake
/-- A Lake job. -/
abbrev Job α := OptionIOTask α
/-- The monad of Lake jobs. -/
abbrev JobM := BuildM
/-- The monad of a finished Lake job. -/
abbrev ResultM := OptionIO
namespace Job
@[inline] def nil : Job Unit :=
pure ()
@[inline] protected def async (act : JobM α) : SchedulerM (Job α) :=
async act
@[inline] protected def await (self : Job α) : ResultM α :=
await self
@[inline] protected def bindSync
(self : Job α) (f : α JobM β) (prio := Task.Priority.default) : SchedulerM (Job β) :=
bindSync prio self f
@[inline] protected def bindAsync
(self : Job α) (f : α SchedulerM (Job β)) : SchedulerM (Job β) :=
bindAsync self f
end Job
/-- A Lake build job. -/
abbrev BuildJob α := Job (α × BuildTrace)
namespace BuildJob
@[inline] def mk (job : Job (α × BuildTrace)) : BuildJob α :=
job
@[inline] def ofJob (self : Job BuildTrace) : BuildJob Unit :=
mk <| ((), ·) <$> self
@[inline] def toJob (self : BuildJob α) : Job (α × BuildTrace) :=
self
@[inline] def nil : BuildJob Unit :=
mk <| pure ((), nilTrace)
@[inline] protected def pure (a : α) : BuildJob α :=
mk <| pure (a, nilTrace)
instance : Pure BuildJob := BuildJob.pure
@[inline] protected def map (f : α β) (self : BuildJob α) : BuildJob β :=
mk <| (fun (a,t) => (f a,t)) <$> self.toJob
instance : Functor BuildJob where
map := BuildJob.map
@[inline] def mapWithTrace (f : α BuildTrace β × BuildTrace) (self : BuildJob α) : BuildJob β :=
mk <| (fun (a,t) => f a t) <$> self.toJob
@[inline] protected def bindSync
(self : BuildJob α) (f : α BuildTrace JobM β)
(prio : Task.Priority := .default) : SchedulerM (Job β) :=
self.toJob.bindSync (prio := prio) fun (a, t) => f a t
@[inline] protected def bindAsync
(self : BuildJob α) (f : α BuildTrace SchedulerM (Job β)) : SchedulerM (Job β) :=
self.toJob.bindAsync fun (a, t) => f a t
@[inline] protected def await (self : BuildJob α) : ResultM α :=
(·.1) <$> await self.toJob
instance : Await BuildJob ResultM := BuildJob.await
@[inline] def materialize (self : BuildJob α) : ResultM Unit :=
discard <| await self.toJob
def mix (t1 : BuildJob α) (t2 : BuildJob β) : BaseIO (BuildJob Unit) :=
mk <$> seqWithAsync (fun (_,t) (_,t') => ((), mixTrace t t')) t1.toJob t2.toJob
def mixList (jobs : List (BuildJob α)) : BaseIO (BuildJob Unit) := ofJob <$> do
jobs.foldrM (init := pure nilTrace) fun j a =>
seqWithAsync (fun (_,t') t => mixTrace t t') j.toJob a
def mixArray (jobs : Array (BuildJob α)) : BaseIO (BuildJob Unit) := ofJob <$> do
jobs.foldlM (init := pure nilTrace) fun a j =>
seqWithAsync (fun t (_,t') => mixTrace t t') a j.toJob
protected def seqWithAsync
(f : α β γ) (t1 : BuildJob α) (t2 : BuildJob β) : BaseIO (BuildJob γ) :=
mk <$> seqWithAsync (fun (a,t) (b,t') => (f a b, mixTrace t t')) t1.toJob t2.toJob
instance : SeqWithAsync BaseIO BuildJob := BuildJob.seqWithAsync
def collectList (jobs : List (BuildJob α)) : BaseIO (BuildJob (List α)) :=
jobs.foldrM (seqWithAsync List.cons) (pure [])
def collectArray (jobs : Array (BuildJob α)) : BaseIO (BuildJob (Array α)) :=
jobs.foldlM (seqWithAsync Array.push) (pure #[])

View File

@@ -0,0 +1,104 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Util.Name
namespace Lake
/-- The type of keys in the Lake build store. -/
inductive BuildKey
| moduleFacet (module : Name) (facet : Name)
| packageFacet (package : Name) (facet : Name)
| targetFacet (package : Name) (target : Name) (facet : Name)
| customTarget (package : Name) (target : Name)
deriving Inhabited, Repr, DecidableEq, Hashable
namespace BuildKey
def toString : (self : BuildKey) String
| moduleFacet m f => s!"+{m}:{f}"
| packageFacet p f => s!"@{p}:{f}"
| targetFacet p t f => s!"{p}/{t}:{f}"
| customTarget p t => s!"{p}/{t}"
instance : ToString BuildKey := (·.toString)
def quickCmp (k k' : BuildKey) : Ordering :=
match k with
| moduleFacet m f =>
match k' with
| moduleFacet m' f' =>
match m.quickCmp m' with
| .eq => f.quickCmp f'
| ord => ord
| _ => .lt
| packageFacet p f =>
match k' with
| moduleFacet .. => .gt
| packageFacet p' f' =>
match p.quickCmp p' with
| .eq => f.quickCmp f'
| ord => ord
| _ => .lt
| targetFacet p t f =>
match k' with
| customTarget .. => .lt
| targetFacet p' t' f' =>
match p.quickCmp p' with
| .eq =>
match t.quickCmp t' with
| .eq => f.quickCmp f'
| ord => ord
| ord => ord
| _=> .gt
| customTarget p t =>
match k' with
| customTarget p' t' =>
match p.quickCmp p' with
| .eq => t.quickCmp t'
| ord => ord
| _ => .gt
theorem eq_of_quickCmp {k k' : BuildKey} :
quickCmp k k' = Ordering.eq k = k' := by
unfold quickCmp
cases k with
| moduleFacet m f =>
cases k'
case moduleFacet m' f' =>
dsimp only; split
next m_eq => intro f_eq; rw [eq_of_cmp m_eq, eq_of_cmp f_eq]
next => intro; contradiction
all_goals (intro; contradiction)
| packageFacet p f =>
cases k'
case packageFacet p' f' =>
dsimp only; split
next p_eq => intro f_eq; rw [eq_of_cmp p_eq, eq_of_cmp f_eq]
next => intro; contradiction
all_goals (intro; contradiction)
| targetFacet p t f =>
cases k'
case targetFacet p' t' f' =>
dsimp only; split
next p_eq =>
split
next t_eq =>
intro f_eq
rw [eq_of_cmp p_eq, eq_of_cmp t_eq, eq_of_cmp f_eq]
next => intro; contradiction
next => intro; contradiction
all_goals (intro; contradiction)
| customTarget p t =>
cases k'
case customTarget p' t' =>
dsimp only; split
next p_eq => intro t_eq; rw [eq_of_cmp p_eq, eq_of_cmp t_eq]
next => intro; contradiction
all_goals (intro; contradiction)
instance : LawfulCmpEq BuildKey quickCmp where
eq_of_cmp := eq_of_quickCmp
cmp_rfl {k} := by cases k <;> simp [quickCmp]

View File

@@ -0,0 +1,111 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Common
namespace Lake
/-- Get the Lean library in the workspace with the configuration's name. -/
@[inline] def LeanLibConfig.get (self : LeanLibConfig)
[Monad m] [MonadError m] [MonadLake m] : m LeanLib := do
let some lib findLeanLib? self.name
| error "Lean library '{self.name}' does not exist in the workspace"
return lib
/-- Fetch the build result of a library facet. -/
@[inline] protected def LibraryFacetDecl.fetch (lib : LeanLib)
(self : LibraryFacetDecl) [FamilyOut LibraryData self.name α] : IndexBuildM α := do
fetch <| lib.facet self.name
/-- Fetch the build job of a library facet. -/
def LibraryFacetConfig.fetchJob (lib : LeanLib)
(self : LibraryFacetConfig name) : IndexBuildM (BuildJob Unit) := do
let some getJob := self.getJob?
| error "library facet '{self.name}' has no associated build job"
return getJob <| fetch <| lib.facet self.name
/-- Fetch the build job of a library facet. -/
def LeanLib.fetchFacetJob
(name : Name) (self : LeanLib) : IndexBuildM (BuildJob Unit) := do
let some config := ( getWorkspace).libraryFacetConfigs.find? name
| error "library facet '{name}' does not exist in workspace"
inline <| config.fetchJob self
/-! # Build Lean & Static Lib -/
/--
Collect the local modules of a library.
That is, the modules from `getModuleArray` plus their local transitive imports.
-/
partial def LeanLib.recCollectLocalModules (self : LeanLib) : IndexBuildM (Array Module) := do
let mut mods := #[]
let mut modSet := ModuleSet.empty
for mod in ( self.getModuleArray) do
(mods, modSet) go mod mods modSet
return mods
where
go root mods modSet := do
let mut mods := mods
let mut modSet := modSet
unless modSet.contains root do
modSet := modSet.insert root
let imps root.imports.fetch
for mod in imps do
if self.isLocalModule mod.name then
(mods, modSet) go mod mods modSet
mods := mods.push root
return (mods, modSet)
/-- The `LibraryFacetConfig` for the builtin `modulesFacet`. -/
def LeanLib.modulesFacetConfig : LibraryFacetConfig modulesFacet :=
mkFacetConfig LeanLib.recCollectLocalModules
protected def LeanLib.recBuildLean
(self : LeanLib) : IndexBuildM (BuildJob Unit) := do
let mods self.modules.fetch
mods.foldlM (init := BuildJob.nil) fun job mod => do
job.mix <| mod.leanBin.fetch
/-- The `LibraryFacetConfig` for the builtin `leanFacet`. -/
def LeanLib.leanFacetConfig : LibraryFacetConfig leanFacet :=
mkFacetJobConfigSmall LeanLib.recBuildLean
protected def LeanLib.recBuildStatic
(self : LeanLib) : IndexBuildM (BuildJob FilePath) := do
let mods self.modules.fetch
let oJobs mods.concatMapM fun mod =>
mod.nativeFacets.mapM fun facet => fetch <| mod.facet facet.name
buildStaticLib self.staticLibFile oJobs
/-- The `LibraryFacetConfig` for the builtin `staticFacet`. -/
def LeanLib.staticFacetConfig : LibraryFacetConfig staticFacet :=
mkFacetJobConfig LeanLib.recBuildStatic
/-! # Build Shared Lib -/
protected def LeanLib.recBuildShared
(self : LeanLib) : IndexBuildM (BuildJob FilePath) := do
let mods self.modules.fetch
let oJobs mods.concatMapM fun mod =>
mod.nativeFacets.mapM fun facet => fetch <| mod.facet facet.name
let pkgs := mods.foldl (·.insert ·.pkg) OrdPackageSet.empty |>.toArray
let externJobs pkgs.concatMapM (·.externLibs.mapM (·.shared.fetch))
buildLeanSharedLib self.sharedLibFile (oJobs ++ externJobs) self.linkArgs
/-- The `LibraryFacetConfig` for the builtin `sharedFacet`. -/
def LeanLib.sharedFacetConfig : LibraryFacetConfig sharedFacet :=
mkFacetJobConfig LeanLib.recBuildShared
open LeanLib in
/--
A library facet name to build function map that contains builders for
the initial set of Lake library facets (e.g., `lean`, `static`, and `shared`).
-/
def initLibraryFacetConfigs : DNameMap LibraryFacetConfig :=
DNameMap.empty
|>.insert modulesFacet modulesFacetConfig
|>.insert leanFacet leanFacetConfig
|>.insert staticFacet staticFacetConfig
|>.insert sharedFacet sharedFacetConfig

View File

@@ -0,0 +1,255 @@
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich, Mac Malone
-/
import Lake.Util.OrdHashSet
import Lean.Elab.ParseImportsFast
import Lake.Build.Common
open System
namespace Lake
/-- Fetch the build result of a module facet. -/
@[inline] protected def ModuleFacetDecl.fetch (mod : Module)
(self : ModuleFacetDecl) [FamilyOut ModuleData self.name α] : IndexBuildM α := do
fetch <| mod.facet self.name
/-- Fetch the build job of a module facet. -/
def ModuleFacetConfig.fetchJob (mod : Module)
(self : ModuleFacetConfig name) : IndexBuildM (BuildJob Unit) := do
let some getJob := self.getJob?
| error "module facet '{self.name}' has no associated build job"
return getJob <| fetch <| mod.facet self.name
/-- Fetch the build job of a module facet. -/
def Module.fetchFacetJob
(name : Name) (self : Module) : IndexBuildM (BuildJob Unit) := do
let some config := ( getWorkspace).moduleFacetConfigs.find? name
| error "library facet '{name}' does not exist in workspace"
inline <| config.fetchJob self
def Module.buildUnlessUpToDate (mod : Module)
(dynlibPath : SearchPath) (dynlibs : Array FilePath)
(depTrace : BuildTrace) : BuildM PUnit := do
let isOldMode getIsOldMode
let argTrace : BuildTrace := pureHash mod.leanArgs
let srcTrace : BuildTrace computeTrace { path := mod.leanFile : TextFilePath }
let modTrace := ( getLeanTrace).mix <| argTrace.mix <| srcTrace.mix depTrace
let modUpToDate do
if isOldMode then
srcTrace.checkAgainstTime mod
else
modTrace.checkAgainstFile mod mod.traceFile
let name := mod.name.toString
unless modUpToDate do
compileLeanModule name mod.leanFile mod.oleanFile mod.ileanFile mod.cFile
( getLeanPath) mod.rootDir dynlibs dynlibPath (mod.leanArgs ++ mod.weakLeanArgs) ( getLean)
unless isOldMode do
modTrace.writeToFile mod.traceFile
/-- Compute library directories and build external library Jobs of the given packages. -/
def recBuildExternDynlibs (pkgs : Array Package)
: IndexBuildM (Array (BuildJob Dynlib) × Array FilePath) := do
let mut libDirs := #[]
let mut jobs : Array (BuildJob Dynlib) := #[]
for pkg in pkgs do
libDirs := libDirs.push pkg.nativeLibDir
jobs := jobs.append <| pkg.externLibs.mapM (·.dynlib.fetch)
return (jobs, libDirs)
/--
Build the dynlibs of the transitive imports that want precompilation
and the dynlibs of *their* imports.
-/
partial def recBuildPrecompileDynlibs (imports : Array Module)
: IndexBuildM (Array (BuildJob Dynlib) × Array (BuildJob Dynlib) × Array FilePath) := do
let (pkgs, _, jobs)
go imports OrdPackageSet.empty ModuleSet.empty #[] false
return (jobs, recBuildExternDynlibs pkgs.toArray)
where
go imports pkgs modSet jobs shouldPrecompile := do
let mut pkgs := pkgs
let mut modSet := modSet
let mut jobs := jobs
for mod in imports do
if modSet.contains mod then
continue
modSet := modSet.insert mod
let shouldPrecompile := shouldPrecompile || mod.shouldPrecompile
if shouldPrecompile then
pkgs := pkgs.insert mod.pkg
jobs := jobs.push <| ( mod.dynlib.fetch)
let recImports mod.imports.fetch
(pkgs, modSet, jobs) go recImports pkgs modSet jobs shouldPrecompile
return (pkgs, modSet, jobs)
variable [MonadLiftT BuildM m]
/--
Recursively parse the Lean files of a module and its imports
building an `Array` product of its direct local imports.
-/
def Module.recParseImports (mod : Module) : IndexBuildM (Array Module) := do
let contents IO.FS.readFile mod.leanFile
let imports Lean.parseImports' contents mod.leanFile.toString
let mods imports.foldlM (init := OrdModuleSet.empty) fun set imp =>
findModule? imp.module <&> fun | some mod => set.insert mod | none => set
return mods.toArray
/-- The `ModuleFacetConfig` for the builtin `importsFacet`. -/
def Module.importsFacetConfig : ModuleFacetConfig importsFacet :=
mkFacetConfig (·.recParseImports)
/-- Recursively compute a module's transitive imports. -/
def Module.recComputeTransImports (mod : Module) : IndexBuildM (Array Module) := do
(·.toArray) <$> ( mod.imports.fetch).foldlM (init := OrdModuleSet.empty) fun set imp => do
return set.appendArray ( imp.transImports.fetch) |>.insert imp
/-- The `ModuleFacetConfig` for the builtin `transImportsFacet`. -/
def Module.transImportsFacetConfig : ModuleFacetConfig transImportsFacet :=
mkFacetConfig (·.recComputeTransImports)
/-- Recursively compute a module's precompiled imports. -/
def Module.recComputePrecompileImports (mod : Module) : IndexBuildM (Array Module) := do
(·.toArray) <$> ( mod.imports.fetch).foldlM (init := OrdModuleSet.empty) fun set imp => do
if imp.shouldPrecompile then
return set.appendArray ( imp.transImports.fetch) |>.insert imp
else
return set.appendArray ( imp.precompileImports.fetch)
/-- The `ModuleFacetConfig` for the builtin `precompileImportsFacet`. -/
def Module.precompileImportsFacetConfig : ModuleFacetConfig precompileImportsFacet :=
mkFacetConfig (·.recComputePrecompileImports)
/-- Recursively build a module's transitive local imports and shared library dependencies. -/
def Module.recBuildDeps (mod : Module) : IndexBuildM (BuildJob (SearchPath × Array FilePath)) := do
let imports mod.imports.fetch
let extraDepJob mod.pkg.extraDep.fetch
let precompileImports mod.precompileImports.fetch
let modJobs precompileImports.mapM (·.dynlib.fetch)
let pkgs := precompileImports.foldl (·.insert ·.pkg)
OrdPackageSet.empty |>.insert mod.pkg |>.toArray
let (externJobs, libDirs) recBuildExternDynlibs pkgs
let importJob BuildJob.mixArray <| imports.mapM (·.importBin.fetch)
let externDynlibsJob BuildJob.collectArray externJobs
let modDynlibsJob BuildJob.collectArray modJobs
extraDepJob.bindAsync fun _ _ => do
importJob.bindAsync fun _ importTrace => do
modDynlibsJob.bindAsync fun modDynlibs modTrace => do
return externDynlibsJob.mapWithTrace fun externDynlibs externTrace =>
let depTrace := importTrace.mix <| modTrace.mix externTrace
/-
Requirements:
* Lean wants the external library symbols before module symbols.
* Unix requires the file extension of the dynlib.
* For some reason, building from the Lean server requires full paths.
Everything else loads fine with just the augmented library path.
* Linux still needs the augmented path to resolve nested dependencies in dynlibs.
-/
let dynlibPath := libDirs ++ externDynlibs.filterMap (·.dir?) |>.toList
let dynlibs := externDynlibs.map (·.path) ++ modDynlibs.map (·.path)
((dynlibPath, dynlibs), depTrace)
/-- The `ModuleFacetConfig` for the builtin `depsFacet`. -/
def Module.depsFacetConfig : ModuleFacetConfig depsFacet :=
mkFacetJobConfigSmall (·.recBuildDeps)
/-- Recursively build a module and its dependencies. -/
def Module.recBuildLeanCore (mod : Module) : IndexBuildM (BuildJob Unit) := do
( mod.deps.fetch).bindSync fun (dynlibPath, dynlibs) depTrace => do
mod.buildUnlessUpToDate dynlibPath dynlibs depTrace
return ((), depTrace)
/-- The `ModuleFacetConfig` for the builtin `leanBinFacet`. -/
def Module.leanBinFacetConfig : ModuleFacetConfig leanBinFacet :=
mkFacetJobConfig (·.recBuildLeanCore)
/-- The `ModuleFacetConfig` for the builtin `importBinFacet`. -/
def Module.importBinFacetConfig : ModuleFacetConfig importBinFacet :=
mkFacetJobConfigSmall fun mod => do
( mod.leanBin.fetch).bindSync fun _ depTrace =>
return ((), mixTrace ( computeTrace mod) depTrace)
/-- The `ModuleFacetConfig` for the builtin `oleanFacet`. -/
def Module.oleanFacetConfig : ModuleFacetConfig oleanFacet :=
mkFacetJobConfigSmall fun mod => do
( mod.leanBin.fetch).bindSync fun _ depTrace =>
return (mod.oleanFile, mixTrace ( computeTrace mod.oleanFile) depTrace)
/-- The `ModuleFacetConfig` for the builtin `ileanFacet`. -/
def Module.ileanFacetConfig : ModuleFacetConfig ileanFacet :=
mkFacetJobConfigSmall fun mod => do
( mod.leanBin.fetch).bindSync fun _ depTrace =>
return (mod.ileanFile, mixTrace ( computeTrace mod.ileanFile) depTrace)
/-- The `ModuleFacetConfig` for the builtin `cFacet`. -/
def Module.cFacetConfig : ModuleFacetConfig cFacet :=
mkFacetJobConfigSmall fun mod => do
( mod.leanBin.fetch).bindSync fun _ _ =>
-- do content-aware hashing so that we avoid recompiling unchanged C files
return (mod.cFile, computeTrace mod.cFile)
/-- Recursively build the module's object file from its C file produced by `lean`. -/
def Module.recBuildLeanO (self : Module) : IndexBuildM (BuildJob FilePath) := do
buildLeanO self.name.toString self.oFile ( self.c.fetch) self.leancArgs
/-- The `ModuleFacetConfig` for the builtin `oFacet`. -/
def Module.oFacetConfig : ModuleFacetConfig oFacet :=
mkFacetJobConfig Module.recBuildLeanO
-- TODO: Return `BuildJob OrdModuleSet × OrdPackageSet` or `OrdRBSet Dynlib`
/-- Recursively build the shared library of a module (e.g., for `--load-dynlib`). -/
def Module.recBuildDynlib (mod : Module) : IndexBuildM (BuildJob Dynlib) := do
-- Compute dependencies
let transImports mod.transImports.fetch
let modJobs transImports.mapM (·.dynlib.fetch)
let pkgs := transImports.foldl (·.insert ·.pkg)
OrdPackageSet.empty |>.insert mod.pkg |>.toArray
let (externJobs, pkgLibDirs) recBuildExternDynlibs pkgs
let linkJobs mod.nativeFacets.mapM (fetch <| mod.facet ·.name)
-- Collect Jobs
let linksJob BuildJob.collectArray linkJobs
let modDynlibsJob BuildJob.collectArray modJobs
let externDynlibsJob BuildJob.collectArray externJobs
-- Build dynlib
show SchedulerM _ from do
linksJob.bindAsync fun links oTrace => do
modDynlibsJob.bindAsync fun modDynlibs libTrace => do
externDynlibsJob.bindSync fun externDynlibs externTrace => do
let libNames := modDynlibs.map (·.name) ++ externDynlibs.map (·.name)
let libDirs := pkgLibDirs ++ externDynlibs.filterMap (·.dir?)
let depTrace := oTrace.mix <| libTrace.mix externTrace
let trace buildFileUnlessUpToDate mod.dynlibFile depTrace do
let args := links.map toString ++
libDirs.map (s!"-L{·}") ++ libNames.map (s!"-l{·}")
compileSharedLib mod.name.toString mod.dynlibFile args ( getLeanc)
return (mod.dynlibFile, mod.dynlibName, trace)
/-- The `ModuleFacetConfig` for the builtin `dynlibFacet`. -/
def Module.dynlibFacetConfig : ModuleFacetConfig dynlibFacet :=
mkFacetJobConfig Module.recBuildDynlib
open Module in
/--
A name-configuration map for the initial set of
Lake module facets (e.g., `lean.{imports, c, o, dynlib]`).
-/
def initModuleFacetConfigs : DNameMap ModuleFacetConfig :=
DNameMap.empty
|>.insert importsFacet importsFacetConfig
|>.insert transImportsFacet transImportsFacetConfig
|>.insert precompileImportsFacet precompileImportsFacetConfig
|>.insert depsFacet depsFacetConfig
|>.insert leanBinFacet leanBinFacetConfig
|>.insert importBinFacet importBinFacetConfig
|>.insert oleanFacet oleanFacetConfig
|>.insert ileanFacet ileanFacetConfig
|>.insert cFacet cFacetConfig
|>.insert oFacet oFacetConfig
|>.insert dynlibFacet dynlibFacetConfig

View File

@@ -0,0 +1,57 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Config.Monad
import Lake.Build.Context
import Lake.Util.EStateT
open System
namespace Lake
def mkBuildContext (ws : Workspace) (oldMode : Bool) : IO BuildContext := do
let lean := ws.lakeEnv.lean
let leanTrace := Hash.ofString lean.githash
return {
opaqueWs := ws, leanTrace, oldMode
startedBuilds := IO.mkRef 0
finishedBuilds := IO.mkRef 0
}
@[inline] def getLeanTrace : BuildM BuildTrace :=
(·.leanTrace) <$> readThe BuildContext
@[inline] def getIsOldMode : BuildM Bool :=
(·.oldMode) <$> readThe BuildContext
def failOnBuildCycle [ToString k] : Except (List k) α BuildM α
| Except.ok a => pure a
| Except.error cycle => do
let cycle := cycle.map (s!" {·}")
error s!"build cycle detected:\n{"\n".intercalate cycle}"
/--
Run the recursive build in the given build store.
If a cycle is encountered, log it and then fail.
-/
@[inline] def RecBuildM.runIn (store : BuildStore) (build : RecBuildM α) : BuildM (α × BuildStore) := do
let (res, store) EStateT.run store <| ReaderT.run build []
return ( failOnBuildCycle res, store)
/--
Run the recursive build in a fresh build store.
If a cycle is encountered, log it and then fail.
-/
@[inline] def RecBuildM.run (build : RecBuildM α) : BuildM α := do
(·.1) <$> build.runIn {}
/-- Run the given build function in the Workspace's context. -/
@[inline] def Workspace.runBuild (ws : Workspace) (build : BuildM α) (oldMode := false) : LogIO α := do
let ctx mkBuildContext ws oldMode
build.run ctx
/-- Run the given build function in the Lake monad's workspace. -/
@[inline] def runBuild (build : BuildM α) (oldMode := false) : LakeT LogIO α := do
( getWorkspace).runBuild build oldMode

View File

@@ -0,0 +1,122 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Util.Sugar
import Lake.Build.Common
open System
namespace Lake
/-- Fetch the build job of the specified package target. -/
def Package.fetchTargetJob (self : Package)
(target : Name) : IndexBuildM (Option (BuildJob Unit)) := do
let some config := self.findTargetConfig? target
| error s!"package '{self.name}' has no target '{target}'"
return config.getJob ( fetch <| self.target target)
/-- Fetch the build result of a target. -/
protected def TargetDecl.fetch (self : TargetDecl)
[FamilyDef CustomData (self.pkg, self.name) α] : IndexBuildM α := do
let some pkg findPackage? self.pkg
| error s!"package '{self.pkg}' of target '{self.name}' does not exist in workspace"
fetch <| pkg.target self.name
/-- Fetch the build job of the target. -/
def TargetDecl.fetchJob (self : TargetDecl) : IndexBuildM (BuildJob Unit) := do
let some pkg findPackage? self.pkg
| error s!"package '{self.pkg}' of target '{self.name}' does not exist in workspace"
return self.config.getJob ( fetch <| pkg.target self.name)
/-- Fetch the build result of a package facet. -/
@[inline] protected def PackageFacetDecl.fetch (pkg : Package)
(self : PackageFacetDecl) [FamilyOut PackageData self.name α] : IndexBuildM α := do
fetch <| pkg.facet self.name
/-- Fetch the build job of a package facet. -/
def PackageFacetConfig.fetchJob (pkg : Package)
(self : PackageFacetConfig name) : IndexBuildM (BuildJob Unit) := do
let some getJob := self.getJob?
| error "package facet '{pkg.name}' has no associated build job"
return getJob <| fetch <| pkg.facet self.name
/-- Fetch the build job of a library facet. -/
def Package.fetchFacetJob
(name : Name) (self : Package) : IndexBuildM (BuildJob Unit) := do
let some config := ( getWorkspace).packageFacetConfigs.find? name
| error "package facet '{name}' does not exist in workspace"
inline <| config.fetchJob self
/-- Compute a topological ordering of the package's transitive dependencies. -/
def Package.recComputeDeps (self : Package) : IndexBuildM (Array Package) := do
let mut deps := #[]
let mut depSet := PackageSet.empty
for dep in self.deps do
for depDep in ( fetch <| dep.facet `deps) do
unless depSet.contains depDep do
deps := deps.push depDep
depSet := depSet.insert depDep
unless depSet.contains dep do
deps := deps.push dep
depSet := depSet.insert dep
return deps
/-- The `PackageFacetConfig` for the builtin `depsFacet`. -/
def Package.depsFacetConfig : PackageFacetConfig depsFacet :=
mkFacetConfig Package.recComputeDeps
/--
Build the `extraDepTarget` for the package and its transitive dependencies.
Also fetch pre-built releases for the package's' dependencies.
-/
def Package.recBuildExtraDepTargets (self : Package) : IndexBuildM (BuildJob Unit) := do
let mut job := BuildJob.nil
-- Build dependencies' extra dep targets
for dep in self.deps do
job job.mix <| dep.extraDep.fetch
-- Fetch pre-built release if desired and this package is a dependency
if self.name ( getWorkspace).root.name self.preferReleaseBuild then
job job.mix <| self.release.fetch
-- Build this package's extra dep targets
for target in self.extraDepTargets do
if let some config := self.findTargetConfig? target then
job job.mix <| config.getJob <| fetch <| self.target target
else
error s!"unknown target `{target}`"
return job
/-- The `PackageFacetConfig` for the builtin `dynlibFacet`. -/
def Package.extraDepFacetConfig : PackageFacetConfig extraDepFacet :=
mkFacetJobConfigSmall Package.recBuildExtraDepTargets
/-- Download and unpack the package's prebuilt release archive (from GitHub). -/
def Package.fetchRelease (self : Package) : SchedulerM (BuildJob Unit) := Job.async do
let some (repoUrl, tag) := self.release? | do
logWarning "wanted prebuilt release, but release repository and tag was not known"
return ((), .nil)
let url := s!"{repoUrl}/releases/download/{tag}/{self.buildArchive}"
let logName := s!"{self.name}/{tag}/{self.buildArchive}"
try
let depTrace := Hash.ofString url
let trace buildFileUnlessUpToDate self.buildArchiveFile depTrace do
download logName url self.buildArchiveFile
untar logName self.buildArchiveFile self.buildDir
return ((), trace)
else
return ((), .nil)
/-- The `PackageFacetConfig` for the builtin `releaseFacet`. -/
def Package.releaseFacetConfig : PackageFacetConfig releaseFacet :=
mkFacetJobConfig (·.fetchRelease)
open Package in
/--
A package facet name to build function map that contains builders for
the initial set of Lake package facets (e.g., `extraDep`).
-/
def initPackageFacetConfigs : DNameMap PackageFacetConfig :=
DNameMap.empty
|>.insert depsFacet depsFacetConfig
|>.insert extraDepFacet extraDepFacetConfig
|>.insert releaseFacet releaseFacetConfig

View File

@@ -0,0 +1,88 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Data
import Lake.Util.StoreInsts
/-!
# The Lake Build Store
The Lake build store is the map of Lake build keys to build task and/or
build results that is slowly filled during a recursive build (e.g., via
topological-based build of an initial key's dependencies).
-/
namespace Lake
/-- A monad equipped with a Lake build store. -/
abbrev MonadBuildStore (m) := MonadDStore BuildKey BuildData m
/-- The type of the Lake build store. -/
abbrev BuildStore :=
DRBMap BuildKey BuildData BuildKey.quickCmp
@[inline] def BuildStore.empty : BuildStore := DRBMap.empty
namespace BuildStore
-- Linter reports false positives on the `v` variables below
set_option linter.unusedVariables false
/-- Derive an array of built module facets from the store. -/
def collectModuleFacetArray (self : BuildStore)
(facet : Name) [FamilyOut ModuleData facet α] : Array α := Id.run do
let mut res : Array α := #[]
for k, v in self do
match k with
| .moduleFacet m f =>
if h : f = facet then
have of_data := by unfold BuildData; simp [h]
res := res.push <| cast of_data v
| _ => pure ()
return res
/-- Derive a map of module names to built facets from the store. -/
def collectModuleFacetMap (self : BuildStore)
(facet : Name) [FamilyOut ModuleData facet α] : NameMap α := Id.run do
let mut res := Lean.mkNameMap α
for k, v in self do
match k with
| .moduleFacet m f =>
if h : f = facet then
have of_data := by unfold BuildData; simp [h]
res := res.insert m <| cast of_data v
| _ => pure ()
return res
/-- Derive an array of built package facets from the store. -/
def collectPackageFacetArray (self : BuildStore)
(facet : Name) [FamilyOut PackageData facet α] : Array α := Id.run do
let mut res : Array α := #[]
for k, v in self do
match k with
| .packageFacet _ f =>
if h : f = facet then
have of_data := by unfold BuildData; simp [h]
res := res.push <| cast of_data v
| _ => pure ()
return res
/-- Derive an array of built target facets from the store. -/
def collectTargetFacetArray (self : BuildStore)
(facet : Name) [FamilyOut TargetData facet α] : Array α := Id.run do
let mut res : Array α := #[]
for k, v in self do
match k with
| .targetFacet _ _ f =>
if h : f = facet then
have of_data := by unfold BuildData; simp [h]
res := res.push <| cast of_data v
| _ => pure ()
return res
/-- Derive an array of built external shared libraries from the store. -/
def collectSharedExternLibs (self : BuildStore)
[FamilyOut TargetData `externLib.shared α] : Array α :=
self.collectTargetFacetArray `externLib.shared

View File

@@ -0,0 +1,139 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Util.Cycle
import Lake.Util.Store
import Lake.Util.EquipT
/-!
# Topological / Suspending Recursive Builder
This module defines a recursive build function that topologically
(ι.e., via a depth-first search with memoization) builds the elements of
a build store.
This is called a suspending scheduler in *Build systems à la carte*.
-/
namespace Lake
/-!
## Recursive Fetching
In this section, we define the primitives that make up a builder.
-/
/--
A dependently typed monadic *fetch* function.
That is, a function within the monad `m` and takes an input `a : α`
describing what to fetch and and produces some output `b : β a` (dependently
typed) or `b : B` (not) describing what was fetched. All build functions are
fetch functions, but not all fetch functions need build something.
-/
abbrev DFetchFn (α : Type u) (β : α Type v) (m : Type v Type w) :=
(a : α) m (β a)
/-!
In order to nest builds / fetches within one another,
we equip the monad `m` with a fetch function of its own.
-/
/-- A transformer that equips a monad with a `DFetchFn`. -/
abbrev DFetchT (α : Type u) (β : α Type v) (m : Type v Type w) :=
EquipT (DFetchFn α β m) m
/-- A `DFetchT` that is not dependently typed. -/
abbrev FetchT (α : Type u) (β : Type v) (m : Type v Type w) :=
DFetchT α (fun _ => β) m
/-!
We can then use the such a monad as the basis for a fetch function itself.
-/
/-
A `DFetchFn` that utilizes another `DFetchFn` equipped to the monad to
fetch values. It is thus usually implemented recursively via some variation
of the `recFetch` function below, hence the "rec" in both names.
-/
abbrev DRecFetchFn (α : Type u) (β : α Type v) (m : Type v Type w) :=
DFetchFn α β (DFetchT α β m)
/-- A `DRecFetchFn` that is not dependently typed. -/
abbrev RecFetchFn (α : Type u) (β : Type v) (m : Type v Type w) :=
α FetchT α β m β
/-- A `DFetchFn` that provides its base `DRecFetchFn` with itself. -/
@[specialize] partial def recFetch
[(α : Type u) Nonempty (m α)] (fetch : DRecFetchFn α β m) : DFetchFn α β m :=
fun a => fetch a (recFetch fetch)
/-!
The basic `recFetch` can fail to terminate in a variety of ways,
it can even cycle (i.e., `a` fetches `b` which fetches `a`). Thus, we
define the `acyclicRecFetch` below to guard against such cases.
-/
/--
A `recFetch` augmented by a `CycleT` to guard against recursive cycles.
If the set of visited keys is finite, this function should provably terminate.
We use `keyOf` to the derive the unique key of a fetch from its descriptor
`a : α`. We do this because descriptors may not be comparable and/or contain
more information than necessary to determine uniqueness.
-/
@[inline] partial def recFetchAcyclic [BEq κ] [Monad m]
(keyOf : α κ) (fetch : DRecFetchFn α β (CycleT κ m)) : DFetchFn α β (CycleT κ m) :=
recFetch fun a recurse =>
/-
NOTE: We provide the stack directly to `recurse` rather than
get it through `ReaderT` to prevent it being overridden by the `fetch`
function (and thereby potentially produce a cycle).
-/
guardCycle (keyOf a) fun stack => fetch a (recurse · stack) stack
/-!
When building, we usually do not want to build the same thing twice during
a single build pass. At the same time, separate builds may both wish to fetch
the same thing. Thus, we need to store past build results to return them upon
future fetches. This is what `recFetchMemoize` below does.
-/
/--
`recFetchAcyclic` augmented with a `MonadDStore` to
memoize fetch results and thus avoid computing the same result twice.
-/
@[inline] def recFetchMemoize [BEq κ] [Monad m] [MonadDStore κ β m]
(keyOf : α κ) (fetch : DRecFetchFn α (fun a => β (keyOf a)) (CycleT κ m))
: DFetchFn α (fun a => β (keyOf a)) (CycleT κ m) :=
recFetchAcyclic keyOf fun a recurse =>
fetchOrCreate (keyOf a) do fetch a recurse
/-!
## Building
In this section, we use the abstractions we have just created to define
the desired topological recursive build function (a.k.a. a suspending scheduler).
-/
/-- Recursively builds objects for the keys `κ`, avoiding cycles. -/
@[inline] def buildAcyclic [BEq κ] [Monad m]
(keyOf : α κ) (a : α) (build : RecFetchFn α β (CycleT κ m)) : ExceptT (Cycle κ) m β :=
recFetchAcyclic (β := fun _ => β) keyOf build a []
/-- Dependently typed version of `buildTop`. -/
@[inline] def buildDTop (β) [BEq κ] [Monad m] [MonadDStore κ β m]
(keyOf : α κ) (a : α) (build : DRecFetchFn α (fun a => β (keyOf a)) (CycleT κ m))
: ExceptT (Cycle κ) m (β (keyOf a)) :=
recFetchMemoize keyOf build a []
/--
Recursively fills a `MonadStore` of key-object pairs by
building objects topologically (ι.e., depth-first with memoization).
If a cycle is detected, the list of keys traversed is thrown.
-/
@[inline] def buildTop [BEq κ] [Monad m] [MonadStore κ β m]
(keyOf : α κ) (a : α) (build : RecFetchFn α β (CycleT κ m)) : ExceptT (Cycle κ) m β :=
recFetchMemoize (β := fun _ => β) keyOf build a []

View File

@@ -0,0 +1,273 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
open System
namespace Lake
--------------------------------------------------------------------------------
/-! # Utilities -/
--------------------------------------------------------------------------------
class CheckExists.{u} (i : Type u) where
/-- Check whether there already exists an artifact for the given target info. -/
checkExists : i BaseIO Bool
export CheckExists (checkExists)
instance : CheckExists FilePath where
checkExists := FilePath.pathExists
--------------------------------------------------------------------------------
/-! # Trace Abstraction -/
--------------------------------------------------------------------------------
class ComputeTrace.{u,v,w} (i : Type u) (m : outParam $ Type v Type w) (t : Type v) where
/-- Compute the trace of some target info using information from the monadic context. -/
computeTrace : i m t
def computeTrace [ComputeTrace i m t] [MonadLiftT m n] (info : i) : n t :=
liftM <| ComputeTrace.computeTrace info
class NilTrace.{u} (t : Type u) where
/-- The nil trace. Should not unduly clash with a proper trace. -/
nilTrace : t
export NilTrace (nilTrace)
instance [NilTrace t] : Inhabited t := nilTrace
class MixTrace.{u} (t : Type u) where
/-- Combine two traces. The result should be dirty if either of the inputs is dirty. -/
mixTrace : t t t
export MixTrace (mixTrace)
def mixTraceM [MixTrace t] [Pure m] (t1 t2 : t) : m t :=
pure <| mixTrace t1 t2
section
variable [MixTrace t] [NilTrace t]
def mixTraceList (traces : List t) : t :=
traces.foldl mixTrace nilTrace
def mixTraceArray (traces : Array t) : t :=
traces.foldl mixTrace nilTrace
variable [ComputeTrace i m t]
def computeListTrace [MonadLiftT m n] [Monad n] (artifacts : List i) : n t :=
mixTraceList <$> artifacts.mapM computeTrace
instance [Monad m] : ComputeTrace (List i) m t := computeListTrace
def computeArrayTrace [MonadLiftT m n] [Monad n] (artifacts : Array i) : n t :=
mixTraceArray <$> artifacts.mapM computeTrace
instance [Monad m] : ComputeTrace (Array i) m t := computeArrayTrace
end
--------------------------------------------------------------------------------
/-! # Hash Trace -/
--------------------------------------------------------------------------------
/--
A content hash.
TODO: Use a secure hash rather than the builtin Lean hash function.
-/
structure Hash where
val : UInt64
deriving BEq, DecidableEq, Repr
namespace Hash
def ofNat (n : Nat) :=
mk n.toUInt64
def loadFromFile (hashFile : FilePath) : IO (Option Hash) :=
return ( IO.FS.readFile hashFile).toNat?.map ofNat
def nil : Hash :=
mk <| 1723 -- same as Name.anonymous
instance : NilTrace Hash := nil
def mix (h1 h2 : Hash) : Hash :=
mk <| mixHash h1.val h2.val
instance : MixTrace Hash := mix
protected def toString (self : Hash) : String :=
toString self.val
instance : ToString Hash := Hash.toString
def ofString (str : String) :=
mix nil <| mk <| hash str -- same as Name.mkSimple
def ofByteArray (bytes : ByteArray) : Hash :=
hash bytes
end Hash
class ComputeHash (α : Type u) (m : outParam $ Type Type v) where
computeHash : α m Hash
instance [ComputeHash α m] : ComputeTrace α m Hash := ComputeHash.computeHash
def pureHash [ComputeHash α Id] (a : α) : Hash :=
ComputeHash.computeHash a
def computeHash [ComputeHash α m] [MonadLiftT m n] (a : α) : n Hash :=
liftM <| ComputeHash.computeHash a
instance : ComputeHash String Id := Hash.ofString
def computeFileHash (file : FilePath) : IO Hash :=
Hash.ofByteArray <$> IO.FS.readBinFile file
instance : ComputeHash FilePath IO := computeFileHash
/--
A wrapper around `FilePath` that adjusts its `ComputeHash` implementation
to normalize `\r\n` sequences to `\n` for cross-platform compatibility. -/
structure TextFilePath where
path : FilePath
instance : ComputeHash TextFilePath IO where
computeHash file := do
let text IO.FS.readFile file.path
let text := text.replace "\r\n" "\n"
return Hash.ofString text
instance [ComputeHash α m] [Monad m] : ComputeHash (Array α) m where
computeHash ar := ar.foldlM (fun b a => Hash.mix b <$> computeHash a) Hash.nil
--------------------------------------------------------------------------------
/-! # Modification Time (MTime) Trace -/
--------------------------------------------------------------------------------
open IO.FS (SystemTime)
/-- A modification time. -/
def MTime := SystemTime
namespace MTime
instance : OfNat MTime (nat_lit 0) := 0,0
instance : BEq MTime := inferInstanceAs (BEq SystemTime)
instance : Repr MTime := inferInstanceAs (Repr SystemTime)
instance : Ord MTime := inferInstanceAs (Ord SystemTime)
instance : LT MTime := ltOfOrd
instance : LE MTime := leOfOrd
instance : Min MTime := minOfLe
instance : Max MTime := maxOfLe
instance : NilTrace MTime := 0
instance : MixTrace MTime := max
end MTime
class GetMTime (α) where
getMTime : α IO MTime
export GetMTime (getMTime)
instance [GetMTime α] : ComputeTrace α IO MTime := getMTime
def getFileMTime (file : FilePath) : IO MTime :=
return ( file.metadata).modified
instance : GetMTime FilePath := getFileMTime
instance : GetMTime TextFilePath := (getFileMTime ·.path)
/-- Check if the info's `MTIme` is at least `depMTime`. -/
def checkIfNewer [GetMTime i] (info : i) (depMTime : MTime) : BaseIO Bool :=
(do pure (( getMTime info) >= depMTime : Bool)).catchExceptions fun _ => pure false
--------------------------------------------------------------------------------
/-! # Lake Build Trace (Hash + MTIme) -/
--------------------------------------------------------------------------------
/-- Trace used for common Lake targets. Combines `Hash` and `MTime`. -/
structure BuildTrace where
hash : Hash
mtime : MTime
deriving Repr
namespace BuildTrace
def withHash (hash : Hash) (self : BuildTrace) : BuildTrace :=
{self with hash}
def withoutHash (self : BuildTrace) : BuildTrace :=
{self with hash := Hash.nil}
def withMTime (mtime : MTime) (self : BuildTrace) : BuildTrace :=
{self with mtime}
def withoutMTime (self : BuildTrace) : BuildTrace :=
{self with mtime := 0}
def fromHash (hash : Hash) : BuildTrace :=
mk hash 0
instance : Coe Hash BuildTrace := fromHash
def fromMTime (mtime : MTime) : BuildTrace :=
mk Hash.nil mtime
instance : Coe MTime BuildTrace := fromMTime
def nil : BuildTrace :=
mk Hash.nil 0
instance : NilTrace BuildTrace := nil
def compute [ComputeHash i m] [MonadLiftT m IO] [GetMTime i] (info : i) : IO BuildTrace :=
return mk ( computeHash info) ( getMTime info)
instance [ComputeHash i m] [MonadLiftT m IO] [GetMTime i] : ComputeTrace i IO BuildTrace := compute
def mix (t1 t2 : BuildTrace) : BuildTrace :=
mk (Hash.mix t1.hash t2.hash) (max t1.mtime t2.mtime)
instance : MixTrace BuildTrace := mix
/--
Check the build trace against the given target info and hash
to see if the target is up-to-date.
-/
def checkAgainstHash [CheckExists i]
(info : i) (hash : Hash) (self : BuildTrace) : BaseIO Bool :=
pure (hash == self.hash) <&&> checkExists info
/--
Check the build trace against the given target info and its modification time
to see if the target is up-to-date.
-/
def checkAgainstTime [CheckExists i] [GetMTime i]
(info : i) (self : BuildTrace) : BaseIO Bool :=
checkIfNewer info self.mtime
/--
Check the build trace against the given target info and its trace file
to see if the target is up-to-date.
-/
def checkAgainstFile [CheckExists i] [GetMTime i]
(info : i) (traceFile : FilePath) (self : BuildTrace) : BaseIO Bool := do
let act : IO _ := do
if let some hash Hash.loadFromFile traceFile then
self.checkAgainstHash info hash
else
return self.mtime < ( getMTime info)
act.catchExceptions fun _ => pure false
def writeToFile (traceFile : FilePath) (self : BuildTrace) : IO PUnit :=
IO.FS.writeFile traceFile self.hash.toString
end BuildTrace

6
src/lake/Lake/CLI.lean Normal file
View File

@@ -0,0 +1,6 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.CLI.Main

View File

@@ -0,0 +1,29 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Index
namespace Lake
def env (cmd : String) (args : Array String := #[]) : LakeT IO UInt32 := do
IO.Process.spawn {cmd, args, env := getAugmentedEnv} >>= (·.wait)
def exe (name : Name) (args : Array String := #[]) (oldMode := false) : LakeT LogIO UInt32 := do
let ws getWorkspace
if let some exe := ws.findLeanExe? name then
let exeFile ws.runBuild (exe.build >>= (·.await)) oldMode
env exeFile.toString args
else
error s!"unknown executable `{name}`"
def uploadRelease (pkg : Package) (tag : String) : LogIO Unit := do
let mut args :=
#["release", "upload", tag, pkg.buildArchiveFile.toString, "--clobber"]
if let some repo := pkg.releaseRepo? then
args := args.append #["-R", repo]
tar pkg.buildArchive pkg.buildDir pkg.buildArchiveFile
(excludePaths := #["*.tar.gz", "*.tar.gz.trace"])
logInfo s!"Uploading {tag}/{pkg.buildArchive}"
proc {cmd := "gh", args}

View File

@@ -0,0 +1,187 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Build.Index
import Lake.CLI.Error
namespace Lake
/-! ## Build Target Specifiers -/
structure BuildSpec where
info : BuildInfo
getBuildJob : BuildData info.key BuildJob Unit
@[inline] def BuildSpec.getJob (self : BuildSpec) (data : BuildData self.info.key) : Job Unit :=
discard <| self.getBuildJob data
@[inline] def BuildData.toBuildJob
[FamilyOut BuildData k (BuildJob α)] (data : BuildData k) : BuildJob Unit :=
discard <| ofFamily data
@[inline] def mkBuildSpec (info : BuildInfo)
[FamilyOut BuildData info.key (BuildJob α)] : BuildSpec :=
{info, getBuildJob := BuildData.toBuildJob}
@[inline] def mkConfigBuildSpec (facetType : String)
(info : BuildInfo) (config : FacetConfig Fam ι facet) (h : BuildData info.key = Fam facet)
: Except CliError BuildSpec := do
let some getJob := config.getJob?
| throw <| CliError.nonCliFacet facetType facet
return {info, getBuildJob := h getJob}
def BuildSpec.build (self : BuildSpec) : RecBuildM (Job Unit) :=
self.getJob <$> buildIndexTop' self.info
def buildSpecs (specs : Array BuildSpec) : BuildM PUnit := do
let jobs RecBuildM.run do specs.mapM (·.build)
jobs.forM (discard <| ·.await)
/-! ## Parsing CLI Build Target Specifiers -/
def parsePackageSpec (ws : Workspace) (spec : String) : Except CliError Package :=
if spec.isEmpty then
return ws.root
else
match ws.findPackage? <| stringToLegalOrSimpleName spec with
| some pkg => return pkg
| none => throw <| CliError.unknownPackage spec
open Module in
def resolveModuleTarget (ws : Workspace) (mod : Module) (facet : Name) : Except CliError BuildSpec :=
if facet.isAnonymous then
return mkBuildSpec <| mod.facet leanBinFacet
else if let some config := ws.findModuleFacetConfig? facet then do
mkConfigBuildSpec "module" (mod.facet facet) config rfl
else
throw <| CliError.unknownFacet "module" facet
def resolveLibTarget (ws : Workspace) (lib : LeanLib) (facet : Name) : Except CliError (Array BuildSpec) :=
if facet.isAnonymous then
lib.defaultFacets.mapM (resolveFacet ·)
else
Array.singleton <$> resolveFacet facet
where
resolveFacet facet :=
if let some config := ws.findLibraryFacetConfig? facet then do
mkConfigBuildSpec "library" (lib.facet facet) config rfl
else
throw <| CliError.unknownFacet "library" facet
def resolveExeTarget (exe : LeanExe) (facet : Name) : Except CliError BuildSpec :=
if facet.isAnonymous || facet == `exe then
return mkBuildSpec exe.exe
else
throw <| CliError.unknownFacet "executable" facet
def resolveExternLibTarget (lib : ExternLib) (facet : Name) : Except CliError BuildSpec :=
if facet.isAnonymous || facet = `static then
return mkBuildSpec lib.static
else if facet = `shared then
return mkBuildSpec lib.shared
else
throw <| CliError.unknownFacet "external library" facet
def resolveCustomTarget (pkg : Package)
(name facet : Name) (config : TargetConfig pkg.name name) : Except CliError BuildSpec :=
if !facet.isAnonymous then
throw <| CliError.invalidFacet name facet
else do
let info := pkg.target name
have h : BuildData info.key = CustomData (pkg.name, name) := rfl
return {info, getBuildJob := h config.getJob}
def resolveTargetInPackage (ws : Workspace)
(pkg : Package) (target facet : Name) : Except CliError (Array BuildSpec) :=
if let some config := pkg.findTargetConfig? target then
Array.singleton <$> resolveCustomTarget pkg target facet config
else if let some exe := pkg.findLeanExe? target then
Array.singleton <$> resolveExeTarget exe facet
else if let some lib := pkg.findExternLib? target then
Array.singleton <$> resolveExternLibTarget lib facet
else if let some lib := pkg.findLeanLib? target then
resolveLibTarget ws lib facet
else if let some mod := pkg.findModule? target then
Array.singleton <$> resolveModuleTarget ws mod facet
else
throw <| CliError.missingTarget pkg.name (target.toString false)
def resolveDefaultPackageTarget (ws : Workspace) (pkg : Package) : Except CliError (Array BuildSpec) :=
pkg.defaultTargets.concatMapM (resolveTargetInPackage ws pkg · .anonymous)
def resolvePackageTarget (ws : Workspace) (pkg : Package) (facet : Name) : Except CliError (Array BuildSpec) :=
if facet.isAnonymous then
resolveDefaultPackageTarget ws pkg
else if let some config := ws.findPackageFacetConfig? facet then do
Array.singleton <$> mkConfigBuildSpec "package" (pkg.facet facet) config rfl
else
throw <| CliError.unknownFacet "package" facet
def resolveTargetInWorkspace (ws : Workspace)
(target : Name) (facet : Name) : Except CliError (Array BuildSpec) :=
if let some pkg, config := ws.findTargetConfig? target then
Array.singleton <$> resolveCustomTarget pkg target facet config
else if let some exe := ws.findLeanExe? target then
Array.singleton <$> resolveExeTarget exe facet
else if let some lib := ws.findExternLib? target then
Array.singleton <$> resolveExternLibTarget lib facet
else if let some lib := ws.findLeanLib? target then
resolveLibTarget ws lib facet
else if let some pkg := ws.findPackage? target then
resolvePackageTarget ws pkg facet
else if let some mod := ws.findModule? target then
Array.singleton <$> resolveModuleTarget ws mod facet
else
throw <| CliError.unknownTarget target
def resolveTargetBaseSpec
(ws : Workspace) (spec : String) (facet : Name) : Except CliError (Array BuildSpec) := do
match spec.splitOn "/" with
| [spec] =>
if spec.isEmpty then
resolvePackageTarget ws ws.root facet
else if spec.startsWith "@" then
let pkg parsePackageSpec ws <| spec.drop 1
resolvePackageTarget ws pkg facet
else if spec.startsWith "+" then
let mod := spec.drop 1 |>.toName
if let some mod := ws.findModule? mod then
Array.singleton <$> resolveModuleTarget ws mod facet
else
throw <| CliError.unknownModule mod
else
resolveTargetInWorkspace ws (stringToLegalOrSimpleName spec) facet
| [pkgSpec, targetSpec] =>
let pkgSpec := if pkgSpec.startsWith "@" then pkgSpec.drop 1 else pkgSpec
let pkg parsePackageSpec ws pkgSpec
if targetSpec.isEmpty then
resolvePackageTarget ws pkg facet
else if targetSpec.startsWith "+" then
let mod := targetSpec.drop 1 |>.toName
if let some mod := pkg.findModule? mod then
Array.singleton <$> resolveModuleTarget ws mod facet
else
throw <| CliError.unknownModule mod
else
resolveTargetInPackage ws pkg targetSpec facet
| _ =>
throw <| CliError.invalidTargetSpec spec '/'
def parseTargetSpec (ws : Workspace) (spec : String) : Except CliError (Array BuildSpec) := do
match spec.splitOn ":" with
| [spec] =>
resolveTargetBaseSpec ws spec .anonymous
| [rootSpec, facet] =>
resolveTargetBaseSpec ws rootSpec facet.toName
| _ =>
throw <| CliError.invalidTargetSpec spec ':'
def parseTargetSpecs (ws : Workspace) (specs : List String) : Except CliError (Array BuildSpec) := do
let mut results := #[]
for spec in specs do
results := results ++ ( parseTargetSpec ws spec)
if results.isEmpty then
results resolveDefaultPackageTarget ws ws.root
return results

View File

@@ -0,0 +1,70 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
namespace Lake
open Lean (Name)
inductive CliError
/- CLI Errors -/
| missingCommand
| unknownCommand (cmd : String)
| missingArg (arg : String)
| missingOptArg (opt arg : String)
| unknownShortOption (opt : Char)
| unknownLongOption (opt : String)
| unexpectedArguments (args : List String)
/- Init CLI Errors -/
| unknownTemplate (spec : String)
/- Build CLI Errors -/
| unknownModule (mod : Name)
| unknownPackage (spec : String)
| unknownFacet (type : String) (facet : Name)
| unknownTarget (target : Name)
| missingModule (pkg : Name) (mod : Name)
| missingTarget (pkg : Name) (spec : String)
| nonCliTarget (target : Name)
| nonCliFacet (type : String) (facet : Name)
| invalidTargetSpec (spec : String) (tooMany : Char)
| invalidFacet (target : Name) (facet : Name)
/- Script CLI Error -/
| unknownScript (script : String)
| missingScriptDoc (script : String)
| invalidScriptSpec (spec : String)
/- Config Errors -/
| unknownLeanInstall
| unknownLakeInstall
| leanRevMismatch (expected actual : String)
deriving Inhabited, Repr
namespace CliError
def toString : CliError String
| missingCommand => "missing command"
| unknownCommand cmd => s!"unknown command '{cmd}'"
| missingArg arg => s!"missing {arg}"
| missingOptArg opt arg => s!"missing {arg} after {opt}"
| unknownShortOption opt => s!"unknown short option '-{opt}'"
| unknownLongOption opt => s!"unknown long option '{opt}'"
| unexpectedArguments as => s!"unexpected arguments: {" ".intercalate as}"
| unknownTemplate spec => s!"unknown package template `{spec}`"
| unknownModule mod => s!"unknown module `{mod.toString false}`"
| unknownPackage spec => s!"unknown package `{spec}`"
| unknownFacet ty f => s!"unknown {ty} facet `{f.toString false}`"
| unknownTarget t => s!"unknown target `{t.toString false}`"
| missingModule pkg mod => s!"package '{pkg.toString false}' has no module '{mod.toString false}'"
| missingTarget pkg spec => s!"package '{pkg.toString false}' has no target '{spec}'"
| nonCliTarget t => s!"target `{t.toString false}` is not a buildable via `lake`"
| nonCliFacet t f => s!"{t} facet `{f.toString false}` is not a buildable via `lake`"
| invalidTargetSpec s c => s!"invalid script spec '{s}' (too many '{c}')"
| invalidFacet t f => s!"invalid facet `{f.toString false}`; target {t.toString false} has no facets"
| unknownScript s => s!"unknown script {s}"
| missingScriptDoc s => s!"no documentation provided for `{s}`"
| invalidScriptSpec s => s!"invalid script spec '{s}' (too many '/')"
| unknownLeanInstall => "could not detect a Lean installation"
| unknownLakeInstall => "could not detect the configuration of the Lake installation"
| leanRevMismatch e a => s!"expected Lean commit {e}, but got {if a.isEmpty then "nothing" else a}"
instance : ToString CliError := toString

242
src/lake/Lake/CLI/Help.lean Normal file
View File

@@ -0,0 +1,242 @@
/-
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Sebastian Ullrich, Mac Malone
-/
import Lake.Version
namespace Lake
def usage :=
uiVersionString ++ "
USAGE:
lake [OPTIONS] <COMMAND>
OPTIONS:
--version print version and exit
--help, -h print help of the program or a command and exit
--dir, -d=file use the package configuration in a specific directory
--file, -f=file use a specific file for the package configuration
--quiet, -q hide progress messages
--verbose, -v show verbose information (command invocations)
--lean=cmd specify the `lean` command used by Lake
-K key[=value] set the configuration file option named key
--old only rebuild modified modules (ignore transitive deps)
--update, -U update manifest before building
COMMANDS:
new <name> [<temp>] create a Lean package in a new directory
init <name> [<temp>] create a Lean package in the current directory
build [<targets>...] build targets
update update dependencies
upload <tag> upload build artifacts to a GitHub release
clean remove build outputs
script manage and run workspace scripts
scripts shorthand for `lake script list`
run <script> shorthand for `lake script run`
serve start the Lean language server
env <cmd> [<args>...] execute a command in the workspace's environment
exe <exe> [<args>...] build an exe and run it in the workspace's environment
See `lake help <command>` for more information on a specific command."
def templateHelp :=
s!"The initial configuration and starter files are based on the template:
std library and executable; default
exe executable only
lib library only
math library only with a mathlib dependency"
def helpNew :=
s!"Create a Lean package in a new directory
USAGE:
lake new <name> [<template>]
{templateHelp}"
def helpInit :=
s!"Create a Lean package in the current directory
USAGE:
lake init <name> [<template>]
{templateHelp}"
def helpBuild :=
"Build targets
USAGE:
lake build [<targets>...]
A target is specified with a string of the form:
[[@]<package>/][<target>|[+]<module>][:<facet>]
The optional `@` and `+` markers can be used to disambiguate packages
and modules from other kinds of targets (i.e., executables and libraries).
LIBRARY FACETS: build the library's ...
lean (default) Lean binaries (*.olean, *.ilean files)
static static binary (*.a file)
shared shared binary (*.so, *.dll, or *.dylib file)
MODULE FACETS: build the module's ...
deps transitive local imports & shared library dependencies
bin (default) Lean binaries (*.olean, *.ilean files) and *.c file
o *.o object file (of its C file)
dynlib shared library (e.g., for `--load-dynlib`)
TARGET EXAMPLES: build the ...
a default facet of target `a`
@a default target(s) of package `a`
+A olean and .ilean files of module `A`
a/b default facet of target `b` of package `a`
a/+A:c C file of module `A` of package `a`
:foo facet `foo` of the root package
A bare `build` command will build the default facet of the root package.
Package dependencies are not updated during a build."
def helpUpdate :=
"Update dependencies
USAGE:
lake update
This command sets up the directory with the package's dependencies
(i.e., `packagesDir`, which is, by default, `lake-packages`).
For each (transitive) git dependency, the specified commit is checked out
into a sub-directory of `packagesDir`. Already checked out dependencies are
updated to the latest version compatible with the package's configuration.
If there are dependencies on multiple versions of the same package, the
version materialized is undefined. The specific revision of the resolved
packages are cached in the `manifest.json` file of the `packagesDir`.
No copy is made of local dependencies."
def helpUpload :=
"Upload build artifacts to a GitHub release
USAGE:
lake upload <tag>
Packs the root package's `buildDir` into a `tar.gz` archive using `tar` and
then uploads the asset to the pre-existing GitHub release `tag` using `gh`."
def helpClean :=
"Remove build outputs
USAGE:
lake clean
Deletes the build directory of the package."
def helpScriptCli :=
"Manage Lake scripts
USAGE:
lake script <COMMAND>
COMMANDS:
list list available scripts
run <script> run a script
doc <script> print the docstring of a given script
See `lake help <command>` for more information on a specific command."
def helpScriptList :=
"List available scripts
USAGE:
lake script list
This command prints the list of all available scripts in the workspace."
def helpScriptRun :=
"Run a script
USAGE:
lake script run [<package>/]<script> [<args>...]
This command runs the given `script` from `package`, passing `args` to it.
Defaults to the root package.
A bare `run` command will run the default script(s) of the root package
(with no arguments)."
def helpScriptDoc :=
"Print a script's docstring
USAGE:
lake script doc [<package>/]<script>
Print the docstring of `script` in `package`. Defaults to the root package."
def helpServe :=
"Start the Lean language server
USAGE:
lake serve [-- <args>...]
Run the language server of the Lean installation (i.e., via `lean --server`)
with the package configuration's `moreServerArgs` field and `args`.
"
def helpEnv :=
"Execute a command in the workspace's environment
USAGE:
lake env <cmd> [<args>...]
Spawns a new process executing `cmd` with the given `args` and with
the environment set based on the workspace configuration and the detected
Lean/Lake installations.
Specifically, this command sets the following environment variables:
LAKE set to the detected Lake executable
LAKE_HOME set to the detected Lake home
LEAN_SYSROOT set to the detected Lean sysroot
LEAN_AR set to the detected Lean `ar` binary
LEAN_CC set to the detected `cc` (if not using bundled one)
LEAN_PATH adds the workspace's library directories
LEAN_SRC_PATH adds the workspace's source directories
PATH adds the workspace's library directories (Windows)
DYLD_LIBRARY_PATH adds the workspace's library directories (MacOS)
LD_LIBRARY_PATH adds the workspace's library directories (other Unix)"
def helpExe :=
"Build an executable target and run it in the workspace's environment
USAGE:
lake exe <exe-target> [<args>...]
Looks for the executable target in the workspace (see `lake help build` to
learn how to specify targets), builds it if it is out of date, and then runs
it with the given `args` in the workspace's environment (see `lake help env`
for how the environment is set)."
def helpScript : (cmd : String) String
| "list" => helpScriptList
| "run" => helpScriptRun
| "doc" => helpScriptDoc
| _ => helpScriptCli
def help : (cmd : String) String
| "new" => helpNew
| "init" => helpInit
| "build" => helpBuild
| "update" => helpUpdate
| "upload" => helpUpload
| "clean" => helpClean
| "script" => helpScriptCli
| "scripts" => helpScriptList
| "run" => helpScriptRun
| "serve" => helpServe
| "env" => helpEnv
| "exe" => helpExe
| _ => usage

205
src/lake/Lake/CLI/Init.lean Normal file
View File

@@ -0,0 +1,205 @@
/-
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner, Sebastian Ullrich, Mac Malone
-/
import Lake.Util.Git
import Lake.Util.Sugar
import Lake.Config.Package
import Lake.Config.Workspace
import Lake.Load.Config
import Lake.Build.Actions
namespace Lake
open Git System
/-- The default module of an executable in `std` package. -/
def defaultExeRoot : Name := `Main
/-- `elan` toolchain file name -/
def toolchainFileName : FilePath :=
"lean-toolchain"
def gitignoreContents :=
s!"/{defaultBuildDir}
/{defaultPackagesDir}/*
"
def libFileContents :=
s!"def hello := \"world\""
def mainFileName : FilePath :=
s!"{defaultExeRoot}.lean"
def mainFileContents (libRoot : String) :=
s!"import {libRoot}
def main : IO Unit :=
IO.println s!\"Hello, \{hello}!\"
"
def exeFileContents :=
s!"def main : IO Unit :=
IO.println s!\"Hello, world!\"
"
def stdConfigFileContents (pkgName libRoot : String) :=
s!"import Lake
open Lake DSL
package {pkgName} \{
-- add package configuration options here
}
lean_lib {libRoot} \{
-- add library configuration options here
}
@[default_target]
lean_exe {pkgName} \{
root := `Main
}
"
def exeConfigFileContents (pkgName exeRoot : String) :=
s!"import Lake
open Lake DSL
package {pkgName} \{
-- add package configuration options here
}
@[default_target]
lean_exe {exeRoot} \{
-- add executable configuration options here
}
"
def libConfigFileContents (pkgName libRoot : String) :=
s!"import Lake
open Lake DSL
package {pkgName} \{
-- add package configuration options here
}
@[default_target]
lean_lib {libRoot} \{
-- add library configuration options here
}
"
def mathConfigFileContents (pkgName libRoot : String) :=
s!"import Lake
open Lake DSL
package {pkgName} \{
-- add any package configuration options here
}
require mathlib from git
\"https://github.com/leanprover-community/mathlib4.git\"
@[default_target]
lean_lib {libRoot} \{
-- add any library configuration options here
}
"
def mathToolchainUrl : String :=
"https://raw.githubusercontent.com/leanprover-community/mathlib4/master/lean-toolchain"
/-- The options for the template argument to `initPkg`. -/
inductive InitTemplate
| std | exe | lib | math
deriving Repr, DecidableEq
instance : Inhabited InitTemplate := .std
def InitTemplate.parse? : String Option InitTemplate
| "std" => some .std
| "exe" => some .exe
| "lib" => some .lib
| "math" => some .math
| _ => none
def InitTemplate.configFileContents (pkgName root : String) : InitTemplate String
| .std => stdConfigFileContents pkgName root
| .lib => libConfigFileContents pkgName root
| .exe => exeConfigFileContents pkgName root
| .math => mathConfigFileContents pkgName root
def escapeName! : Name String
| .anonymous => "[anonymous]"
| .str .anonymous s => escape s
| .str n s => escapeName! n ++ "." ++ escape s
| _ => unreachable!
where
escape s := Lean.idBeginEscape.toString ++ s ++ Lean.idEndEscape.toString
/-- Initialize a new Lake package in the given directory with the given name. -/
def initPkg (dir : FilePath) (name : String) (tmp : InitTemplate) : LogIO PUnit := do
let pkgName := stringToLegalOrSimpleName name
-- determine the name to use for the root
-- use upper camel case unless the specific module name already exists
let (root, rootFile, rootExists) do
let root := pkgName
let rootFile := Lean.modToFilePath dir root "lean"
let rootExists rootFile.pathExists
if tmp = .exe || rootExists then
pure (root, rootFile, rootExists)
else
let root := toUpperCamelCase (toUpperCamelCaseString name |>.toName)
let rootFile := Lean.modToFilePath dir root "lean"
pure (root, rootFile, rootFile.pathExists)
-- write default configuration file
let configFile := dir / defaultConfigFile
if ( configFile.pathExists) then
error "package already initialized"
let rootNameStr := escapeName! root
let contents := tmp.configFileContents (escapeName! pkgName) rootNameStr
IO.FS.writeFile configFile contents
-- write example code if the files do not already exist
if tmp = .exe then
unless ( rootFile.pathExists) do
IO.FS.writeFile rootFile exeFileContents
else
if !rootExists then
IO.FS.createDirAll rootFile.parent.get!
IO.FS.writeFile rootFile libFileContents
if tmp = .std then
let mainFile := dir / mainFileName
unless ( mainFile.pathExists) do
IO.FS.writeFile mainFile <| mainFileContents rootNameStr
-- write Lean's toolchain to file (if it has one) for `elan`
if Lean.toolchain "" then
if tmp = .math then
download "lean-toolchain" mathToolchainUrl (dir / toolchainFileName)
else
IO.FS.writeFile (dir / toolchainFileName) <| Lean.toolchain ++ "\n"
-- update `.gitignore` with additional entries for Lake
let h IO.FS.Handle.mk (dir / ".gitignore") IO.FS.Mode.append
h.putStr gitignoreContents
-- initialize a `.git` repository if none already
unless ( FilePath.isDir <| dir / ".git") do
let repo := GitRepo.mk dir
try
repo.quietInit
unless upstreamBranch = "master" do
repo.checkoutBranch upstreamBranch
else
logWarning "failed to initialize git repository"
def init (pkgName : String) (tmp : InitTemplate) : LogIO PUnit :=
initPkg "." pkgName tmp
def new (pkgName : String) (tmp : InitTemplate) : LogIO PUnit := do
let dirName := pkgName.map fun chr => if chr == '.' then '-' else chr
IO.FS.createDir dirName
initPkg dirName pkgName tmp

384
src/lake/Lake/CLI/Main.lean Normal file
View File

@@ -0,0 +1,384 @@
/-
Copyright (c) 2021 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Load
import Lake.Build.Imports
import Lake.Util.Error
import Lake.Util.MainM
import Lake.Util.Cli
import Lake.CLI.Init
import Lake.CLI.Help
import Lake.CLI.Build
import Lake.CLI.Error
import Lake.CLI.Actions
import Lake.CLI.Serve
-- # CLI
open System
open Lean (Json toJson fromJson? LeanPaths)
namespace Lake
/-! ## General options for top-level `lake` -/
structure LakeOptions where
rootDir : FilePath := "."
configFile : FilePath := defaultConfigFile
leanInstall? : Option LeanInstall := none
lakeInstall? : Option LakeInstall := none
configOpts : NameMap String := {}
subArgs : List String := []
wantsHelp : Bool := false
verbosity : Verbosity := .normal
oldMode : Bool := false
updateDeps : Bool := false
/-- Get the Lean installation. Error if missing. -/
def LakeOptions.getLeanInstall (opts : LakeOptions) : Except CliError LeanInstall :=
match opts.leanInstall? with
| none => .error CliError.unknownLeanInstall
| some lean => .ok lean
/-- Get the Lake installation. Error if missing. -/
def LakeOptions.getLakeInstall (opts : LakeOptions) : Except CliError LakeInstall :=
match opts.lakeInstall? with
| none => .error CliError.unknownLakeInstall
| some lake => .ok lake
/-- Get the Lean and Lake installation. Error if either is missing. -/
def LakeOptions.getInstall (opts : LakeOptions) : Except CliError (LeanInstall × LakeInstall) := do
return ( opts.getLeanInstall, opts.getLakeInstall)
/-- Compute the Lake environment based on `opts`. Error if an install is missing. -/
def LakeOptions.computeEnv (opts : LakeOptions) : EIO CliError Lake.Env := do
Env.compute ( opts.getLakeInstall) ( opts.getLeanInstall)
/-- Make a `LoadConfig` from a `LakeOptions`. -/
def LakeOptions.mkLoadConfig (opts : LakeOptions) : EIO CliError LoadConfig :=
return {
env := opts.computeEnv
rootDir := opts.rootDir
configFile := opts.rootDir / opts.configFile
configOpts := opts.configOpts
leanOpts := Lean.Options.empty
}
export LakeOptions (mkLoadConfig)
/-! ## Monad -/
abbrev CliMainM := ExceptT CliError MainM
abbrev CliStateM := StateT LakeOptions CliMainM
abbrev CliM := ArgsT CliStateM
def CliM.run (self : CliM α) (args : List String) : BaseIO ExitCode := do
let (leanInstall?, lakeInstall?) findInstall?
let main := self args |>.run' {leanInstall?, lakeInstall?}
let main := main.run >>= fun | .ok a => pure a | .error e => error e.toString
main.run
instance : MonadLift LogIO CliStateM :=
fun x => do MainM.runLogIO x ( get).verbosity
instance : MonadLift OptionIO MainM where
monadLift x := x.adaptExcept (fun _ => 1)
/-! ## Argument Parsing -/
def takeArg (arg : String) : CliM String := do
match ( takeArg?) with
| none => throw <| CliError.missingArg arg
| some arg => pure arg
def takeOptArg (opt arg : String) : CliM String := do
match ( takeArg?) with
| none => throw <| CliError.missingOptArg opt arg
| some arg => pure arg
/--
Verify that there are no CLI arguments remaining
before running the given action.
-/
def noArgsRem (act : CliStateM α) : CliM α := do
let args getArgs
if args.isEmpty then act else
throw <| CliError.unexpectedArguments args
/-! ## Option Parsing -/
def getWantsHelp : CliStateM Bool :=
(·.wantsHelp) <$> get
def setLean (lean : String) : CliStateM PUnit := do
let leanInstall? findLeanCmdInstall? lean
modify ({· with leanInstall?})
def setConfigOpt (kvPair : String) : CliM PUnit :=
let pos := kvPair.posOf '='
let (key, val) :=
if pos = kvPair.endPos then
(kvPair.toName, "")
else
(kvPair.extract 0 pos |>.toName, kvPair.extract (kvPair.next pos) kvPair.endPos)
modifyThe LakeOptions fun opts =>
{opts with configOpts := opts.configOpts.insert key val}
def lakeShortOption : (opt : Char) CliM PUnit
| 'q' => modifyThe LakeOptions ({· with verbosity := .quiet})
| 'v' => modifyThe LakeOptions ({· with verbosity := .verbose})
| 'd' => do let rootDir takeOptArg "-d" "path"; modifyThe LakeOptions ({· with rootDir})
| 'f' => do let configFile takeOptArg "-f" "path"; modifyThe LakeOptions ({· with configFile})
| 'K' => do setConfigOpt <| takeOptArg "-K" "key-value pair"
| 'U' => modifyThe LakeOptions ({· with updateDeps := true})
| 'h' => modifyThe LakeOptions ({· with wantsHelp := true})
| opt => throw <| CliError.unknownShortOption opt
def lakeLongOption : (opt : String) CliM PUnit
| "--quiet" => modifyThe LakeOptions ({· with verbosity := .quiet})
| "--verbose" => modifyThe LakeOptions ({· with verbosity := .verbose})
| "--update" => modifyThe LakeOptions ({· with updateDeps := true})
| "--old" => modifyThe LakeOptions ({· with oldMode := true})
| "--dir" => do let rootDir takeOptArg "--dir" "path"; modifyThe LakeOptions ({· with rootDir})
| "--file" => do let configFile takeOptArg "--file" "path"; modifyThe LakeOptions ({· with configFile})
| "--lean" => do setLean <| takeOptArg "--lean" "path or command"
| "--help" => modifyThe LakeOptions ({· with wantsHelp := true})
| "--" => do let subArgs takeArgs; modifyThe LakeOptions ({· with subArgs})
| opt => throw <| CliError.unknownLongOption opt
def lakeOption :=
option {
short := lakeShortOption
long := lakeLongOption
longShort := shortOptionWithArg lakeShortOption
}
/-! ## Actions -/
/-- Verify the Lean version Lake was built with matches that of the give Lean installation. -/
def verifyLeanVersion (leanInstall : LeanInstall) : Except CliError PUnit := do
unless leanInstall.githash == Lean.githash do
throw <| CliError.leanRevMismatch Lean.githash leanInstall.githash
/-- Output the detected installs and verify the Lean version. -/
def verifyInstall (opts : LakeOptions) : ExceptT CliError MainM PUnit := do
IO.println s!"Lean:\n{repr <| opts.leanInstall?}"
IO.println s!"Lake:\n{repr <| opts.lakeInstall?}"
let (leanInstall, _) opts.getInstall
verifyLeanVersion leanInstall
def parseScriptSpec (ws : Workspace) (spec : String) : Except CliError (Package × String) :=
match spec.splitOn "/" with
| [script] => return (ws.root, script)
| [pkg, script] => return ( parsePackageSpec ws pkg, script)
| _ => throw <| CliError.invalidScriptSpec spec
def parseTemplateSpec (spec : String) : Except CliError InitTemplate :=
if spec.isEmpty then
pure default
else if let some tmp := InitTemplate.parse? spec then
pure tmp
else
throw <| CliError.unknownTemplate spec
/-! ## Commands -/
namespace lake
/-! ### `lake script` CLI -/
namespace script
protected def list : CliM PUnit := do
processOptions lakeOption
let config mkLoadConfig ( getThe LakeOptions)
noArgsRem do
let ws loadWorkspace config
ws.packageMap.forM fun _ pkg => do
let pkgName := pkg.name.toString (escape := false)
pkg.scripts.forM fun name _ =>
let scriptName := name.toString (escape := false)
IO.println s!"{pkgName}/{scriptName}"
protected nonrec def run : CliM PUnit := do
processOptions lakeOption
let config mkLoadConfig ( getThe LakeOptions)
let ws loadWorkspace config
if let some spec takeArg? then
let args takeArgs
let (pkg, scriptName) parseScriptSpec ws spec
if let some script := pkg.scripts.find? scriptName then
exit <| script.run args |>.run {opaqueWs := ws}
else do
throw <| CliError.unknownScript scriptName
else
for script in ws.root.defaultScripts do
exitIfErrorCode <| script.run [] |>.run {opaqueWs := ws}
exit 0
protected def doc : CliM PUnit := do
processOptions lakeOption
let spec takeArg "script name"
let config mkLoadConfig ( getThe LakeOptions)
noArgsRem do
let ws loadWorkspace config
let (pkg, scriptName) parseScriptSpec ws spec
if let some script := pkg.scripts.find? scriptName then
match script.doc? with
| some doc => IO.println doc
| none => throw <| CliError.missingScriptDoc scriptName
else
throw <| CliError.unknownScript scriptName
protected def help : CliM PUnit := do
IO.println <| helpScript <| ( takeArg?).getD ""
end script
def scriptCli : (cmd : String) CliM PUnit
| "list" => script.list
| "run" => script.run
| "doc" => script.doc
| "help" => script.help
| cmd => throw <| CliError.unknownCommand cmd
/-! ### `lake` CLI -/
protected def new : CliM PUnit := do
processOptions lakeOption
let pkgName takeArg "package name"
let template parseTemplateSpec <| ( takeArg?).getD ""
noArgsRem do MainM.runLogIO (new pkgName template) ( getThe LakeOptions).verbosity
protected def init : CliM PUnit := do
processOptions lakeOption
let pkgName takeArg "package name"
let template parseTemplateSpec <| ( takeArg?).getD ""
noArgsRem do MainM.runLogIO (init pkgName template) ( getThe LakeOptions).verbosity
protected def build : CliM PUnit := do
processOptions lakeOption
let opts getThe LakeOptions
let config mkLoadConfig opts
let ws loadWorkspace config opts.updateDeps
let targetSpecs takeArgs
let specs parseTargetSpecs ws targetSpecs
ws.runBuild (buildSpecs specs) opts.oldMode |>.run (MonadLog.io opts.verbosity)
protected def resolveDeps : CliM PUnit := do
processOptions lakeOption
let opts getThe LakeOptions
let config mkLoadConfig opts
noArgsRem do
liftM <| discard <| (loadWorkspace config opts.updateDeps).run (MonadLog.io opts.verbosity)
protected def update : CliM PUnit := do
processOptions lakeOption
let opts getThe LakeOptions
let config mkLoadConfig opts
noArgsRem do
liftM <| (updateManifest config).run (MonadLog.io opts.verbosity)
protected def upload : CliM PUnit := do
processOptions lakeOption
let tag takeArg "release tag"
let opts getThe LakeOptions
let config mkLoadConfig opts
let ws loadWorkspace config
noArgsRem do
liftM <| uploadRelease ws.root tag |>.run (MonadLog.io opts.verbosity)
protected def printPaths : CliM PUnit := do
processOptions lakeOption
let opts getThe LakeOptions
let config mkLoadConfig opts
printPaths config ( takeArgs) opts.oldMode opts.verbosity
protected def clean : CliM PUnit := do
processOptions lakeOption
let config mkLoadConfig ( getThe LakeOptions)
noArgsRem do ( loadWorkspace config).clean
protected def script : CliM PUnit := do
if let some cmd takeArg? then
processLeadingOptions lakeOption -- between `lake script <cmd>` and args
if ( getWantsHelp) then
IO.println <| helpScript cmd
else
scriptCli cmd
else
throw <| CliError.missingCommand
protected def serve : CliM PUnit := do
processOptions lakeOption
let opts getThe LakeOptions
let args := opts.subArgs.toArray
let config mkLoadConfig opts
noArgsRem do exit <| serve config args
protected def env : CliM PUnit := do
let cmd takeArg "command"; let args takeArgs
let config mkLoadConfig ( getThe LakeOptions)
let ws loadWorkspace config
let ctx := mkLakeContext ws
exit <| (env cmd args.toArray).run ctx
protected def exe : CliM PUnit := do
let exeName takeArg "executable name"
let args takeArgs
let opts getThe LakeOptions
let config mkLoadConfig opts
let ws loadWorkspace config
let ctx := mkLakeContext ws
exit <| (exe exeName args.toArray opts.oldMode).run ctx
protected def selfCheck : CliM PUnit := do
processOptions lakeOption
noArgsRem do verifyInstall ( getThe LakeOptions)
protected def help : CliM PUnit := do
IO.println <| help <| ( takeArg?).getD ""
end lake
def lakeCli : (cmd : String) CliM PUnit
| "new" => lake.new
| "init" => lake.init
| "build" => lake.build
| "update" => lake.update
| "resolve-deps" => lake.resolveDeps
| "upload" => lake.upload
| "print-paths" => lake.printPaths
| "clean" => lake.clean
| "script" => lake.script
| "scripts" => lake.script.list
| "run" => lake.script.run
| "serve" => lake.serve
| "env" => lake.env
| "exe" => lake.exe
| "self-check" => lake.selfCheck
| "help" => lake.help
| cmd => throw <| CliError.unknownCommand cmd
def lake : CliM PUnit := do
match ( getArgs) with
| [] => IO.println usage
| ["--version"] => IO.println uiVersionString
| _ => -- normal CLI
processLeadingOptions lakeOption -- between `lake` and command
if let some cmd takeArg? then
processLeadingOptions lakeOption -- between `lake <cmd>` and args
if ( getWantsHelp) then
IO.println <| help cmd
else
lakeCli cmd
else
if ( getWantsHelp) then
IO.println usage
else
throw <| CliError.missingCommand
def cli (args : List String) : BaseIO ExitCode :=
(lake).run args

View File

@@ -0,0 +1,67 @@
/-
Copyright (c) 2022 Mac Malone. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mac Malone
-/
import Lake.Load
import Lake.Build
import Lake.Util.MainM
namespace Lake
open Lean (Json toJson fromJson? LeanPaths)
/-- Exit code to return if `print-paths` cannot find the config file. -/
def noConfigFileCode : ExitCode := 2
/--
Environment variable that is set when `lake serve` cannot parse the Lake configuration file
and falls back to plain `lean --server`.
-/
def invalidConfigEnvVar := "LAKE_INVALID_CONFIG"
/--
Build a list of imports of the package
and print the `.olean` and source directories of every used package.
If no configuration file exists, exit silently with `noConfigFileCode` (i.e, 2).
The `print-paths` command is used internally by Lean 4 server.
-/
def printPaths (config : LoadConfig) (imports : List String := [])
(oldMode : Bool := false) (verbosity : Verbosity := .normal) : MainM PUnit := do
let configFile := config.rootDir / config.configFile
if ( configFile.pathExists) then
if let some errLog := ( IO.getEnv invalidConfigEnvVar) then
IO.eprint errLog
IO.eprintln s!"Invalid Lake configuration. Please restart the server after fixing the Lake configuration file."
exit 1
let ws MainM.runLogIO (loadWorkspace config) verbosity
let dynlibs ws.runBuild (buildImportsAndDeps imports) oldMode
|>.run (MonadLog.eio verbosity)
IO.println <| Json.compress <| toJson {
oleanPath := ws.leanPath
srcPath := ws.leanSrcPath
loadDynlibPaths := dynlibs
: LeanPaths
}
else
exit noConfigFileCode
/--
Start the Lean LSP for the `Workspace` loaded from `config`
with the given additional `args`.
-/
def serve (config : LoadConfig) (args : Array String) : IO UInt32 := do
let (extraEnv, moreServerArgs) do
let (log, ws?) loadWorkspace config |>.captureLog
IO.eprint log
if let some ws := ws? then
let ctx := mkLakeContext ws
pure ( LakeT.run ctx getAugmentedEnv, ws.root.moreServerArgs)
else
IO.eprint "warning: package configuration has errors, falling back to plain `lean --server`"
pure (config.env.installVars.push (invalidConfigEnvVar, log), #[])
( IO.Process.spawn {
cmd := config.env.lean.lean.toString
args := #["--server"] ++ moreServerArgs ++ args
env := extraEnv
}).wait

Some files were not shown because too many files have changed in this diff Show More