Skip to content

Build & test

Everything runs through just. just --list shows the recipes.

Terminal window
just # build + check, the default
just build # build the crates and regenerate the C headers
just test # every suite: Rust, C++, Python
just check # every linter CI runs
just format # format everything
ForTool
The crates and the C headersRust (stable + nightly for fmt), cbindgen
The C++ suitea C++17 compiler; optionally mingw-w64 for the Windows cross-build
The Python suiteuv (the recipe creates the venv itself)
The documentation siteNode and pnpm; doxygen and a nightly Rust toolchain for the reference; a Playwright browser for diagrams (pnpm --dir docs exec playwright install chromium)

The Windows cross-build is skipped with a message if x86_64-w64-mingw32-g++ is absent, so it is optional.

c/fznso_types.h and c/fznso_solver_template.c are generated by cbindgen from rust/fznso-types and rust/fznso-solver-template.

To change what a C consumer sees, change the Rust doc comment or type it comes from, then run just build. just check-headers confirms the result still compiles as both C and C++.

The prose in each generated file’s preamble comes from the header = """…""" strings in cbindgen_types.toml and cbindgen_template.toml.

The suites drive a throwaway example solver by default. Point the C++ consumer at your own library to check it against the full interface:

Terminal window
just test-cpp
./target/test_consumer /path/to/libmysolver.so

Run the Rust suite under miri before changing anything that touches handles, casts or lifetimes:

Terminal window
just miri

This is not optional diligence. The interface passes handles as raw pointers that each side casts back to its own type, and every bug in that class has passed the ordinary test suite first. rust/fznso/tests/abi.rs drives the generated entry points directly so miri covers them too; miri cannot dlopen, so tests/dylib.rs is skipped under it.

Terminal window
just docs # build the site, including the generated reference
just docs-serve # live reload while writing

Two parts of the site are generated and must not be edited in place:

  • docs/src/content/docs/registry/ comes from docs/registry/*.toml. Edit the TOML.
  • docs/src/content/docs/reference/ comes from the code, via rustdoc JSON, Doxygen XML and griffe. Edit the doc comment.

Both run from pnpm gen, which dev and build invoke for you; the dumps they read come from just docs-api.

Diagrams are written as Mermaid in a ```mermaid block and rendered to inline SVG at build time, so a page ships no JavaScript to draw one and the labels stay searchable text. That needs a browser: pnpm --dir docs exec playwright install chromium, once. Doxygen and the Python toolchain are optional: a missing one skips its pages with a warning, so the prose stays workable without them.

One rule, and it is the reason the site exists:

Every fact has one home. Everywhere else links to it.

Kind of factLives in
A rule of the protocola page under docs/src/content/docs/spec/
The contract of one function, type or fieldits doc comment — the reference is generated from it, never hand-written
A common namedocs/registry/*.toml
Example codea real file under rust/fznso/examples/, cpp/tests/ or python/tests/, imported with ?raw

If you find yourself pasting a paragraph into a second file, that is the signal to put it in the spec and link instead. CI enforces the links, so a reference that stops resolving is a build failure rather than a dead end for a reader: cargo doc runs with -D warnings, and scripts/check-links.mjs walks the built site checking every internal link and anchor.