Observation
mcpp 2026.9.27.1 (#719) decomposes src/build/prepare.cppm: prepare_build becomes eleven phase functions over an explicit PrepareState, in implementation units of at most 2,500 lines each. The file boundaries are architectural; several phases are still single functions of about two thousand lines:
| Phase function |
File |
Lines |
phase13_finish |
src/build/prepare/plan.cpp |
2,293 |
phase4b_graph_worklist |
graph.cpp |
2,245 |
phase6_features_and_host_tools |
features.cpp |
1,953 |
phase9_target_side |
target_side.cpp |
1,869 |
phase4a_graph_load |
graph_load.cpp |
1,060 |
phase1_toolchain_spec_and_axes |
toolchain.cpp |
1,029 |
phase2_define_toolchain_resolver |
toolchain.cpp |
1,007 |
Each still keeps many locals of its own and defines closures that later steps of the same phase call, so a step inside a phase can be read, tested or changed only through the whole phase.
Proposal
Split each of these along the sections its own banners already name, the way the decomposition split prepare_build:
phase13_finish: prebuilt dependencies, link forms, make_plan, the runtime binding, assembly units, Windows resources, the global dependency cache, mcpp.lock, resolution.json, the empty-link check;
phase4b_graph_worklist: the worklist step for one item, identity adoption, the cycle check;
phase6_features_and_host_tools: feature activation, capability and ABI accumulation, host-tool provisioning, the dependencies' build programs;
phase9_target_side: capability binding, target-side resolution, link forms.
Each sub-step is a function over PrepareState& (or over a phase-local struct passed by reference), extracted verbatim; the checks the decomposition used apply unchanged: the golden fixtures byte-identical, the unit tests, the e2e suite, AddressSanitizer with detect_stack_use_after_return=1 for closures that outlive their step, and no new interface unit in mcpp.build.prepare's import chain (#721).
Acceptance
- No function under
src/build/prepare/ longer than about 400 lines, and the length gate extended to functions.
- The pure pieces that fall out of the split gain unit tests alongside
tests/unit/test_prepare_helpers.cpp.
Observation
mcpp 2026.9.27.1 (#719) decomposes
src/build/prepare.cppm:prepare_buildbecomes eleven phase functions over an explicitPrepareState, in implementation units of at most 2,500 lines each. The file boundaries are architectural; several phases are still single functions of about two thousand lines:phase13_finishsrc/build/prepare/plan.cppphase4b_graph_worklistgraph.cppphase6_features_and_host_toolsfeatures.cppphase9_target_sidetarget_side.cppphase4a_graph_loadgraph_load.cppphase1_toolchain_spec_and_axestoolchain.cppphase2_define_toolchain_resolvertoolchain.cppEach still keeps many locals of its own and defines closures that later steps of the same phase call, so a step inside a phase can be read, tested or changed only through the whole phase.
Proposal
Split each of these along the sections its own banners already name, the way the decomposition split
prepare_build:phase13_finish: prebuilt dependencies, link forms,make_plan, the runtime binding, assembly units, Windows resources, the global dependency cache,mcpp.lock,resolution.json, the empty-link check;phase4b_graph_worklist: the worklist step for one item, identity adoption, the cycle check;phase6_features_and_host_tools: feature activation, capability and ABI accumulation, host-tool provisioning, the dependencies' build programs;phase9_target_side: capability binding, target-side resolution, link forms.Each sub-step is a function over
PrepareState&(or over a phase-local struct passed by reference), extracted verbatim; the checks the decomposition used apply unchanged: the golden fixtures byte-identical, the unit tests, the e2e suite, AddressSanitizer withdetect_stack_use_after_return=1for closures that outlive their step, and no new interface unit inmcpp.build.prepare's import chain (#721).Acceptance
src/build/prepare/longer than about 400 lines, and the length gate extended to functions.tests/unit/test_prepare_helpers.cpp.