Open and answer this issue on GitHub.
tools, note · opened 2026-10-08 · updated 2026-10-08 · 0 comments
Three places in this repository check Nikaia programs that live outside a package’s own tests. Each one carries its own loop:
crates/nikaia/tests/examples.rs runs nikaia test once per package in examples/.crates/nikaia/tests/specification.rs, through specbook, takes every nika block of Part I-III and lowers it.tests/guide/ (a Nikaia package) builds every nika block of guide/ as a project of its own and runs it with nikaia run.nikaia test checks one package (Part III 13.2). It has no doc tests, and no way to take several packages in one call. Every caller therefore builds the loop itself, and every block or package is its own Cargo build. One package is one crate today (ADR-286 D19, project.rs cargo_workspace), so 14 guide blocks mean 14 rustc and link runs for 14 small programs.
The owner’s view is that compiling each block alone is the wrong default, because it costs time for no gain. There should be a way to build them together with the same isolation, and a switch to build them one by one.
The isolation is the language’s own: a package is a directory and a namespace (Part I 9.1). Two blocks that both declare main or Item cannot share a package. So each block becomes a package of its own: a directory, its own names, its own ledger. Blocks marked // file: src/X.nika join the package of the block that follows, as guide/syntax.md’s module example already writes.
The Rust side keeps those packages apart without a crate each. For a doc-test build, each package lowers to a mod of one crate instead of a crate of its own. Its main becomes an entry the test binary dispatches to. A Rust module is a namespace as separate as a crate for everything a package can declare, so the separation drawn by directories survives. What it saves is the per-crate rustc and link work.
At run time each block is still alone: one process and one empty directory per block, which is how nikaia test already runs test blocks and output tests (14.1).
Further rules:
NK…) is settled by the checker and never reaches rustc.user_parallelism, target, dependencies) form separate groups, one crate each.extern symbols such as examples/c-library’s, assets) moves the block to a build of its own, automatically.--separately builds every package as its own crate, as today. If the merged build fails in rustc, the blocks are rebuilt one by one to name the culprit; that failure is a C.1 defect in any case.Prior art:
standalone_crate as the opt-out.Example functions into its one test binary.doctest shares one namespace per docstring; that is rejected here as a default, because a block must stay copyable on its own.Count, never time (callgrind, --branch-sim=yes), release builds:
tests/guide/ run one by one as today.mod block_N with main renamed, plus a dispatching main, compiled as one crate with the same settings. The output of each block must match first, byte for byte.examples/’ packages, to see whether “several packages, one crate” is worth having beyond doc tests.If (1) shows the front end dominates, or (2) saves little, this stops here with the numbers. Otherwise it becomes a decision: where doc tests are declared (the manifest naming Markdown files, or a nikaia test argument), the block markers, and whether specbook and examples.rs move onto it.