Commit 5daaacb
committed
feat(build): scope the dependency cache per package, and make hits actually skip work (2026.7.30.2)
The global dependency cache existed but its net benefit was zero, for two
independent reasons.
It never hit across projects. The key was the whole-project fingerprint, whose
flags field serializes every package in the graph INCLUDING the root — its name,
its version, its [build] flags. So bumping a project's own version invalidated
every dependency it had, and two projects with identical dependencies and
toolchain shared nothing. Measured on one machine: 26 GB across 1198 fingerprint
directories, compat.zlib@1.3.2 stored 162 times, 15 distinct std module
identities occupying 1014 directories (16.1 GB where ~0.5 GB was needed).
And when it did hit, nothing was saved. Artifacts were copied into the build dir
from inside prepare_build while those paths stayed declared as compile edge
outputs — and ninja treats an output it has no command line for in .ninja_log as
dirty, which a fresh build dir always is. Every "cached" unit was recompiled
while the CLI printed "Cached".
ninja explain: command line not found in log for obj/zutil.o
ninja explain: obj/zutil.o is dirty
Keying is now per package (new mcpp.build.cache_key): toolchain identity,
language/dialect, profile, package identity, the package's own build config, and
— recursively — the keys of its direct dependencies. Nothing about the consumer,
which is sound because the root's [build] flags verifiably do not reach
dependency translation units. The recursion is not conservatism: GCC embeds a
CRC of an imported module's BMI into the importer's BMI, so an importer's
artifacts are bound to the exact upstream artifacts they read.
Hits now emit stage_file edges instead of compile edges (and no scan/dyndep
edges), so ninja has a command-line record for the staged outputs. Artifacts
land where a compile edge would have put them, leaving link edges, BMI implicit
inputs and runtime deployment unchanged. The status line carries the unit count
it saved, because a bare "Cached" was printed for months while every unit was
recompiled behind it.
Three correctness defects had to land with it, all of them harmless only while
the cache was a no-op:
- The profile was not an invalidation axis. --dev, --release and --profile dist
shared one fingerprint, one build dir and one cache entry, so a release build
would have been served -O0 -g objects.
- .build_cache keyed fast-path entries by target triple alone, and the fast path
only refuses to run for an EXPLICIT profile flag. `mcpp build --release`
followed by a bare `mcpp build` reported success in 0.00s and left the release
artifacts in place. This one was live regardless of the cache.
- Transitively reached path/git dependencies were cached: the exclusion
predicate consulted the root manifest's dependency maps, where a transitive
package does not appear. Their sources can change without name@version
changing.
Also: --cache=global|local|off (with --no-cache as a deprecated alias for off,
and its inaccurate help text corrected), and mcpp cache grown into something
operable — dir / gc with a real LRU / clean --deps|--std|--all|--legacy /
list --json / verify, with each entry now describing itself in entry.json so a
suspected wrong hit can be audited.
The cache root is $MCPP_HOME/build-cache/v1, deliberately not $MCPP_HOME/cache:
that name belongs to the index metadata cache, whose reset path removes the
whole directory.
Design: .agents/docs/2026-07-30-dep-build-cache-scoping-design.md
Plan: .agents/docs/2026-07-30-dep-build-cache-implementation-plan.md1 parent 1005c2f commit 5daaacb
37 files changed
Lines changed: 3789 additions & 609 deletions
File tree
- .agents/docs
- docs
- zh
- src
- bmi_cache
- build
- cli
- manifest
- toolchain
- tests
- e2e
- unit
Lines changed: 396 additions & 0 deletions
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
6 | 72 | | |
7 | 73 | | |
8 | 74 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| 149 | + | |
149 | 150 | | |
150 | 151 | | |
151 | 152 | | |
| |||
717 | 718 | | |
718 | 719 | | |
719 | 720 | | |
| 721 | + | |
| 722 | + | |
| 723 | + | |
| 724 | + | |
| 725 | + | |
720 | 726 | | |
721 | | - | |
| 727 | + | |
| 728 | + | |
| 729 | + | |
| 730 | + | |
| 731 | + | |
| 732 | + | |
| 733 | + | |
| 734 | + | |
| 735 | + | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
| 746 | + | |
| 747 | + | |
| 748 | + | |
| 749 | + | |
| 750 | + | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
722 | 771 | | |
723 | 772 | | |
724 | 773 | | |
| |||
744 | 793 | | |
745 | 794 | | |
746 | 795 | | |
747 | | - | |
| 796 | + | |
748 | 797 | | |
749 | 798 | | |
750 | 799 | | |
| |||
756 | 805 | | |
757 | 806 | | |
758 | 807 | | |
759 | | - | |
| 808 | + | |
760 | 809 | | |
761 | 810 | | |
762 | 811 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| 142 | + | |
142 | 143 | | |
143 | 144 | | |
144 | 145 | | |
| |||
506 | 507 | | |
507 | 508 | | |
508 | 509 | | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
509 | 513 | | |
510 | | - | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
511 | 553 | | |
512 | 554 | | |
513 | 555 | | |
| |||
529 | 571 | | |
530 | 572 | | |
531 | 573 | | |
532 | | - | |
| 574 | + | |
533 | 575 | | |
534 | 576 | | |
535 | 577 | | |
| |||
540 | 582 | | |
541 | 583 | | |
542 | 584 | | |
543 | | - | |
| 585 | + | |
544 | 586 | | |
545 | 587 | | |
546 | 588 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
0 commit comments