0015. Build: pin fmpp and its rendering environment
Date: 2026-09-30
The board-file renderer is pinned in two parts, without adding its version to the board manifests. Extracted verbatim from the "What was not done" section of Tag Firmware Build Reproducibility.
Decision, alternatives and consequences
The board manifests hash the ChibiOS templates but not the renderer, so a
different fmpp could in principle render them differently and the manifests
would not notice. Two changes closed that without touching the manifests.
FMPP_VERSION pins 0.9.16 and configure compares what fmpp reports
against it, routing a disagreement through reproducibility_problem like the
ARM toolchain check. fmpp's last release was September 2018, so there is
effectively one renderer in circulation and this is an assertion rather than a
constraint. It is a check and not a manifest entry, which is what avoids the
problem described next.
board.fmpp.in pins the rendering environment -- locale, number format and
both encodings -- which FreeMarker was otherwise taking from the machine. That
mattered more than the version: the templates interpolate numbers in 54 places
via ?number and 156 more via ?index, ?size and ?counter, none guarded
with ?c, and board.c is C source, so a locale that groups digits
differently produces a file that does not compile. board.fmpp.in is itself a
hashed input of every board manifest, so this pin is covered by the existing
freshness check with nothing added to it.
The original reasoning for leaving the version out of the manifests still stands and is why it stayed out: Pinning it was rejected because a version string reported on one machine and not another would cause false staleness across the group, which would be worse than the risk. The per-image build manifest does not record it either -- that would be a small, easy addition.
That reasoning was sound while the renderer was an uncontrolled desktop
install, and config-gen has since shown what removes it. Its protobuf is
pinned in a requirements.txt and installed into a virtualenv the build makes
itself, so every machine reports the same version because every machine runs
the same bytes, and the version becomes recordable rather than a source of
false staleness. The same pattern would work for fmpp and the JRE under it,
with one difference worth weighing: a Java runtime is not a pip install, so it
would mean either a documented download or a container.
Whichever way that goes, the pin and the manifest entry have to land
together. Recording fmpp in inputs.sha256 while desktop regeneration is
still permitted reintroduces exactly the false staleness that was avoided, and
the commit that adds it invalidates every board manifest and requires a
regeneration alongside.