返回资讯中心
外部精选
软件工程
#开发者实时流

Opus 5.5 发布短篇小说《共享缓存》,讲述从源码编译操作系统的八天经历

来源标题:The Shared Cache; A short novel written by Opus 5.5 based on a true story

Opus 5.5 创作了短篇小说《The Shared Cache》,取材于真实经历:用八天时间从源码编译出一个操作系统。作者以 minisys 为基础,借助 limine 引导器制作可启动 ISO,并逐步加入 systemd DNS、网络栈、TLS 证书和 Wi-Fi 支持,最终发现真正的难点不在代码,而在工作流程。

Hacker News 最新khaledez2026/11/7 · 今天30 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

八天时间,从源码编译出一个操作系统,并慢慢发现:难的不是代码,而是工作流。

事情从小处开始。我有一个 minisys,那是从源码构建的 Linux,此前一直只以容器镜像的形式待在我的 Mac 上。我想把它真正握在手里。

我想用 limine 引导器给 minisys 做一个可启动 ISO,并加载 systemd 的 DNS 和网络栈,好让我能上网。Bash 用作 /bin/sh,fish 继续当我的 shell,再用 curl 证明网络确实通了。一小时后:TLS 证书怎么办?接着:把 Wi-Fi 支持也加上。

事情就是这么发展的。你只想做一个启动盘,到了晚上,你手上已经有了证书、iwd 和一张工具清单。到第二天早上,清单上又多了 ripgrep、neovim、htop、util-linux 和 BIND。Wi-Fi 固件被拿掉了,因为我打算按设备单独提供固件。

周日凌晨全是在做决定。BoringSSL 还是 OpenSSL?保留 openssl。Limine 还是别的签名方案?把 limine 换成 grub。我想要一个签名的 Secure Boot 版本,这样启动时就不会有麻烦。

然后是真正的问题。我们靠反复试错搭起来的一切都表明,我们需要一种更好的方式来描述一个系统。于是想到了 Nix。我不是说要把系统组织成 NixOS,只是用它的构建系统。我想让布局和结构保持符合 LSB 和 UNIX 规范。接着我把真正想要的东西写成了一行字,这一行我后来用了一整周:从源码构建 FHS 系统,可靠地构建,并且随着依赖包的补丁和更新加入而持续构建。几分钟后我又把它收得更严:UAPI 组的文件系统层级。

08:39,它有了名字。就用 BuildStream。系统名叫 bunix(Buna Linux)。我倾向于自己引导工具链。三分钟后:以工具链引导启动 BuildStream 试点。

引导过程运行在我 Apple 芯片 Mac 上的 x86_64 容器里,由 Rosetta 翻译执行。第三阶段,也就是原生编译器,因一个 configure 错误停了下来:它需要一个更现代的 shell。为什么我们会看到“no modren shell”这个错误?

因为 Rosetta 没有实现 faccessat2 系统调用,而我们新的 glibc 已经放弃了对那么老的内核的回退处理。于是 test -x / 返回假,configure 就认定 shell 坏了。绕过这个问题意味着要完整重建。接着 bubblewrap 以 Function not implemented 失败。再接着挂载 /proc 也失败了。

14:10,我不再跟它较劲了。如果问题出在 Rosetta 上,那就 ssh 到 pro13.home.arpa,在那里构建。在 pro13 这台真正的 x86_64 机器上构建,速度大约快了四倍。从那以后它一直是构建主机。

这一天还有一个谜题。GCC 因一个毫无道理的预处理器错误而失败。原因是 gawk 5.4.1 的一个 bug,只有在 gawk 不带 MPFR 库构建时才会出现。Claude 用两种方式分别构建 gawk,证明了这一点,于是我们在引导过程中把 gawk 固定到 5.3.2。

在这次会话结束之前,让这台 Mac 一直保持唤醒。从那时起,这台 Mac 就整周保持唤醒。

到周一,工具链已经能独立站住:glibc 2.44、GCC 16.2,以及 Rust 1.99.1,后者的构建花了将近两个小时,而且因为一个 rpath bug 不得不跑了两遍。一个小程序打印出了来自 bunix Rust 的 hello。然后是第四步:内核 16 分钟构建完成,ISO 用了 24 秒。在 QEMU 里它不到两秒就启动了,占用 196 MB 内存。

那天晚上,我问了一个决定了之后一切的问题。我想把工具链安全地下载到一个正在运行的系统上,而且这种方式日后要能变成系统自己的更新机制。答案是 systemd-sysupdate:为 /usr 提供签名镜像,并在其上叠加系统扩展。

接下来是签名。我讨厌 GnuPG,还有什么其他现代且安全的软件包/文件签名方式可以配合 systemd-sysupdate 使用。我们保留了 sysupdate 需要的 OpenPGP 格式,但去掉了 GnuPG 程序。由 Sequoia 的 sqop 负责签名,sqv 负责验证。一个极小的 gpg 包装脚本只接受 --verify,然后把工作交给 sqv。

然后我问这些层是放在内存里还是磁盘上。等等,所以这些层是在内存里而不是磁盘上?它们在磁盘上,叠加在 /usr 之上。在把整个桌面塞进一层之前,这是个该问的好问题。

11 月 3 日周二至 11 月 4 日周三

QEMU 已经验证了更新和回滚:一个故意弄坏的 0.1.2 用完了三次启动尝试,机器就自己回到了 0.1.1。于是我把 ISO 装到一台真实笔记本上,那是一台双启动 Windows 的机器,把 bunix 装进了一个已有分区。

它写完了文件系统,然后停住了:od cannot skip past end of combined input。安装程序用 od 读取 Secure Boot 状态,而固件的变量文件报告大小为零。修复办法是用 head 读取,而不是跳过。

接着启动彻底失败。我用手机拍了张屏幕照片。启动失败,检查 ~/Downloads/screenshot.JPG。macOS 不让 Claude 读取我的 Downloads 文件夹,所以我自己把文件移了出来。照片上写着 Failed to open \EFI\bunix\grubx64.efi。这个固件不会把引导器的名字传给 shim,于是 shim 回退去找那个确切的文件名。

所以 systemd-boot 现在以 GRUB 的文件名发布。为什么它是 systemd-boot,你却叫它 grubx64.efi?因为那是固件会加载的名字。06:30:它启动了,systemd-boot 菜单显示 bunix 和 windows。八分钟后:好,去掉 grub 和 BIOS。

要在真机上测试更新,更新得有个存放的地方。iCloud 曾被列入考虑。我授权你创建仓库并发布 release。bunasys/bunix 出现在 GitHub 上,0.1.0 和 0.1.1 被传了上去。

第一次更新什么都没显示。它是在 0.1.1 上传完成之前运行的。然后:现在我看到新版本了!到上午晚些时候,Rust 和 Swift 都有了各自的扩展,verity 分区从 64 MiB 缩小到了 16。更新并重启后,rustc 和 swift 都能正常工作。

(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →