Skip to content

Commit a203bdb

Browse files
committed
prepare.cppm: add the file-length CI gate and the CHANGELOG entry
check_file_lengths.sh fails the build if src/build/prepare.cppm or any file directly under src/build/prepare/ exceeds 2,500 lines, wired into ci-linux.yml next to the other pure-text, no-toolchain check_*.sh steps (check_version_pins.sh, check_modules_wiring.sh). Currently passes: 13 files, all at or under the cap (the largest, plan.cpp, is 2,392). CHANGELOG.md: one entry under 2026.9.27.1 describing the internal decomposition -- no behavior change, so it sits in the existing '其他' (other) section alongside the ELF-read-once note, not as its own dated change.
1 parent 960f0b2 commit a203bdb

3 files changed

Lines changed: 87 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Guard: no file under the prepare.cppm decomposition grows past 2,500 lines.
4+
#
5+
# WHY
6+
#
7+
# prepare.cppm was 16,105 lines: one exported function, prepare_build, ~85%
8+
# of the file, ~180 top-level locals sharing a stack frame. It was split into
9+
# a primary interface (src/build/prepare.cppm), an implementation partition
10+
# (src/build/prepare/state.cppm) and twelve implementation units, each phase
11+
# a function taking PrepareState& instead of closing over the old locals
12+
# directly — see the layout comment at the top of prepare.cppm and
13+
# .agents/docs/2026-09-27-mcpp-2026.9.27.1-ecosystem-plan.md §4.
14+
#
15+
# A size cap with no gate is a target nobody re-checks. The decomposition's
16+
# whole point was to keep any one file's compile from blocking on the rest —
17+
# a phase file that quietly grows back to several thousand lines is the same
18+
# defect it fixed, arrived at one small commit at a time. This fails the
19+
# build the day that happens, at the commit that did it, rather than leaving
20+
# it for the next person who tries to read the file.
21+
#
22+
# THE RULE
23+
#
24+
# Every file directly under src/build/prepare/, plus src/build/prepare.cppm
25+
# itself, stays at or under 2,500 lines. There is no per-file waiver: a file
26+
# that needs one is a file that needs splitting the way graph.cpp/graph_load.cpp
27+
# and toolchain.cpp/toolchain_decision.cpp already were.
28+
#
29+
# Usage: bash .github/tools/check_file_lengths.sh [repo_dir]
30+
31+
set -uo pipefail
32+
33+
REPO_DIR="${1:-$(pwd)}"
34+
cd "$REPO_DIR" || { echo "FAIL: cannot cd to $REPO_DIR" >&2; exit 1; }
35+
36+
LIMIT=2500
37+
PRIMARY="src/build/prepare.cppm"
38+
DIR="src/build/prepare"
39+
40+
[ -f "$PRIMARY" ] || { echo "FAIL: $PRIMARY does not exist — this guard has gone stale" >&2; exit 1; }
41+
[ -d "$DIR" ] || { echo "FAIL: $DIR does not exist — this guard has gone stale" >&2; exit 1; }
42+
43+
fail=0
44+
checked=0
45+
46+
check_one() {
47+
file="$1"
48+
n=$(wc -l < "$file")
49+
checked=$((checked + 1))
50+
if [ "$n" -gt "$LIMIT" ]; then
51+
echo "FAIL: $file is $n lines (limit $LIMIT)" >&2
52+
fail=1
53+
fi
54+
}
55+
56+
check_one "$PRIMARY"
57+
while IFS= read -r f; do
58+
check_one "$f"
59+
done < <(find "$DIR" -maxdepth 1 -type f \( -name '*.cppm' -o -name '*.cpp' \) | sort)
60+
61+
if [ "$fail" = 1 ]; then
62+
cat >&2 <<EOF
63+
64+
A file over the limit needs splitting, not a raised limit: cut it at a
65+
phase boundary (see the layout comment at the top of $PRIMARY) the way
66+
P4 (graph_load.cpp/graph.cpp) and P1+P2+P5 (toolchain.cpp/
67+
toolchain_decision.cpp) already were. A phase whose closures escape into a
68+
later phase needs its captures promoted to PrepareState members first —
69+
see state.cppm's own comments for the pattern.
70+
EOF
71+
exit 1
72+
fi
73+
74+
echo "ok: $checked file(s) under $PRIMARY / $DIR/, all at or under $LIMIT lines"
75+
exit 0

‎.github/workflows/ci-linux.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ jobs:
6262
- name: Check modules/ wiring
6363
run: bash .github/tools/check_modules_wiring.sh
6464

65+
# Same placement, same reason: pure text, no toolchain, under a second.
66+
# Catches the prepare.cppm decomposition growing back into one huge
67+
# file one commit at a time — see the script's header.
68+
- name: Check src/build/prepare* file lengths
69+
run: bash .github/tools/check_file_lengths.sh
70+
6571
# Same placement, same reason: pure text, no toolchain, under a second.
6672
#
6773
# This one is a HARD gate (unlike lint-ci-assertions.sh below) because it

‎CHANGELOG.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@
6868
工具链,使其断言不依赖机器的默认工具链。
6969
- ELF 检查以一次读取载入文件。此前逐字节读入,`mcpp test` 的链接后检查在测试程序较多时耗时
7070
数十分钟。
71+
- **`src/build/prepare.cppm` 的内部分解。** 原文件 16,105 行,其中一个函数 `prepare_build`
72+
占 85%。按 §4.1 划出的十三个阶段拆分为 `PrepareState`(跨阶段状态,取代原来约 180 个共用
73+
一个栈帧的局部变量)加十三个阶段函数,后者移入 `src/build/prepare/` 下十二个实现单元与一个
74+
实现分区 `:state`;主接口 `prepare.cppm` 只保留导出声明。行为逐条移动,未重排、未改写。公开
75+
接口、导出符号与默认参数不变,现有导入方无需改动。分解本身不改变任何行为,详见
76+
`src/build/prepare.cppm` 开头的布局说明与 GCC 16.1 约束记录。
7177
- 规范:SPEC-001 v1.5、SPEC-004 v1.8、SPEC-005 v1.4、SPEC-007 v0.3。
7278

7379
## [2026.9.26.2] - 2026-09-26

0 commit comments

Comments
 (0)