Skip to content

Commit f2cabe5

Browse files
author
Ryan Lahfa
committed
docs(user): add developer docs
Signed-off-by: Ryan Lahfa <[email protected]>
1 parent 3a1d6bc commit f2cabe5

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed

docs/user/README.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# Aeneas user documentation - developer docs
2+
3+
## Architecture
4+
5+
This is a separate `flake.nix` setup from the root repository's one, but it relies on Aeneas' Lean library from this repository.
6+
7+
We pull Lean 4's upstream flake to build Lean in Nix, use some forked Alectryon-related tooling to assemble a mdBook HTML output.
8+
9+
### How to add new files?
10+
11+
If these files are not supposed to be inked by Alectryon (i.e. display interactive goals in the browser), they can be extended following [the vanilla mdBook documentation](https://rust-lang.github.io/mdBook/guide/creating.html) in the `src/` directory.
12+
13+
If these files are supposed to be inked by Alectryon:
14+
15+
- they need to appear in `src/lean/basics` as `xyz.lean` and `xyz.lean.md`
16+
- the Markdown file version should be included in the `SUMMARY.md` file.
17+
- the contents of `xyz.lean.md` by default should be the same as the others one, i.e. a Lean code block containing `{{#include xyz.lean}}`
18+
19+
### How to add a new directory containing Lean files?
20+
21+
This requires a change in the `flake.nix`, find the place where the `literate` package is defined:
22+
23+
```nix
24+
literate = buildLeanPackage {
25+
name = "literate";
26+
deps = [ aeneas-base ];
27+
src = ./.;
28+
roots = [
29+
{
30+
mod = "src/lean/basics";
31+
glob = "submodules";
32+
}
33+
];
34+
};
35+
```
36+
37+
Add a new `root` as it follows, assuming your new module is `src/lean/advanced`:
38+
39+
```nix
40+
literate = buildLeanPackage {
41+
name = "literate";
42+
deps = [ aeneas-base ];
43+
src = ./.;
44+
roots = [
45+
{
46+
mod = "src/lean/basics";
47+
glob = "submodules";
48+
}
49+
{
50+
mod = "src/lean/advanced";
51+
glob = "submodules";
52+
}
53+
];
54+
};
55+
```
56+
57+
### How to add a new Lean dependency to the project?
58+
59+
Each `buildLeanPackage` can take a list of `deps`.
60+
61+
Two cases:
62+
63+
- either, this is a local dependency and this can be built like the `Base` (Aeneas standard library) one.
64+
- or, this is a remote dependency and this is often added to a Lakefile, this can be built like `Mathlib` and the others.
65+
66+
## How to build?
67+
68+
```console
69+
$ nix build .#docs
70+
```
71+
72+
## How to deploy?
73+
74+
The `result/` symlink is a HTML webroot, this can be deployed as a static website.
75+
76+
## How to update the dependencies?
77+
78+
You just updated `backends/lean/lakefile.lean` dependencies or the Lean version.
79+
80+
### Lean version
81+
82+
Update the flake URI in `flake.nix`, this will trigger a mass rebuild of the documentation: rebootstrapping Lean 4 (this may take a couple of minutes), rebuilding Mathlib4 (this may take up to 20 minutes on a fast computer), building Aeneas standard library and finally the documentation.
83+
84+
### Updating Aeneas standard library's dependencies
85+
86+
You may need to change all `hash = "...";` reference between `aeneas-base =` and `in`, which are the dependencies of `Base`, Aeneas standard library.
87+
88+
To do so, you can replace `hash = "...";` by `hash = lib.fakeHash;`, and rebuild, i.e. `nix build .#doc`, Nix will provide the actual SRI hash.
89+
90+
_Advice_ : build with `--keep-going` to get all hashes at once instead of having to copy one hash per one hash.
91+
92+
## My build is failing due to a compilation error but it works outside of Nix
93+
94+
This is highly likely due to a mismatch between the dependencies in the Nix setup and outside.
95+
96+
The Nix setup reads the `lakefile-manifest.json`, but this lockfile is insufficient to lock purely the dependencies (NAR SHA256 serialization are missing).
97+
98+
To overcome this, they are specified manually in `flake.nix`, but each time the Aeneas standard library updates their dependencies, the `flake.nix` needs to have all its hash rewritten. Refer to "How to update" for guidance.
99+
100+
In the future, it could be smart to extend the lockfile format or write another file besides in the Aeneas standard library containing all NAR SHA256 serializations and link it in the Lake build system so that each updates would regenerate this file.
101+
102+
# Reference documentation
103+
104+
## `fetchFromLakeManifest`
105+
106+
This is a simple Nix function that looks inside a Lean manifest and pulls the Git input information, it does not handle yet automatically fetching the NAR SHA256 serialization of the Git input as Lake does not store this information in its lockfile.
107+
108+
This means that whenever you are updating the manifest, you need to replace all `hash = "...";` by `hash = lib.fakeHash;` to bust the cache, otherwise you will run into compilation errors.
109+
110+
## `addFakeFiles`
111+
112+
Mathlib4 depends on `proof-widgets`, a Lean library which depends on Node.js for its build system, to avoid wasting time to package multi-language dependency system, `addFakeFiles` is a function to poly-fill by **empty files** specific modules, fooling the build system into believing that these files have been built externally.
113+
114+
## `renderPackage`
115+
116+
This is a function to analyze an entire Lean package via [Alectryon](https://github.com/cpitclaudel/alectryon) and [LeanInk](https://github.com/leanprover/LeanInk) and assemble this as a tree of symlinks for each module in the package.

docs/user/flake.nix

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
description = "Aeneas documentation";
44

5+
# When you update Lean in Aeneas, update this URI as well.
56
inputs.lean.url = "github:leanprover/lean4/v4.11.0-rc2";
67
inputs.flake-utils.follows = "lean/flake-utils";
78
inputs.mdBook = {
@@ -33,6 +34,11 @@
3334
});
3435
doCheck = false;
3536
});
37+
38+
# This is the final book:
39+
# * We copy the classical mdBook contents.
40+
# * We interpose the inked Lean files (*.lean.md) in the source tree
41+
# Finally, we call mdBook to process this soup into a HTML webroot you can deploy.
3642
book = stdenv.mkDerivation {
3743
name = "aeneas-doc";
3844
src = doc-src;
@@ -91,6 +97,13 @@
9197
fetchFromLakeManifest = leanLib.fetchFromLakeManifest manifest;
9298
inherit (leanLib) addFakeFiles;
9399

100+
# To update the dependencies, just ensure that the `lake-manifest.json`
101+
# in `backends/lean` is up to date. Then, replace each `hash = "...";`
102+
# by `hash = lib.fakeHash;` Then, perform `nix build .#doc
103+
# --keep-going` to get all the new hashes. Copy them back here and
104+
# commit this result.
105+
106+
# Those are specifically the Mathlib4 dependencies.
94107
batteries = buildLeanPackage {
95108
name = "Batteries";
96109
src = fetchFromLakeManifest {
@@ -129,6 +142,12 @@
129142
hash = "sha256-jPvUi73NylxFiU5V0tjK92M0hJfHWZi5ULZldDwctYY=";
130143
};
131144

145+
# ProofWidgets require a special Node.js build pass encoded in its
146+
# Lakefile In principle, we could parse the Node.js lockfile, lock it
147+
# using Nix, generate these JS files and link them properly in the
148+
# build process. But we make no use of ProofWidgets in Aeneas manual,
149+
# so we just polyfill all of these files by empty files, satisfying
150+
# Lake build process.
132151
overrideBuildModAttrs = addFakeFiles {
133152
"ProofWidgets.Compat" = [ ".lake/build/js/compat.js" ];
134153
"ProofWidgets.Component.Basic" = [ ".lake/build/js/interactiveExpr.js" ];
@@ -145,6 +164,7 @@
145164
"ProofWidgets.Presentation.Expr" = [ ".lake/build/js/exprPresentation.js" ];
146165
};
147166
};
167+
# This is Mathlib4, a dependency of Aeneas standard library.
148168
mathlib = buildLeanPackage {
149169
deps = [ qq aesop batteries import-graph proof-widgets ];
150170
name = "Mathlib";
@@ -154,29 +174,42 @@
154174
};
155175
};
156176
in
177+
# Aeneas standard library does not require any hashing
178+
# as it is present in this local repository.
157179
buildLeanPackage {
158180
name = "Base";
159181
deps = [ mathlib ];
160182
src = ../../backends/lean;
161183
};
162184

185+
# This is a meta Lean package of all Lean files used in the documentation.
163186
literate = buildLeanPackage {
164187
name = "literate";
188+
# Add here new Lean packages if you need them for the manual
165189
deps = [ aeneas-base ];
166190
src = ./.;
191+
# To add a new directory containing Lean files to be processed
192+
# by Alectryon, add a new attribute set `{ mod = "path to the lean files"; glob = "submodules"; }`
167193
roots = [
168194
{
169195
mod = "src/lean/basics";
170196
glob = "submodules";
171197
}
172198
];
173199
};
200+
201+
# This is the tree of all inked Lean files, i.e. the *.lean.md files
202+
# expected by mdBook.
174203
inked = renderPackage literate;
204+
205+
# This is the final book.
175206
doc = book;
176207
};
177208
defaultPackage = self.packages.${system}.doc;
178209
devShells.default = mkShell {
179210
packages = [
211+
# If you need to run Alectryon or LeanInk manually for tests
212+
# This is available in the default development shell.
180213
self.packages.${system}.alectryon
181214
self.packages.${system}.leanInk
182215
];

0 commit comments

Comments
 (0)