Repository navigation
fix: stop make run recompiling the dictionary on every source edit - #40
Conversation
Measured: a no-op `make run` was 0.1s, but touching one Swift file anywhere in HanReaderCore, HanReaderPersistence or the generator cost 15 seconds, and 35 when the release build had to recompile too. Those are the three modules `hanreader-dictgen` links, so the rule listed every `.swift` file in all of them -- and during ordinary work on the reader or the listening core, that is every edit. None of them can change the container's bytes. The dictionary is now built from `generate` only when it is **missing**, through a test in the recipe. An order-only prerequisite is the obvious reach and the wrong one: it stops the timestamp propagating to `generate` but still updates the container it names, so it changed nothing. `make dict` keeps the strict dependency and CI has a job of its own, so a stale container still cannot ship, and `make run` now says plainly when the one on disk is older than its sources. A fresh clone is unaffected: the container is missing, so it is built. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PR Summary by QodoAvoid rebuilding the dictionary on routine app runs
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
1.
|
Two findings, both real. A container that failed `verify` was left on disk. Compiling straight to the destination meant a failed check still produced a file newer than its sources, and the new existence test then saw a file, asked no further questions and bundled it. It is written beside the destination now and moved into place only once it has passed. The staleness notice could stop a build. `find` exits non-zero when the pinned snapshot is missing, and under this file's `-euo pipefail` that aborted the recipe — before the dictionary rule could print how to fetch the snapshot. Reproduced directly: `set -euo pipefail` plus a missing path aborts the shell at the assignment. A courtesy line must not be the thing that stops a build, so it cannot fail any more. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The problem
make runrecompiled the bundled dictionary whenever any Swift file underHanReaderCore,HanReaderPersistenceorhanreader-dictgenwas newer than thecontainer. Those are the three modules the generator links, so the rule named
every
.swiftfile in all of them — and during ordinary work on the reader orthe listening core, that is every edit. None of those edits can change the
container's bytes.
Measured on this machine:
make generateThe fix
The dictionary is built from
generateonly when it is missing, through atest in the recipe:
An order-only prerequisite (
generate: … | $(CEDICT_OUTPUT)) is the obviousreach and the wrong one — it stops the timestamp propagating to
generatebutstill updates the container it names, so it changed nothing. That was
measured too, not assumed.
Why this is still safe
make dictkeeps the full strict dependency list, unchanged.Bundled dictionaryjob runsmake dict, so a container that does notmatch its sources fails there regardless of what a developer has locally.
make runbuilds it — which is also whatthe app-build CI jobs do through
make generate.make runandmake run-iosnow print a line when the container on disk isolder than its sources, so a stale one is visible rather than silent:
Verified
Each path exercised directly: no-op, after an unrelated core edit (notice fires,
no rebuild), with the container deleted (rebuilt), and
make dicton its own(still 15 s of real work).
🤖 Generated with Claude Code