Skip to content

Releases: mcpp-community/mcpp

v2026.8.16.2

Choose a tag to compare

@github-actions github-actions released this 16 Aug 08:13
987b783

修复

  • 装好的 msvc toolset 在 mcpp toolchain list 里不出现。

    枚举问的是 toolchain_frontend(root / "bin", pkg),而 cl.exe 在
    VC/Tools/MSVC/<ver>/bin/Host<h>/<arch>/ —— 深四层。拿不到就 continue,
    于是每一个 msvc payload 都装得好好的、然后看不见

    这个布局有三个地方需要知道:安装知道、构建知道、列表不知道 ——
    一条规则被内联抄了第三份时的典型结果。三者现在共用
    payload_frontend(payloadRoot, pkg, family)

    2026.8.16.1 带着这条(tag 打在修复之前),其余部分不受影响 ——
    install / build / default / remove 都是好的,只有 list 少一行。

v2026.8.16.1

Choose a tag to compare

@github-actions github-actions released this 16 Aug 07:00
26b26ec

工具链

  • MSVC 不再是「唯一版本无法声明」的工具链。

    gcc / llvm 由 mcpp 自己安装、按声明解析;MSVC 是体系里唯一的例外——每一个
    msvc spec 都是系统 spec,manifest 写了版本也会被丢掉。后果不是不够优雅,是
    同一份源码在两台机器上会被不同的编译器编译,而且不报错

    xrgui#3 实测:同一轮 CI 里 mcpp 用 14.51、xmake 用 14.52,直到 14.51 触发
    ICE 才暴露。导出完整 vcvars 环境无效,最后只能在 CI 里把 vswhere.exe
    挪开,逼 mcpp 落到 VSINSTALLDIR 那一步。

    现在由 spec 的版本轴决定来源,两条来源并存:

    spec 来源 用哪个编译器
    msvc@system(或裸 msvc) 机器自己的 Visual Studio 这台机器上装的那个
    msvc@<toolset>(如 msvc@14.44.35207) mcpp 安装的 xlings payload 声明的那个,每台机器都是

    msvc@<toolset>gcc@16.1.0 在每个方面都同构:多版本共存、
    toolchain remove msvc@<toolset> 可卸载、manifest 里写了就自动安装。
    payload 自带编译器、STL,并通过 xim:windows-sdk 依赖带上 ucrt/um 头与库,
    机器上什么都不必预装

    实现上,「获取」与「解析」被拆成两条正交的轴:获取与 gcc 共用一条
    (xim 安装),解析与 msvc@system 共用一条(installation_from_tools_dir)。
    所以受管 toolset 不是第二条代码路径,也就不会长出自己的 bug。

  • ⚠️ 破坏性变更:msvc@19.44 不再是 pin-verify。

    它过去表示「用系统 MSVC,并校验 banner 前缀」——而且只有
    mcpp toolchain default 会校验,构建路径完全忽略它。版本轴现在到处都表示
    toolset。写成 19.x 时,mcpp 会用这台机器自己的 cl 版本说清楚,并给出两个
    替代写法(msvc@system 或该机器实际的 toolset 版本)。

  • VSINSTALLDIR 现在优先于 vswhere 探测。

    vswhere 在几乎每台开发机上都能返回点什么,于是 VSINSTALLDIR 事实上不可达:
    一次已经导出了完整 vcvars 环境的构建,仍然用 vswhere 排第一的那个编译器。
    猜测不该压过答案。 顺带给 vswhere 加了 -prerelease——没有它,只装了
    Insiders 的机器会被报告成「没有 MSVC」,而磁盘上明明有一个可用的 cl.exe。

    VS*COMNTOOLS 仍排在 vswhere 之后:那是机器全局的残留(2017 的
    VS150COMNTOOLS 不该压过当前安装),而 VSINSTALLDIR 是有人为这个 shell
    设的。

  • Windows SDK 不再只认两个写死的绝对路径。

    顺序改为:WindowsSdkDir(+ WindowsSdkVersion,vcvars 本来就导出这两个)
    → 受管 toolset 在 mcpp 自己 store 里的 xim:windows-sdk payload
    → 原来的绝对路径(降为回退)。

    第二条不需要任何配置:编译器自己的路径就说明了它来自哪个 store,
    SDK 是它在那里的邻居。所以 mcpp 里没有任何地方写死 SDK 版本。

接口一致性

  • cxx_runtime = "self-contained" 在 MSVC 上真的生效了。

    过去两个旋钮只有一个管用:linkage = "static" 确实发 /MT,而
    cxx_runtime = "self-contained" 报「未实现」——对着同一个物理开关。
    两处注释也互相矛盾(flags.cppm:605 说发了 /MT,distribution.cppm:202
    说「根本没有 /MT」)。

    在 MSVC ABI 上这两条不是可以二选一的旋钮:/MT 把 C 运行时和 C++ 运行时
    从同一个库里链进来,它们本来就是一个开关。现在两种写法都选中它,由
    msvc_wants_static_crt() 统一推导——项目的 TU 与 std 模块问的是同一个函数,
    不再各写各的表达式(#422 正是这样分叉的)。

    默认仍是 /MD:判据取的是manifest 里写下的字面值,不是解析后的
    contract——后者对多数 role 默认就是 self-contained,拿它做判据会把每一个
    Windows 构建都翻成 /MT

    MSVC 的 CRT 模型是整个项目的属性(一个项目只编一份 std 模块,cl 把
    _MSVC_MT/_MSVC_MD 烤进去),所以按 role 覆盖会被明确拒绝并说明原因,
    而不是在 ucrt 头文件里炸出 C5050/C2375。

测试

  • msvc 的发现逻辑第一次可以在 Windows 之外测试:installation_at() 接受目录
    而不是去探测机器,find_windows_sdk() 接受 root 列表。6 个新单测在 Linux CI
    上跑真实的 fixture 目录树,包括「两个 toolset 都在,要老的那个」这条——
    「取最新」的实现会在这里失败。
  • 新增 e2e 239_msvc_managed_toolset.sh。它的每一条断言都写成
    系统编译器来应答就会失败:cl.exe 必须在 mcpp 的 store 里、toolset 目录
    必须是 spec 声明的那个、同一台机器上换回 msvc@system 必须仍然解析到系统
    的 cl(两条来源互不污染)。

v2026.8.15.3

Choose a tag to compare

@github-actions github-actions released this 15 Aug 14:51
19cd960

(no CHANGELOG entry found for 2026.8.15.3)

v2026.8.15.2

Choose a tag to compare

@github-actions github-actions released this 15 Aug 14:03
f622f02

(no CHANGELOG entry found for 2026.8.15.2)

v2026.8.15.1

Choose a tag to compare

@github-actions github-actions released this 15 Aug 08:58
c459cf2

(no CHANGELOG entry found for 2026.8.15.1)

v2026.8.11.3

Choose a tag to compare

@github-actions github-actions released this 11 Aug 15:21
a749e9f

修复

  • ⚠️ 回归:产物加载的库不是它链接的那一份 —— $ORIGIN 被 SubOS 库视图遮蔽。

    2026.8.11.2(PR #413)首次把 SubOS 库视图(farm)写进产物的 DT_RPATH,但它
    落在 $ORIGIN 之前。于是 imgui/GLFW 应用链接的是 mcpp 从 compat.x11 源码
    构建、部署到产物目录的 libX11.so,运行期加载的却是 farm 里 xlings 装的
    xim:libX11 —— 链接期用 A,运行期加载 B,程序在 main 之前就死:

    undefined symbol: _ZNKSt13runtime_error4whatEv
    

    真因不是「放错了位置」,而是一条链接命令行的顺序由两个互不知情的生产者用
    += 决定
    :flags.cppm 把 farm 拼进全局 ldflags(并注释「so it is LAST」),
    plan.cppm$ORIGIN 拼进 per-unit,而每条链接规则渲染的是
    $ldflags $unit_ldflags。三处各自都对,合起来是错的。

    新增 mcpp.build.link_line:把 per-unit 尾部声明成具名槽位,相对顺序写在
    类型里、由单测钉死。新增一个生产者必须先选一个槽 —— 而"选"正是"在产物自己的
    目录之前还是之后"这个问题被提出来的地方。

  • ⚠️ 共享库不再把自己的 C++ 运行时导出给别人(ELF)。

    SharedLibrary 此前与可执行文件共用 Distributable 角色,于是拿到同一份
    self-contained 契约:-static-libstdc++。在 ELF 上这不是"私有一份" —— 只有一个
    全局符号命名空间,共享对象会导出它定义的每一个全局符号。一个纯 C 的 compat 包
    因此导出了 777 个 GLOBAL 标准库符号(libXau.so:39KB 的 Xau + 9.5MB 的 libstdc++)。

    可执行文件链接时 -lX11 排在驱动的 -lstdc++ 之前,ld 就用它满足了
    std::runtime_error::what(),归档成员从不拉入 —— 可执行文件的
    -static-libstdc++ 变成空操作,它的 C++ 运行时事实上是那个 .so
    。上一条的
    库替换之所以致命,根源在这里。

    共享库默认契约改为按目标格式分档:ELF toolchain-coupled,
    Mach-O / PE 维持 self-contained(两者都没有这个危害 —— Mach-O 的机制本就是
    -load_hidden,PE 没有全局命名空间)。显式 cxx_runtime = { shared = "…" }
    仍可选回自包含,此时自动补 -Wl,--exclude-libs,让内嵌的运行时留在动态符号表之外。

    实测(helloegui,imgui + GLFW + X11):libXau.so 9.5MB → 39KB,
    libX11.so 导出 std 符号 2931 → 0,GUI 正常启动。

内部

  • dist::default_contract没有任何生产调用方变成唯一真源:角色→契约的策略
    此前在 flags.cppm 被第二次推导,而这正是 distribution.cppm 开篇声讨的那类债
    (「used to be derived independently in five places」)换个位置复发。

  • e2e 219 的断言由「farm 是最后一个绝对路径条目」收紧为「字面最后一项」,
    并补一条行为不变量(LD_DEBUG=libs 实测同名 SONAME 解析到 $ORIGIN)。
    旧断言把 $ORIGIN 过滤掉了,对坏顺序与好顺序给出同一个结论 —— 它在一个 farm
    并非最后的二进制上报告「farm is last」。测试工程也从 int main() 换成消费依赖
    共享库,否则它连 $ORIGIN 都不产生,整条断言链是空转的。

v2026.8.11.2

Choose a tag to compare

@github-actions github-actions released this 11 Aug 08:39
c402dd4

修复

  • ⚠️ 回归:SubOS 没有自我描述时,mcpp build / mcpp test 直接失败
    (xlings#543)。

    Windows 上 xlings 不写 subos_info 块,而 mcpp 把「缺声明」当成了错误,于是
    每一次构建都停在一条讲 GL 驱动的消息上 —— 在一台没有 ELF、没有 PT_INTERP
    没有私有 libc 的机器上。2026.8.10.2 引入(PR #400),2026.8.8.4 正常。

    判据改为:矛盾报错,缺席降级。 点名的 SubOS 不存在仍是硬错误(该请求无法被
    满足);SubOS 存在但没描述自己则记 declared=false + 一条必被打印的 note,
    runtime 规则报 inconclusive 而不是给出判决,构建继续。

    同一位置还有第二颗雷:schema 检查是 !=,而它的读取器明写着「更高的 schema
    照读」。xlings 写出 schema 2 的那天,全平台所有构建会同时停摆。已改为上限语义 ——
    发布数据不得使读它的程序失效

  • 图形/系统库链得上却跑不起来:运行期搜索路径补上 SubOS 库视图。

    mcpp 在编译与链接两条线上都发 --sysroot=<subos>,所以 -lGL 零 flag 就解析得到;
    但运行期的搜索路径是另一套独立推导(只有工具链载荷目录)。结果是
    mcpp build rc=0、./bin/applibGL.so.1: cannot open shared object file

    $ readelf -d bin/app | grep RPATH
    before:  [<store>/glibc/2.39/lib64 : <store>/gcc/16.1.0/lib64]
    after:   [<store>/glibc/2.39/lib64 : <store>/gcc/16.1.0/lib64 : <subos>/lib]
    

    新增 mcpp.platform.runtime_search 契约模块:一条搜索目录有来源
    (payload / package / subos_farm / host_default)、次序是否机器本地
    次序 = 不可变性递减,farm 在最后 —— 载荷目录装一次不再动,<subos>/lib 每次
    xlings install 都重写;载荷在前,libc/libstdc++ 永远从被 pin 的载荷解析。
    交叉目标与非 ELF 格式不发 farm。

  • validation: pass 曾对一个跑不起来的产物成立。

    闭包解析在搜完 rpath 后回落到宿主默认目录,而宿主通常自带 libGL.so.1
    模型认为解析到了。但产物跑在私有加载器下,它的默认路径里没有宿主目录。
    现在宿主默认目录只在非 hermetic binding 下参与;hermetic 产物上一个谁都提供
    不了的 DT_NEEDED可证的失败(新判决 unresolvable),会让构建变红并指名。

    实测佐证(LD_DEBUG=libs):私有加载器的内建默认路径是 glibc 载荷自己的构建期
    前缀
    (…/fromsource-x-glibc/2.39/lib),这台机器上根本不存在;/usr/lib 从不
    被查。因此 e2e 206 里那条「安全的宿主 DSO 对照」此前报 pass 也是假绿 —— 它
    刻意不运行产物,而产物其实 127。已改为断言 inconclusive 并说明原因。

    [build] allow_host_libs 同时退出两个阶段。 它本就关掉链接期 hermeticity 检查;
    既然用户已声明「我有意伸到沙箱外」,mcpp 就不能再断言产物起不来(他们可能用
    LD_LIBRARY_PATH 跑,或装在私有加载器会看的地方)。⇒ 该档下未解析的 NEEDED
    inconclusive 并指名,而不是变红。一条声明,一个含义。

    另两处精度修正(CI 抓到的):unresolved 此前混装三种东西 ——「找不到的 SONAME」
    「读不了的对象」「512 上限」。只有第一种可证,故拆出 unresolvedSonames;
    产物的格式由产物决定,不由 binding 决定 —— Linux→Windows 交叉构建拿的是宿主
    binding(hermetic),产物却是 PE,「不是 ELF」落进 unresolved 后被判成「缺库」,
    crosswin.exe 构建失败。

变更

  • xlings 强相关模块归入 src/platform/xlings/:mcpp.platform.xlings
    mcpp.platform.xlings.subos_infomcpp.platform.xlings.runtime_selection
    (命名空间不变)。RuntimeBindingruntime_search 留在 src/platform/ ——
    它们是 provider 中立的契约类型,不是 xlings 专属。
  • resolution.jsonruntime.search 增加 closure 数组(路径 + origin +
    machine_local,保序);mcpp why runtime 按加载器次序打印它。
  • mcpp 为自己启动的每个进程声明 XLINGS_SUBOS_LD_PATHS=0 —— xlings 链接器包装器
    路径注入的退出声明(xlings#540)。
    今天是无操作;它落地后 mcpp 的 DT_RPATH 仍只含 mcpp 自己决定的内容。
    不读 $XLINGS_SUBOS_LIB:实测它指向当前 shell 的 subos,而 mcpp 有自己的
    registry home,两者通常由不同物理 glibc 载荷支撑。
  • 内带 xlings pin → 2026.8.11.2

v2026.8.11.1

Choose a tag to compare

@github-actions github-actions released this 11 Aug 03:12
1bc6074

新增

  • [build] module_extensions —— 哪些扩展名是模块接口,由工程声明。

    [build]
    module_extensions = [".ixx", ".ccm"]

    追加到内置的 .cppm。声明一个扩展名会同时做三件事:默认 sources glob 跟着
    变宽(文件才能被找到)、这些单元走模块规则(产 BMI、.o 无条件进链接)、
    新鲜度快路径扫描它们(加 import 会让构建图作废)。一个键而不是三处配置。

    任何扩展名都接受,唯独拒绝已代表其他角色的(.cpp .c .h .S …)——
    manifest 错误而非警告,因为宣称 .c 是模块接口会把 C 文件送进 C++ 模块规则,
    最终失败在一个既不提文件也不提这个键的地方。

    ⚠️ .ccm/.cxxm/.ixx 不进内置默认。进了的话默认 glob 会跟着变宽,
    于是 src/ 下躺着 vendored MSVC-only .ixx已发布包会在一次 mcpp 升级后
    突然开始编译它
    —— 而包作者改不了已经发出去的 tarball。

  • [build] build_program_timeout —— build.mcpp 的运行上限可配置。

    优先级 MCPP_BUILD_PROGRAM_TIMEOUT > 该包自己的 manifest > 内置 600s,
    macos_deployment_target 同构。超时报错点名要改的那份 mcpp.toml ——
    依赖超时时改自己的那份不会有任何效果,这正是 #410
    从外面看到的样子。不写这个键与写 0 不是一回事:不写=用默认上限,0=不设上限。

  • mcpp self doctor 报告构建策略。 生效的模块接口扩展名表、生效的超时值
    及其来源、以及本平台的 deadline 是否真的强制执行。
    另外 module_extensions 里零命中的条目会告警 —— 否则打字错误(.ixxx)与
    「这个工程还没有」无法区分。

修复

  • 超时上限在 Windows 上从来就是空操作。 capture_exec_deadline 只在 POSIX
    生效,其余平台直接回落到无界启动器 —— 于是 mcpp test --timeout
    --build-timeout、以及这个新键在 Windows 上设了等于没设。现在两侧各有实现:
    Windows 把子进程放进 Job 对象并在到期时关闭它,杀掉的是整棵进程树而不只是
    直接子进程(否则一个还攥着捕获管道的孙进程会让杀掉之后的读取一直挂住)。

  • .mm(Objective-C++)的对象编了但永远不进链接 —— is_implementation_source
    的清单漏了它。

  • stage 一个含汇编的依赖会静默丢掉那些源文件 —— 兜底 glob 漏了全部三种汇编扩展名。

架构

  • 「扩展名 → 角色」此前在 9 个文件 20 处推导,分成 8 份互不一致的清单
    (三份「什么算实现单元」、四份「什么算源文件」)。
    #272 修了链接侧,却漏了
    pick_rule —— 边上声明了 BMI 产物(那行读 providesModule),命令行却丢了
    -fmodule-output=

    收敛的形状不是「大家都调同一个函数」,而是分类只发生一次(文件进图时),
    之后当数据传递(SourceUnit::kindCompileUnit::kind)。扫描器手里本来就有
    所属包的 manifest,所以这一步没有新增任何管道。

  • mcpp 现在每次都显式告诉编译器某个单元是模块接口(-x c++ / -x c++-module /
    /interface /TP),而不是去维护「哪个驱动认哪个后缀」。实测(GCC 16.1 / Clang 22.1):
    Clang 根本不认 .ixx —— 把它当链接输入、警告、退出码 0 且不产 BMI;
    而显式旗标在已识别后缀上幂等(Clang 的 .cppm BMI 逐字节相同)。
    一张会过期、错了还静默的表不该存在。

  • src/platform/ 拆成 unix/ windows/ linux/ macos/;mcpp.platform.process
    对有界运行单点 if constexpr 分派,取代此前散落的平台分支。

兼容性

  • 未配置时构建图零差分:同样的文件被编、同样的 BMI、同样的对象进链接、
    同样的指纹目录。
  • module_extensions 指纹(它改图的形态);build_program_timeout 不进
    (它不改任何一条边 —— 进了会让「抬高超时」重建全世界)。
  • ⚠️ 旧版 mcpp 遇到 module_extensions 会警告+忽略,然后把那些文件当普通翻译单元
    编译 —— 错误的构建而不是干净的失败。发布用了这个键的包必须声明 mcpp 版本下限
    (见 docs/10-publishing-a-library.md)。

v2026.8.10.3

Choose a tag to compare

@github-actions github-actions released this 10 Aug 16:19
e53204a

修复

  • 宿主能力清单从「解析后的图」取,不再从根 manifest 取。 2026.8.10.2 引入的
    「自带 libc 的档拒绝宿主能力」只在根工程自己声明能力时生效 —— 而几乎没有应用
    会自己声明 capability:opengl.glx.driver,它依赖某个声明了的包(glfw / SDL 封装 /
    GL runtime),resolver 会给每条需求盖上请求者身份。读根 manifest 回答的是
    「作者写没写」(几乎总是没写),而该问的是「解析出来的图需不需要」。

    实测:一个真实 imgui 工程的 mcpp why runtime 列着
    capability:opengl.glx.driver [run] <- compat.glfw@3.4 (required),
    mcpp pack --mode self-contained 照打不误。修复后它正确拒绝,并列出
    abi:glibc, opengl.glx.driver, x11.display 三条;--mode vendored 正常打包
    并把三条写进 HOST-REQUIREMENTS

    同一处也修好了 mcpp packHOST-REQUIREMENTS:此前对真实工程是空的
    (空文件会被读成「什么都不需要」,而它现在根本不写空文件)。

    为什么原来的测试没抓到:它的 fixture 在根工程声明了能力 —— 恰恰是真实工程
    唯一不具备的形态。
    216 已改成依赖声明、消费方什么都不声明,并加了一条
    前置断言:那条需求必须先出现在 mcpp why runtime 里,否则测试等于什么都没验。

v2026.8.10.2

Choose a tag to compare

@github-actions github-actions released this 10 Aug 15:21

图形栈闭合与分发档位。完整设计与实施计划见
.agents/docs/2026-08-10-graphics-closure-and-distribution-tiers-design.md
.agents/docs/2026-08-10-graphics-closure-implementation-plan.md

修复

  • 依赖 BMI 缓存命中时,被恢复的包传递依赖的 std 没进构建图(#405)。
    消费方自己不 import std 时,gcm.cache/std.gcm 的 stage 边没有任何消费者,
    ninja 从不执行它,于是被恢复的 BMI 报 No such file or directory /
    Bad import dependency —— 一条完全不指向缓存的错误。缓存 miss 时依赖在本地编译,
    这个动作把 std 边带进图,所以第一个构建它的人永远是好的、之后每个人都坏,
    看起来像升级回归。修法把 std BMI 放进 _mcpp_staged_cache 聚合 ——
    那个聚合本来就是为「stage 边丢掉编译边携带的次序」而存在的。
    不动 cache key、不改 entry schema,现有缓存全部继续有效

  • mcpp build 会重放 mcpp test 留下的构建图(#407)。 三种模式写同一个
    build.ninja(指纹不含 dev-deps 与 test targets),而快路径只比源码 mtime、
    从不校验这张图是哪一种。于是 build → test → build 链测试、不链 target、
    还报 Finished;改坏一个测试文件会让普通 mcpp build 失败,而 src/ 一个字没动。
    修法是让 build.ninja 自己声明形态(# mcpp:graph=normal|test),快路径校验它即将
    重放的那张图。这是读取侧不变式:#387 那半边的写入侧修补被同时删掉了 ——
    写入侧修补要求每一个未来的图重写者都记得调它,而这正是 mcpp test 那半边
    --configure-only 修好之后仍然坏着的原因。

新增

  • 加载器标签契约(mcpp.build.loader_contract)。 可执行文件必须 DT_RPATH,
    共享库保持 DT_RUNPATH。DT_RUNPATH 只对携带它的对象自己发起dlopen 生效;
    图形程序到驱动要经三到四层 dlopen,而这些 dlopen 都不是它发起的,
    libGLX.so.0 / libEGL.so.1 代发的 —— 所以标签(不是路径)决定它能不能拿到 GPU。
    同一路径只翻标签,egl / gles2 / egl-surfaceless 从 llvmpipe 变 NVIDIA。
    反过来在上强制 RPATH 有害(传递性会打断 eglInitialize),所以这是一分为二、
    不是一起翻。链接期与 mcpp pack 的 patchelf 期读同一条契约
  • rule E:标签校验落在产物上,并写进 resolution.jsonloader_tags
    warn-first,与既有闭包规则同一推进节奏。记录而不只是告警 ——
    一个只在沉默中通过的检查,和一个根本没跑的检查,输出完全相同。
  • mcpp pack:产物里不再残留构建机路径。 此前只有主二进制被重写,
    bundle 进来的每个 .so 都保留着链接时的 RUNPATH,而在这个生态里那是一串指向
    构建机 xlings store 的绝对路径。「依赖 xlings 生态」是设计选择,
    「依赖这一台机器的这一份 store」是缺陷,而且它在构建它的机器上跑得好好的。
    另外 patchelf --set-rpath 默认写 DT_RUNPATH —— 对可执行文件而言是同一个缺陷晚一层。
  • HOST-REQUIREMENTS:自包含也有底。 驱动类库只能来自目标机器
    (与内核模块锁步,且专有栈禁止再分发),所以打包这类程序的诚实产出不是一个悄悄
    少了它的 bundle,而是 bundle 加上一份声明。带 discovery 一列,因为几种发现
    机制互不通用 —— 一种是烙进派发库的搜索路径,另一种是 JSON 里的绝对路径,
    「把目录搬过去」只满足其中一个。
  • 自带 libc 的档遇到宿主能力硬拒。 --mode self-contained--mode static
    在存在 run 期能力需求时于 plan 期失败,并指出改用 --mode vendored
    两者坏在同一件事上:那个 .so 带着对宿主 libc 的要求进来,而进程里没有那份
    (#392 / #401 的两个方向)。此前两档都链得过去、然后运行时崩或静默降级。
  • [[runtime.requirements]] discovery 声明式,mcpp 绝不推断 ——
    从能力名推断机制就是把 provider 专属知识写进 mcpp(test_runtime_contract 正是
    为此设的门),而且它是 provider 的属性、会脱离 mcpp 变化。未声明报 unknown
  • 声明的 runtime artifact 带身份判决。 resolution.json 每个 artifact 增加
    identity:ok / mismatch / missing / unverified。这正是 mcpp 已经
    对私有 libc 执行的规则(glibc@2.44 只解析那一个载荷,陈旧即错误)的推广,
    纯路径事实、跟随符号链接、不需要认识 GL。mcpp why runtime
    artifacts: (none declared) 改为 (not declared by the environment — nothing to verify):一个有名无物的 provider 是未验证,不是验证通过。

变更

  • 内带 xlings 升到 2026.8.10.4 其中 2026.8.9.2 的 semver 重写让四段版本可以
    参与范围比较 —— xim:libglvnd@>=1.7.0.1 此前解析成 package not found,
    这正是 mcpp-index 全量跑里 8 个图形成员全红的原因(不是数据缺陷)。