Skip to content

mcpp build 会重放 mcpp test 留下的构建图:源码没动,普通构建却编测试文件并失败 #407

Description

@Sunrisepeak

在 review #387 时发现的既存缺陷,与那个 PR 无关(mcpp build --configure-only 撞上的是同一个洞,已在 #387 内修掉自己那半边;这里记 mcpp test 这半边)。

复现

main(2026.8.10.1,本机 x86_64-linux-gnu):

$ mkdir -p demo/src demo/tests && cd demo
$ printf '[package]\nname = "tst"\nversion = "0.1.0"\n' > mcpp.toml
$ printf 'int main() { return 0; }\n' > src/main.cpp
$ printf 'int main() { return 0; }\n' > tests/smoke.cpp

$ mcpp build
$ grep '^default' target/*/*/build.ninja
default bin/tst

$ mcpp test
$ grep '^default' target/*/*/build.ninja
default bin/smoke                 # <- 同一个 build.ninja 被换成了测试图

$ mcpp build
    Finished dev in 0.00s         # 快路径命中,问 ninja 要的是 bin/smoke

bin/tst 已经不在这张图里了,但 mcpp build 报成功。

把测试文件改坏,症状就变成硬失败 —— src/ 一个字没动

$ printf 'this is not valid C++ at all\n' > tests/smoke.cpp
$ mcpp build
error: build failed
failed: obj/smoke.o
.../tests/smoke.cpp:1:1: error: expected unqualified-id before 'this'
$ echo $?
1

即:一个坏掉的测试文件会让普通 mcpp build 失败。

根因

两件事叠在一起:

  1. mcpp testprepare_build(includeDevDeps=true, extraTargets=tests) 生成 plan,backend 把它写进同一个 target/<fp>/build.ninja(指纹不含 dev-deps/test targets,所以是同一个目录)。emit_ninja_stringdefault 行列的是 plan.linkUnits 全部,测试模式下就只有测试二进制。

  2. try_fast_build 的新鲜度判据是「build.ninja 的 mtime 比源码新」(src/build/execute.cppmsources_newer_than,只扫 src/** + build.mcpp + glob inputs + resource scripts),从不校验这张图是不是普通构建的图target/.build_cache 也没人动。tests/ 不在扫描范围里,所以改测试文件连快路径都不会打断。

于是 mcpp buildmcpp testmcpp build 就重放了测试图。

(顺带:把产物删掉再 build 反而不会复现 —— 产物缺失让 ninja 以「图过期」的样子失败,快路径回退到完整 prepare,正好把缺陷盖住。写回归测试时别先删产物。)

可选修法

  • mcpp test 在重写 build.ninja 之后,丢掉指向该 outputDir 的快路径条目。feat: generate compile database without building #387 给 configure-only 加的 forget_build_cache_entry(projectRoot, outputDir)src/build/execute.cppm)就是这个形状,mcpp test 直接调用即可,代价是 mcpp test 之后的第一次 mcpp build 走完整 prepare。
  • 或者更根本:把 build.ninja 的图形态(普通 / 含测试)记进 .build_cache 条目,快路径匹配时一并比。这样两种模式可以各自保留增量,但要动缓存格式。

第一种最小、方向保守;第二种更彻底。倾向先做第一种。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions