Skip to content

回归:release 的 trim_paths 使切换 CLI/GUI 时公共 core 反复重编译 #844

Open

Description

@julixian

问题描述

升级到近期版本后,在同一工作空间依次构建 CLI → GUI → CLI,公共依赖 core 会反复重新编译,即使源码、工具链、profile 和 core 自身的配置都没有变化。

当前使用 mcpp 2026.10.26.1。从已有构建日志、编译数据库和上游实现看,原因指向 2026.10.24.1 引入的 release 默认 trim_paths = true:本次构建计划中所有包的路径映射都被追加到全局编译参数,所选成员发生变化时,公共依赖的编译命令也跟着变化。

路径裁剪本身是有用的功能,但不相关消费方的加入或移除,不应该使公共依赖失去增量复用。

环境

  • Windows x64
  • mcpp:2026.10.26.1
  • 工具链:llvm@23.1.3,目标 x86_64-pc-windows-msvc
  • MSVC:14.51.36231
  • Windows SDK:10.0.26100.0
  • 同一个工作空间,release profile(opt = 3、debug = true、lto = true),未显式配置 trim_paths

工作空间关系与复现步骤

实际项目关系简化如下:

workspace
├── gpp.core     公共库
├── gpp.version  公共版本模块
├── gpp.cli     → gpp.core、gpp.version
├── gpp.gui     → gpp.core、gpp.version、gpp.updater(artifact)
└── gpp.updater

CLI 和 GUI 都是同一个工作空间的成员,使用相同的工具链和 release 配置,gpp.core 的包配置与构建脚本在两种选择下相同。

在工作空间根目录,不修改任何源文件,依次执行:

mcpp build -p GPPCLI
mcpp build -p GPPGUI
mcpp build -p GPPCLI

预期:第一次构建完成后,切换消费者时仍然复用 core 的对象文件和 BMI。

实际:切换后 core 重新编译,再切回来又重新编译。CLI 和 GUI 共用同一个配置目录及 core 输出路径,因此会反复覆盖这些公共对象。

已有产物中的证据

以下是实际生成参数的摘录,工作空间路径统一简化为 D:/work/GPP。

CLI 的编译数据库中,core 源文件的编译命令包含:

-ffile-prefix-map=D:/work/GPP/GPPCLI=cli@3.2.9
-ffile-prefix-map=D:/work/GPP/GPPVersion=version@3.2.9
-ffile-prefix-map=D:/work/GPP/GalTranslPP=core@3.2.9

GUI 的已有 verbose 构建日志中,全局编译参数则包含:

-ffile-prefix-map=D:/work/GPP/GPPGUI=gui@3.2.9
-ffile-prefix-map=D:/work/GPP/Updater=updater@3.2.9
-ffile-prefix-map=D:/work/GPP/GPPVersion=version@3.2.9
-ffile-prefix-map=D:/work/GPP/GalTranslPP=core@3.2.9

这些映射进入全局 cxxflags,所以即使 core 自身的代码和选项相同,它的实际编译命令也随 CLI / GUI 的选择而变化。Ninja 因编译命令变化而将公共对象判为过期,符合当前观察到的重编行为。

两种选择的配置目录均为 target/x86_64-windows-msvc/e15bf6648b405e65;公共对象使用相同的 obj/gpp_core/... 路径。

本次排查通过读取已有构建记录和源码进行,没有为这个 issue 额外执行一轮完整的 CLI → GUI → CLI 构建,也没有将上述结构另建为独立最小项目运行。

相关更新与实现

这会让公共包的编译参数依赖于当前选择的其他成员,破坏工作空间中“同一配置的公共依赖只编译一次”的行为。

临时规避与期望

按配置语义,可以临时关闭裁剪,以去掉这组变化的参数:

[workspace.profile.release]
trim_paths = false

这里记录的是规避方式,没有在本次排查中修改项目配置并重新构建验证。

期望开启 trim_paths 时,共享源文件的有效编译参数也能在不同消费方选择之间保持稳定。修复时需要考虑包映射的集合及顺序,而不只是把 CLI / GUI 写进输出目录指纹;后者会通过分开输出目录来避免覆盖,却仍然不能复用相同的 core 编译结果。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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