Repository navigation
emit build-database 供 IDE 调用:离线缺依赖的错误码、规划期间不泄漏调用方的管道、xlings 调用要有期限(附联网效应、auto_refresh、索引镜像) #648
Description
Activity
Implemented in 2026.9.16.1 (#650). The triage record is
.agents/docs/2026-09-16-646-649-four-issues-by-home.md; the plan and its readings are in.agents/docs/2026-09-16-646-649-implementation-plan.md.What started the refresh. Reproduced on openxlings/xlings: the refresh decision looked up
(mcpplibs, ftxui), missed, and asked for a network refresh, while the resolver went on to find the package through its deprecated bare-name rung (compat.ftxui). With the 120 s debounce, every build of a project holding a barecompat.*dependency ranxlings updateonline. That is the trigger behind the report, and it is a defect on both sides: the engine's decision now walks the same rung the resolver walks before it calls a miss (e2e 730), and openxlings/xlings#597 spellscompat.ftxuiandcompat.gtestin its own manifest.The rest of the report, item by item.
- Children started while planning no longer inherit the caller's pipe: the saved stdout descriptor is close-on-exec, and not inheritable on Windows. A build program started by
emit build-databaseused to hold the caller's pipe as fd 3, which is what kept an editor's read open. (e2e 731) - xlings children are owned and bounded. They run in mcpp's own process group (a job object on Windows) under a signal guard, so cancelling mcpp cancels them. A refresh has a total deadline,
[index] refresh_timeout(default 120 s); an install has an inactivity deadline. A refresh that times out warns and is not retried in that run. (e2e 732) - An offline plan that needs a download has its own code: refusal
offline-download-required, envelope codeMCPP_OFFLINE_DOWNLOAD_REQUIRED, naming the first missing item. (e2e 733) [index] auto_refresh = falsegoverns every implicit refresh, including the three that bypassed the policy. (e2e 734)- Every envelope's
effectsnow reports observednetwork, as docs/50 requires. (e2e 735)
The caller's side. The measures listed for mcppls -- planning offline by default, its own process group, a cached last document -- belong to the caller and are correct as stated. With the engine's bounds and the offline code they no longer have to stand alone.
Verification. A SubOS sandbox with CN mirrors for both xlings and mcpp runs the scenarios against the published engine and index:
version=2026.9.16.1 fails=0. This issue's assertions areT: cjson@1.7.19 resolves through the rung and asks for no refresh,A2: no planning child holds the caller's pipe,an offline plan that needs a download has its own code, andthe mcpplibs artifact names the GitCode mirror. The same script against 2026.9.15.2 readsfails=10.- Children started while planning no longer inherit the caller's pipe: the saved stdout descriptor is close-on-exec, and not inheritable on Windows. A build program started by
Closing. Every item of this issue was delivered in 2026.9.16.1 (#650) — with
mcpp:plugins0.12.0 for the plugin-side members — and the close-out record merged as #653.The verification is the part worth keeping: a SubOS sandbox with CN mirrors for both xlings and mcpp ran the scenarios against the published engine, plugins and index and read
version=2026.9.16.1 fails=0. The same script against 2026.9.15.2 readsfails=10, so each assertion measures this change rather than the setup it runs in. Two follow-ups also landed and are not open work: #651 (two spellings of one version constraint are one source, found by the review before the release) and the sandbox reading itself.Records:
.agents/docs/2026-09-16-646-649-four-issues-by-home.md(triage) and.agents/docs/2026-09-16-646-649-implementation-plan.md(plan, ledger, readings).Where the delivery contradicts the report, the comment above says so — those corrections are the reason to read it rather than this line.
概述
mcppls(mcpp-language-server)在后台调用
mcpp emit build-database --format json(#636,2026.9.15.1 起提供)读取工程的构建描述。2026-09-16 在 openxlings/xlings 上:xlings update,这条网络连接挂了约 11.5 分钟,mcpp 一直阻塞。xlings update仍持有调用方的标准输出管道,调用方又多等了 6.5 分钟才读到管道结束。mcppls 这边会改为默认离线调用,并自己兜住挂起(见文末)。下面六项需要 mcpp 适配:前三项是这次挂起的原因,同样影响在终端里运行
mcpp build的用户;后三项让调用方能正确判断和提示。现场(xlings,mcpp 2026.9.15.1,Linux)
bin/code启动(VSCODE_CLI=1,不解析登录 shell 的环境),扩展宿主里没有用户终端中的代理变量与 PATH。mcppls 在此环境中运行mcpp emit build-database --format json。xlings update连 GitHub(IPv6,443 端口),发送队列停在 85 字节,一直没有确认,也没有超时。sh与xlings update被 init 收养,它们的 fd 3 与调用方读取 mcpp 标准输出的描述符是同一个管道(/proc/<pid>/fd核对)。调用方直到xlings update退出才读到管道结束。MCPP_OFFLINE=1 mcpp emit build-database --format json在用户终端环境与上述编辑器环境中都是 2.6 s、退出 0,输出逐字节相同(2,608,930 字节)。原因(代码 @ 2fc7b5b)
emit build-database与mcpp build走同一个prepare_build,依赖与工具链解析真实执行,可能刷新索引StdoutToStderr用dup(1)保存原标准输出,没有 close-on-exec,最低空闲描述符正是 3;规划中经popen启动的程序都继承调用方的管道update_index→run_streaming:popen加阻塞fgets加pclose,没有期限;只在非零退出时重试 3 次,挂起时无效MCPP_BUILD_DATABASE_PLAN_FAILED,调用方只能匹配消息文本effects只有read-project、write-global-cache(和exec-build-script),这次刷新了索引也不含networkauto_refresh只约束decide_for_dependency与decide_for_miss;工具链自动安装前的ensure_official_package_index_fresh、工程自定义索引的首次同步不受它约束ensure_official_package_index_fresh的注释已经提到 “xlings update… stalls for minutes on slow/blocked networks (the Termux first-run / build hang)”。按需触发的刷新减少了次数,但一旦触发,仍然没有期限。需要的适配
A1 离线缺依赖:专门的错误码
MCPP_BUILD_DATABASE_PLAN_FAILED,缺的是什么只写在消息文本里。mcpp build,后者提示查看诊断。调用方不应依赖消息文本。MCPP_OFFLINE_DOWNLOAD_REQUIRED。emit build-database,信封中出现该错误码,诊断中含包名与版本,退出码 1。A2 规划期间不把调用方的描述符交给子进程
StdoutToStderr用dup(1)保存的调用方管道没有 close-on-exec,经popen/std::system启动的 xlings 与它的后代都继承了这个管道。mcpp 自己结束后,调用方仍读不到管道结束。$(mcpp …))都可能被 mcpp 的后代无限期挂住。这次多挂了 6.5 分钟。fcntl(1, F_DUPFD_CLOEXEC, 3)保存。close_range/posix_spawn_file_actions_addclosefrom_np,或逐个设FD_CLOEXEC)。emit build-database的输出,并用一个会挂起的 xlings 替身([xlings] binary指向它)。结束 mcpp 后,调用方 1 s 内读到管道结束;替身进程的/proc/<pid>/fd中没有调用方的管道。A3 xlings 调用有期限,并与 mcpp 一起结束
emit build-database与mcpp build会一直挂住,只能手动结束。prepare.cppm已规定“刷新失败只警告,之后仍用本地数据解析”(L4465-4472),但挂起的刷新永远不会“失败”。config.toml中配置)。超时视为刷新失败,按既有语义继续用本地数据;本地数据足够时,命令照常成功。emit build-database在期限后返回并成功。A4 信封的
effects报告实际发生的联网--protocol-version的静态表中,emit build-database含network;每次运行的信封从不含network。network加入信封的effects。network;--offline运行的信封不含。A5
auto_refresh = false约束所有隐式刷新mcpp index update”,但工具链自动安装前的刷新与自定义索引首次同步仍会联网。auto_refresh约束;config.toml注释与文档中写明只有--offline能完全禁止联网。auto_refresh = false且缺少工具链时,不执行xlings update,诊断提示运行mcpp index update。A6 mcpp-index 的镜像地址
mirror = CN选择的是包描述中的下载地址;这次现场 mcpp 私有仓库的.xlings.json为"mirror": "CN",xlings update连接的仍是 GitHub。xlings-res/mcpp-index的 gitcode 镜像后,为默认索引加上{"GLOBAL": …, "CN": …}形态,刷新时按mirror选择。mirror = CN时,mcpp index update不访问 github.com。mcppls 这边的做法(不依赖上述适配也会做)
MCPP_OFFLINE=1调用emit build-database。离线缺依赖时,状态栏提示用户在自己的终端运行mcpp build:代理与凭据只有用户的终端才有。A1 之后改用错误码识别。相关
emit build-database需求)、mcpp emit build-database, program probes as argument vectors, and xlings 2026.9.14.1 (2026.9.15.1, #636) #639(实现)xlings update的连接没有超时,IPv6 不通时也不回退 IPv4,另行报告