Skip to content

Commit af56b82

Browse files
authored
Merge pull request #4193 from FStarLang/gebner_switch_boot_order
Reorder bootstrapping: use current ulib for compiler and plugins
2 parents 040612a + 65001e6 commit af56b82

15 files changed

Lines changed: 141 additions & 104 deletions

File tree

Makefile

Lines changed: 50 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,16 @@ endif
4141
FSTAR0_EXE ?= stage0/out/bin/fstar.exe
4242

4343
# This is hardcoding some dune paths, with internal (non-public) names.
44-
# This is motivated by dune installing packages as a unit, so I could not
45-
# install simply the bare compiler and then use it to build the full compiler
46-
# without splitting into many packages, which complicates the namespaces.
4744
#
48-
# Also, when we want to extract src/ for stage 2, we must call FSTAR1_FULL_EXE,
45+
# When we want to extract src/ for stage 2, we must call FSTAR1_FULL_EXE,
4946
# but it's in a bad location (without a library next to it). So, we must
50-
# pass FSTAR_LIB explicitly. This is the only case where this is needed, the rest
51-
# of stages don't need a library. The alternative is to install it, and use
47+
# pass FSTAR_LIB explicitly. The alternative is to install it, and use
5248
# $(INSTALLED_FSTAR1_FULL_EXE), but that introduces a spurious dependency to the
5349
# stage 1 libraries for the stage 2, which does not need them at all (currently?).
5450
#
5551
# I'd love a better alternative.
56-
FSTAR1_BARE_EXE := stage1/dune/_build/default/fstarc-bare/fstarc1_bare.exe
5752
FSTAR1_FULL_EXE := stage1/dune/_build/default/fstarc-full/fstarc1_full.exe
5853
INSTALLED_FSTAR1_FULL_EXE := stage1/out/bin/fstar.exe
59-
FSTAR2_BARE_EXE := stage2/dune/_build/default/fstarc-bare/fstarc2_bare.exe
6054
FSTAR2_FULL_EXE := stage2/dune/_build/default/fstarc-full/fstarc2_full.exe
6155
INSTALLED_FSTAR2_FULL_EXE := stage2/out/bin/fstar.exe
6256
# Stage3 = Stage2 + Pulse
@@ -79,13 +73,11 @@ endif
7973
build: 3
8074

8175
0: $(FSTAR0_EXE)
82-
1.bare: $(FSTAR1_BARE_EXE)
8376
1.tests: $(TESTS1_EXE)
8477
1.full: $(FSTAR1_FULL_EXE)
85-
2.bare: $(FSTAR2_BARE_EXE)
8678
2.tests: $(TESTS2_EXE)
8779
2.full: $(FSTAR2_FULL_EXE)
88-
# No tests or bare for stage3
80+
# No tests for stage3
8981
3.full: $(FSTAR3_FULL_EXE)
9082

9183

@@ -108,15 +100,15 @@ build: 3
108100

109101
stage0/out/bin/fstar.exe: .stage0.touch
110102
$(call bold_msg, "STAGE 0")
111-
mkdir -p stage0/ulib/.cache # prevent warnings
112-
$(MAKE) -C stage0 minimal # build: only fstar.exe and set-up lib sources
103+
$(MAKE) -C stage0 install_bin # build: only fstar.exe
113104
$(MAKE) -C stage0 trim # We don't need OCaml build files.
114105

115106
.bare1.src.touch: $(FSTAR0_EXE) .force
116-
$(call bold_msg, "EXTRACT", "STAGE 1 FSTARC-BARE")
107+
$(call bold_msg, "EXTRACT", "STAGE 1 FSTARC")
117108
env \
118109
SRC=src/ \
119110
FSTAR_EXE=$(FSTAR0_EXE) \
111+
FSTAR_LIB=$(abspath ulib) \
120112
CACHE_DIR=stage1/fstarc.checked/ \
121113
OUTPUT_DIR=stage1/fstarc.ml/ \
122114
CODEGEN=OCaml \
@@ -129,6 +121,7 @@ stage0/out/bin/fstar.exe: .stage0.touch
129121
env \
130122
SRC=src/ \
131123
FSTAR_EXE=$(FSTAR0_EXE) \
124+
FSTAR_LIB=$(abspath ulib) \
132125
CACHE_DIR=stage1/tests.checked/ \
133126
OUTPUT_DIR=stage1/tests.ml/ \
134127
CODEGEN=PluginNoLib \
@@ -143,11 +136,6 @@ stage0/out/bin/fstar.exe: .stage0.touch
143136
[ -e $@ ] || touch $@
144137
find -L src/ml -newer $@ -exec touch $@ \; -quit
145138

146-
$(FSTAR1_BARE_EXE): .bare1.src.touch .src.ml.touch $(MAYBEFORCE)
147-
$(call bold_msg, "BUILD", "STAGE 1 FSTARC-BARE")
148-
$(MAKE) -C stage1 fstarc-bare
149-
touch -c $@
150-
151139
$(TESTS1_EXE): .tests1.src.touch .src.ml.touch $(MAYBEFORCE)
152140
$(call bold_msg, "BUILD", "STAGE 1 TESTS")
153141
$(MAKE) -C stage1 tests BUILD_FSTAR_OCAML_TESTS=true
@@ -156,11 +144,11 @@ $(TESTS1_EXE): .tests1.src.touch .src.ml.touch $(MAYBEFORCE)
156144
stage1-unit-tests: $(TESTS1_EXE)
157145
FSTAR_LIB=$(CURDIR)/ulib $(TESTS1_EXE)
158146

159-
.full1.src.touch: $(FSTAR1_BARE_EXE) .force
147+
.full1.src.touch: $(FSTAR0_EXE) .force
160148
$(call bold_msg, "EXTRACT", "STAGE 1 PLUGINS")
161149
env \
162150
SRC=ulib/ \
163-
FSTAR_EXE=$(FSTAR1_BARE_EXE) \
151+
FSTAR_EXE=$(FSTAR0_EXE) \
164152
CACHE_DIR=stage1/plugins.checked/ \
165153
OUTPUT_DIR=stage1/plugins.ml/ \
166154
CODEGEN=PluginNoLib \
@@ -241,14 +229,6 @@ $(FSTAR1_FULL_EXE): .bare1.src.touch .full1.src.touch .src.ml.touch $(MAYBEFORCE
241229
TOUCH=$@ \
242230
$(MAKE) -f mk/tests-2.mk ocaml
243231

244-
$(FSTAR2_BARE_EXE): .bare2.src.touch .src.ml.touch $(MAYBEFORCE)
245-
$(call bold_msg, "BUILD", "STAGE 2 FSTARC-BARE")
246-
$(MAKE) -C stage2 fstarc-bare
247-
touch -c $@
248-
# ^ Note, even if we don't release fstar-bare itself,
249-
# it is still part of the build of the full fstar, so
250-
# we set the release flag to have a more incremental build.
251-
252232
$(TESTS2_EXE): .tests2.src.touch .src.ml.touch $(MAYBEFORCE)
253233
$(call bold_msg, "BUILD", "STAGE 2 TESTS")
254234
$(MAKE) -C stage2 tests BUILD_FSTAR_OCAML_TESTS=true
@@ -257,11 +237,12 @@ $(TESTS2_EXE): .tests2.src.touch .src.ml.touch $(MAYBEFORCE)
257237
stage2-unit-tests: $(TESTS2_EXE)
258238
FSTAR_LIB=$(CURDIR)/ulib $(TESTS2_EXE)
259239

260-
.full2.src.touch: $(FSTAR2_BARE_EXE) .force
240+
.full2.src.touch: $(FSTAR1_FULL_EXE) .force
261241
$(call bold_msg, "EXTRACT", "STAGE 2 PLUGINS")
262242
env \
263243
SRC=ulib/ \
264-
FSTAR_EXE=$(FSTAR2_BARE_EXE) \
244+
FSTAR_EXE=$(FSTAR1_FULL_EXE) \
245+
FSTAR_LIB=$(abspath ulib) \
265246
CACHE_DIR=stage2/plugins.checked/ \
266247
OUTPUT_DIR=stage2/plugins.ml/ \
267248
CODEGEN=PluginNoLib \
@@ -376,6 +357,12 @@ endif
376357
.stage2.src.touch: .bare2.src.touch .full2.src.touch .alib2.src.touch .plib2.src.touch .src.ml.touch
377358
touch $@
378359

360+
.stage1-for-bump.src.touch: .bare1.src.touch .full1.src.touch .src.ml.touch
361+
touch $@
362+
363+
.stage2-for-bump.src.touch: .bare2.src.touch .full2.src.touch .src.ml.touch
364+
touch $@
365+
379366
.pulse-plugin.src.touch: stage2
380367
env \
381368
FSTAR_EXE=$(abspath $(INSTALLED_FSTAR2_FULL_EXE)) \
@@ -548,15 +535,15 @@ package-src-3: .stage3.src.touch .tests2.src.touch .force
548535
package: package-3
549536
package-src: package-src-3
550537

551-
test-1-bare: override FSTAR_EXE := $(abspath $(FSTAR1_BARE_EXE))
538+
test-1-bare: override FSTAR_EXE := $(abspath $(INSTALLED_FSTAR1_FULL_EXE))
552539
test-1-bare: override FSTAR_LIB := $(abspath ulib)
553-
test-1-bare: $(FSTAR1_BARE_EXE)
554-
$(MAKE) -C bare-tests
540+
test-1-bare: stage1
541+
$(MAKE) -C bare-tests FSTAR_EXE=$(FSTAR_EXE) FSTAR_LIB=$(FSTAR_LIB)
555542

556-
test-2-bare: override FSTAR_EXE := $(abspath $(FSTAR2_BARE_EXE))
543+
test-2-bare: override FSTAR_EXE := $(abspath $(INSTALLED_FSTAR2_FULL_EXE))
557544
test-2-bare: override FSTAR_LIB := $(abspath ulib)
558-
test-2-bare: $(FSTAR2_BARE_EXE)
559-
$(MAKE) -C bare-tests
545+
test-2-bare: stage2
546+
$(MAKE) -C bare-tests FSTAR_EXE=$(FSTAR_EXE) FSTAR_LIB=$(FSTAR_LIB)
560547

561548
test: test-3
562549

@@ -640,46 +627,53 @@ ci: .force
640627

641628
save: stage0_new
642629

643-
stage0_new: TO=stage0_new
644-
stage0_new: .stage2.src.touch
630+
# Shared logic for creating a stage0 snapshot from a given stage.
631+
define do-stage0-snapshot
645632
$(call bold_msg, "SNAPSHOT", "$(TO)")
646633
rm -rf "$(TO)"
647-
.scripts/src-install.sh "stage2" "$(TO)"
634+
mkdir -p "$(1)"/ulib.ml "$(1)"/ulib.pluginml # rsync fails with dangling symlinks
635+
.scripts/src-install.sh "$(1)" "$(TO)"
648636
# Trim it a bit...
649637
rm -rf "$(TO)/src" # no need for compiler F* sources
650-
rm -rf "$(TO)/ulib/.hints" # this library won't be checked
651-
rm -rf "$(TO)/ulib.pluginml" # we won't build plugins against stage0
638+
rm -rf "$(TO)/ulib"* # stage0 does not need its own ulib copy
652639
rm -rf "$(TO)/dune/libplugin" # idem
653640
rm -rf "$(TO)/dune/libapp" # we won't even build apps
654641
rm -rf "$(TO)/dune/tests" # we won't build tests
655642
rm -rf "$(TO)/karamel" # only needed in source packages
643+
endef
656644

657-
bump-stage0: stage0_new
645+
stage0_new: TO=stage0_new
646+
stage0_new: .stage2-for-bump.src.touch
647+
$(call do-stage0-snapshot,stage2)
648+
649+
# Faster alternative: snapshot from stage1 (only requires building stage1).
650+
stage0_new_from_stage1: TO=stage0_new
651+
stage0_new_from_stage1: .stage1-for-bump.src.touch
652+
$(call do-stage0-snapshot,stage1)
653+
654+
# Shared logic for finalizing a stage0 bump.
655+
define do-bump-stage0
658656
$(call bold_msg, "BUMP!")
659657
# Replace stage0
660658
rm -rf stage0
661659
mv stage0_new stage0
662660
echo 'out' >> stage0/.gitignore
663661
echo '** -diff -merge linguist-generated=true' >> stage0/.gitattributes
664662
# Now that stage0 supports all features, we can return to a clean state
665-
# where the 01 makefile is equal to the 12 makefile. Same for stage1
666-
# support and config code, we just take it from the stage2.
663+
# where the 01 makefile is equal to the 12 makefile.
667664
rm -f mk/generic-0.mk
668665
ln -sf generic-1.mk mk/generic-0.mk
669666
cp mk/fstar-12.mk mk/fstar-01.mk
670667
sed -i 's,include mk/generic-1.mk,include mk/generic-0.mk,' mk/fstar-01.mk
671-
rm -rf stage1
672-
cp -r stage2 stage1
673-
rm -rf stage1/dune/_build
674-
# Rename dune executables: stage1 must use fstarc1_*, not fstarc2_*
675-
sed -i 's/fstarc2_/fstarc1_/g' stage1/dune/fstarc-bare/dune
676-
sed -i 's/fstarc2_/fstarc1_/g' stage1/dune/fstarc-full/dune
677-
sed -i 's/fstarc2_/fstarc1_/g' stage1/dune/tests/dune
678-
mv stage1/dune/fstarc-bare/fstarc2_bare.ml stage1/dune/fstarc-bare/fstarc1_bare.ml
679-
mv stage1/dune/fstarc-full/fstarc2_full.ml stage1/dune/fstarc-full/fstarc1_full.ml
680-
mv stage1/dune/tests/fstarc2_tests.ml stage1/dune/tests/fstarc1_tests.ml
681668
rm -f stage1/dune/fstar-guts/app
682-
ln -Trsf stage0/ulib/ml/app stage1/dune/fstar-guts/app
669+
ln -Trsf ulib/ml/app stage1/dune/fstar-guts/app
670+
endef
671+
672+
bump-stage0: stage0_new
673+
$(do-bump-stage0)
674+
675+
bump-stage0-from-stage1: stage0_new_from_stage1
676+
$(do-bump-stage0)
683677

684678
# This rule brings a stage0 from an OLD fstar repo. Only useful for migrating.
685679
bring-stage0: .force
@@ -688,9 +682,6 @@ bring-stage0: .force
688682
mkdir stage0
689683
cp -r $(FROM)/ocaml -T stage0
690684
ln -Tsrf mk/stage0.mk stage0/Makefile
691-
cp -r $(FROM)/ulib -T stage0/ulib
692-
find stage0/ulib -name '*.checked' -delete
693-
find stage0/ulib -name '*.hints' -delete
694685
echo '/lib' >> stage0/.gitignore
695686
echo '** -diff -merge' >> stage0/.gitattributes
696687
echo '** linguist-generated=true' >> stage0/.gitattributes
@@ -718,7 +709,6 @@ clean-depend: .force
718709
clean-0: .force
719710
$(call bold_msg, "CLEAN", "STAGE 0")
720711
$(MAKE) -C stage0 clean
721-
rm -rf stage0/ulib/.cache # created only to prevent warnings, always empty
722712

723713
define clean-stage
724714
$(call bold_msg, "CLEAN", "STAGE $(1)")

bare-tests/Cfg.fst.config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"fstar_exe": "../stage1/dune/_build/default/fstarc-bare/fstarc1_bare.exe",
2+
"fstar_exe": "../stage1/dune/_build/default/fstarc-full/fstarc1_full.exe",
33
"options": [
44
"--no_prelude"
55
],

bare-tests/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ OTHERFLAGS += --warn_error -241
1616
# warnings about missing checked files since it will mess up the output.
1717

1818
FSTAR_ROOT ?= ..
19-
FSTAR_EXE ?= $(abspath $(FSTAR_ROOT)/stage1/dune/_build/default/fstarc-bare/fstarc1_bare.exe)
19+
FSTAR_EXE ?= $(abspath $(FSTAR_ROOT)/stage1/dune/_build/default/fstarc-full/fstarc1_full.exe)
2020
export FSTAR_LIB ?= $(abspath $(FSTAR_ROOT)/ulib)
2121
include $(FSTAR_ROOT)/mk/test.mk
2222

doc/ref/bootstrapping.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Bootstrapping
2+
3+
The F\* compiler is written in F\*, extracted to OCaml, and compiled
4+
with dune. The build uses a multi-stage bootstrapping process to
5+
ensure that the compiler can compile itself.
6+
7+
## Components
8+
9+
The compiler has three main components:
10+
11+
- **Compiler** (`src/`): The F\* compiler source code (FStarC.\*
12+
modules), extracted to OCaml.
13+
- **Plugins** (`ulib/`): Tactic and metaprogramming plugins
14+
(FStar.Tactics.\*, etc.), extracted from the standard library using
15+
`--codegen PluginNoLib`.
16+
- **Standard library** (`ulib/`): The F\* standard library (Prims,
17+
FStar.\* modules), verified and extracted to OCaml.
18+
19+
## Stages
20+
21+
### Stage 0
22+
23+
A pre-built OCaml snapshot of the compiler, stored in `stage0/`. It
24+
contains extracted OCaml sources and a dune build configuration, but
25+
no copy of the standard library. Stage 0 is periodically updated via
26+
`make bump-stage0`.
27+
28+
### Stage 1
29+
30+
Built by the stage 0 compiler using the current ulib:
31+
32+
1. **Extract compiler**: stage 0 lax-checks `src/` using the current
33+
`ulib/` (via `FSTAR_LIB`) and extracts OCaml.
34+
2. **Extract plugins**: stage 0 lax-checks the plugin modules in
35+
`ulib/` and extracts them.
36+
3. **Build**: dune compiles the extracted compiler + plugins into the
37+
stage 1 executable.
38+
4. **Verify ulib**: stage 1 fully verifies and extracts the standard
39+
library.
40+
41+
### Stage 2
42+
43+
Same structure as stage 1, but built by the stage 1 compiler. This
44+
is the stage that is checked for bootstrapping stability: the
45+
`boot-diff` target re-extracts the compiler with the stage 2 compiler
46+
and verifies that the output matches stage 2's own extracted sources.
47+
48+
### Stage 3
49+
50+
Stage 2 plus the Pulse separation logic DSL (baked-in as a plugin).
51+
This is the compiler that is released and tested.
52+
53+
## Key Make targets
54+
55+
| Target | Description |
56+
|---|---|
57+
| `make build` (= `make 3`) | Build through stage 3 |
58+
| `make 1` / `make 2` | Build stage 1 / stage 2 and set `out/` symlink |
59+
| `make ci` | Build stage 2, run tests, boot-diff, fsharp |
60+
| `make test` | Run tests with stage 3 |
61+
| `make boot-diff` | Verify bootstrapping stability (stage 2 vs 2+1) |
62+
| `make bump-stage0` | Update stage 0 snapshot from stage 2 ML files |
63+
| `make bump-stage0-from-stage1` | Update stage 0 snapshot from stage 1 (faster) |
64+
65+
## Bumping stage 0
66+
67+
When changes to the compiler source (`src/`) or standard library
68+
(`ulib/`) require updating the stage 0 snapshot:
69+
70+
```sh
71+
make bump-stage0 # snapshot from stage 2 (full bootstrap)
72+
make bump-stage0-from-stage1 # snapshot from stage 1 (faster)
73+
```
74+
75+
The stage 1 variant is faster since it only requires building one
76+
stage instead of two. Both snapshot the extracted OCaml into
77+
`stage0/` and reset `mk/fstar-01.mk` and `mk/generic-0.mk` to
78+
match their stage 1→2 counterparts.
79+
80+
## Source packages
81+
82+
Source packages (built via `make package-src`) are self-contained
83+
OCaml distributions that can be built without a pre-existing F\*
84+
compiler. They use `stage0/Makefile` (= `mk/src_package_mk.mk`)
85+
which builds the compiler, verifies the library, and installs
86+
everything.

examples/algorithms/StringMatching.fst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ let lemma_mod_add_3 (a b c:int) (p:pos)
124124
= lemma_mod_add_distr_l (a + b) c p;
125125
lemma_mod_add_distr_l (a + c) b p
126126

127-
#push-options "--z3rlimit_factor 10 --ifuel 0 --fuel 2 --split_queries no"
127+
#push-options "--z3rlimit_factor 10 --ifuel 0 --fuel 2 --split_queries always"
128128
#restart-solver
129129
// This is the main utility lemma on the hash function
130130
// It allows inverting the hash to inspect the most significant digit

mk/stage.mk

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ else
2828
DUNE=dune
2929
endif
3030

31-
fstarc-bare: _force
32-
cd dune && $(DUNE) build $(FSTAR_DUNE_BUILD_OPTIONS) fstarc-bare
33-
3431
tests: _force
3532
cd dune && $(DUNE) build $(FSTAR_DUNE_BUILD_OPTIONS) tests
3633

stage1/dune/fstar-guts/app

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
../../../stage0/ulib/ml/app
1+
../../../ulib/ml/app

stage1/dune/fstarc-bare/dune

Lines changed: 0 additions & 10 deletions
This file was deleted.

stage1/dune/fstarc-bare/fstarc1_bare.ml

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)