自我管理与修复

September 6, 2026 · View on GitHub

编写日期: 2026-07-29 | 版本: 2026.7.29.0

自我管理与修复

xlings self 管理 xlings 自身:升级客户端、检查并修复 home 的状态、清理缓存。 日常几乎用不到,但升级之后、或者某个命令开始报奇怪的错时,从这里开始。

升级

xlings self update

它做两件事:刷新包索引,然后把 xlings 自己作为一个包安装到最新版。 升级完成后可能会看到这一行:

packages installed by the previous client may still be registered in its format
  run  xlings self doctor --fix

这不是错误。它的意思是:这个 home 里的包是更早的客户端注册的,记录格式还是旧的。 旧格式仍然能用,但新客户端读它的时候会看到一些"看起来坏了、其实没坏"的条目。 跑一次 --fix 就迁移完了,之后这行提示不再出现。

体检

xlings self doctor

只读,不改任何东西。它检查四层状态是否一致:

检查什么
workspace当前 SubOS 声明的活跃版本
版本数据库每个 包@版本 的注册记录
shimbin/ 下的转发文件
payload记录指向的目录和里面的可执行文件
sysrootlib/lib64/usr/etc/share/ 下的链接是否还指得到东西

退出码 0 表示当前 SubOS 健康;非 0 表示有需要处理的问题。 只有告警(例如"某个 alias 可能是系统命令")不会让它变红。

默认输出是收敛过的:一个丢失的 payload 只报一行,而不是它注册的每个程序报一行; "没问题但值得知道"的条目(例如只用来锚定发布的包)合并成一行计数。想看全部:

xlings self doctor --all

修复

xlings self doctor --fix

一次跑完,把能修的都修掉。它会:

  • 重建缺失的 shim,删除多余的 shim
  • 丢掉指向不存在版本的绑定边(这类边会让 useinstall 都失败)
  • 把指向未注册版本的活跃项取消激活 —— 包括其他 SubOS
  • 对 payload 坏掉的包重新注册;不行就卸载重装
  • 把断掉的 sysroot 链接重新指回去(下面单独说),指不回去的才删除
  • 应该在、却不在的 sysroot 链接放回去(被更早的客户端删掉的那些)
  • 如果这个 home 被整体挪过位置,把记录和链接重新指到当前根(下面单独说)
  • 上面都救不回来、且任何索引都提供不了的记录,直接清除

修复结束后会重新体检一遍,你看到的报告是修复之后的状态,不是修复之前的。 所以"报了一堆问题又说修好了"不会发生;剩下的行就是真的还没解决的。

想先看看它打算做什么:

xlings self doctor --fix --dry-run

列出将要执行的动作,一个字节都不改。

关于"清除记录"

--fix 会删除注册记录,但只在同时满足这些条件时:

  • payload 目录已经不存在了(或者存在但里面没有可执行文件、也不是发布锚点)
  • 重新注册、卸载重装都失败了
  • 没有任何索引能重新提供它
  • 没有别的 SubOS 还在用它

删掉的是一个指向虚空的指针 —— payload 早就没了,留着只会让每次体检变红。 包本身、payload 本身,都不会被 --fix 删除。

这一步会丢信息("这个包曾经装过"这条事实没有了),所以它不会被算作"修好了": 一次清除过记录的运行,结尾不会说 OK,而是明说清除了几条。 删除 sysroot 链接同样算丢信息,同样不会说 OK —— 从 sysroot 里删掉一个文件, 不比丢掉一条记录轻。

退出码仍然是 0。退出码回答的是"这个 home 还需不需要人来处理", 合法清除之后它不需要 —— 把它变成非 0 等于把"丢了东西"和"坏了"混成一个信号。

断掉的 sysroot 链接

SubOS 的 lib/usr/include/ 这些目录里是指向 payload 的链接。 包被换版本、被移除之后,可能留下指不到东西的链接。

--fix 对它们的处理顺序是先问版本数据库: 如果数据库知道这个库当前该指向哪里,就重新指过去; 只有在没有任何记录能说明它该指向哪里时,才删除它。

"目标不存在"和"目标救不回来"不是同一件事 —— 前者只是链接过期了。

如果你把整个 home 挪过位置

mv 搬 home 不是受支持的操作,以后也不会是:payload 里的可执行文件把旧路径 写死在 PT_INTERP/RPATH 里(内核按字面读它,$ORIGIN 在那里不展开),linker script 里也是绝对路径。这些东西不是 xlings 的簿记,是 payload 的内容,谁都改不回来。

但**"不修"不等于"可以毁"**。挪过之后 self doctor 会先说出这件事:

✗ home relocated   this home is at <新路径>, but its records were written for <旧路径>
                   2901 registration(s) still name the old path and 2901 of them
                   have their payload present here
  → run            xlings self doctor --fix
  • note           re-points the versions database and the sysroot links;
                   binaries that baked the old path into PT_INTERP/RPATH are
                   NOT repaired — re-provision the home if the toolchain fails

--fix 会把 xlings 自己的簿记指回当前根:版本数据库、索引缓存、SubOS 清单里的 绝对路径,以及所有 SubOS 的 sysroot 链接。它不会因为记录里的路径不存在 就删链接、清记录 —— 判据是"payload 在不在当前根下",不是"记录里的路径存在不存在"。

它也不会因此宣布这个 home 好了。上面那条 note 是认真的:用旧路径编译出来的东西 仍然可能起不来。真正的答案还是重新 provision($MCPP_HOME 下的 registry 是可重建 缓存,删掉重来就是)。

被更早的客户端删掉过链接的 home 也能救回来:--fix 会把当前选择声明、却不在位的 链接重新放回去。单个包也可以自己来 —— xlings install <包>@<版本>,payload 还在 的话它不下载、只重新注册并重新放置链接。

命令给的建议一定能跑

报告里 → run 后面的命令是可以直接粘贴执行的完整命令。 它给的是的坐标,不是程序名 —— nm 是 llvm 装出来的程序, 索引里没有叫 nm 的包,所以这里不会出现 xlings install nm。 如果没有任何包能提供某个条目,它会直说没有办法,而不是给一条跑不通的命令。

元数据重置

xlings self doctor --reset-metadata

单独一个开关,--fix 不包含它。原因是它会丢信息:把读不出来的发布元数据 (成员列表、头文件资产)整个丢掉,条目退回成一个可以单独切换的版本。 只有在这些元数据已经损坏、且重装也救不回来时才用它。

清理

xlings self clean            # 清缓存 + 回收没人引用的包
xlings self clean --dry-run  # 先看看会删什么

payload 是按引用计数共享的,clean 只回收所有 SubOS 都不再引用的那些。

其他

xlings self config     # 显示 home 路径、当前 SubOS、镜像等配置
xlings self install    # 从 release 包安装 xlings(一般由安装脚本调用)
xlings self init       # 创建 home / data / subos 目录
xlings self migrate    # 把旧版本的目录布局迁移到 subos/default

出问题时的顺序

xlings self doctor              # 先看清楚是什么问题
xlings self doctor --fix --dry-run   # 再看它打算怎么修
xlings self doctor --fix        # 修
xlings self doctor              # 确认干净了(退出码 0)

如果 --fix 之后还有剩余问题,报告里会写明每一条为什么没修好。 属于其他 SubOS 的 payload 问题不会在这里修 —— 修它需要在那个 SubOS 里安装, 会把包拉进当前环境,所以报告只会告诉你去哪个 SubOS 处理。

相关文档