mcpp 只在构建程序非零退出时打印抓到的输出,于是一个「做完了正确的事、但用户
需要知道一件事」的程序没有通道。写到 stderr 的提示在最需要它的那些成功构建上
一个字都不打印;让构建失败也不对,因为构建是对的。
- 新指令 mcpp:warning= + 类型化 API mcpp::warning(),协议 4 → 5
- 新增 Scope::Advisory:每条指令都要回答「谁看到这个值」,而警告的答案是
用户 —— 不是六个既有值中的任何一个
- ⭐ tag 非空是承重的:构建程序的结果被缓存,命中时不再运行,一条只活在运行
路径上的提示会出现一次然后再也不出现,读起来像「问题已解决」
- kCacheEpoch 刻意不递增:旧条目里没有 warning 行,而写它的程序当时也发不出
一条,所以旧条目仍然正确;递增会让所有工程白跑一遍
新增 tools/lint-ci-assertions.sh:三条关于「断言写在哪」的规则,由三次同源
事故导出。它打印而不失败 —— 规则的价值在于被读到。⚠️ 工具头部写明它抓不到
其中一次事故:那次的缺陷是断言「缺失」,而 linter 检查写下来的东西。
修 ci-macos.yml 一处真实的同形缺陷:nm 失败时打印「0 (good)」。
mcpp 只在构建程序非零退出时打印抓到的输出。于是一个「做完了正确的事、但用户需要知道一件事」的程序没有通道:写到 stderr 的提示在恰恰需要它的那些成功构建上一个字都不打印,而让构建失败也不对 —— 构建是对的。
动机是实测过的一次:清单的 [xlings] deps 是声明而非安装触发器,干净机器上 xpkg_dir 返回空,构建程序静默地不配 runner,mcpp run 给出一条一般情况下对、在此处不对的建议。
§1 mcpp:warning=
兼容性:实测,比预想的好
用旧引擎跑一个调 mcpp::warning 的构建程序:
error: 'warning' is not a member of 'mcpp' The `mcpp` build module this engine bundles does not have that name. Either the package was written for a newer mcpp (try `mcpp self update`; this is mcpp 2026.8.20.3), or the name is misspelled …引擎已有的 mentions_missing_mcpp_api 按命名空间匹配,所以新 API 自动被它覆盖 —— 不是原始编译错误。
§4 tools/lint-ci-assertions.sh
三条规则,由三次同源事故导出。它打印而不失败 —— 规则的价值在于被读到,硬门一个月内就会被豁免绕过。
⚠️ 工具头部第一段写的是它抓不到什么:三次事故里的第一次,缺陷是断言缺失(那一步只断言了 mcpp build,也只声称了这么多)。文件里没有任何东西是错的。linter 检查写下来的东西,不检查没写的东西。
四个证物逐一验证:0.5.0 触发 R1、ldd 2>/dev/null | grep -v 触发 R3、无模拟器的作业触发 R4、装了模拟器的不触发。两条规则在跑过之后被收窄:grep -q . 恰恰是在断言非空(R3 误报),而宿主目标的 mcpp run 不需要模拟器(R4 在六个完全正确的作业上误报)。
对 mcpp 自身跑,剩 1 条真的:nm "$BIN" 2>/dev/null | grep -c 在 nm 失败时打印「0 (good)」。已修成可区分两种情况。
测试
tests/e2e/139_build_program_advisory.sh。⚠️ 第二次构建才是测试,而且 touch 是必需的 —— 无事可做的构建走全工程 fast path,根本到不了 build.mcpp 阶段。
⭐ 判据「先看到它失败」已执行:临时移除缓存命中处的发射,第二条断言变红而第一条仍绿。
文档
docs/07-build-mcpp.md 与 docs/13-baremetal.md,中英双份。含一条边界:全工程 no-op 构建什么都不打印,包括这一条。