๐ One Binary, Six OSes: What I'd Tell Myself Before Starting
Sixth and last post in the one-bin-to-rule-them-all series. Previously: intro, probe matrix, extern-static pattern, ripgrep and dog, the async wall.
Five posts of evidence ๐.. A probe, three real tools, a forked libc, a stack of std patches, a new reusable crate for system config, and a clean cut between what works and what doesn't. This post is the wrap-up: the finding-by-finding scoreboard, the things I had wrong in my head going in, and a proper thank-you to the people whose shoulders this whole thing sits on.
I'll keep it short. The substance lives in the preceding posts; this is the index ๐.
Finding disposition
Fourteen findings came out of the investigation. Twelve are closed by the work in the previous posts, two are deferred to cosmo itself, one is really just expected behaviour that we noted and moved on from. Ordered by finding number, not by importance:
| ID | What broke | Closed by |
|---|---|---|
| F-001 | struct stat layout wrong on aarch64 | libc-cosmo: redefine stat for cosmo-aarch64 |
| F-002 | errno numbers pass through unnormalised on BSD / macOS | std patch: extern-static COSMO_E* cascade in sys/io/error/unix.rs |
| F-003 | socket constants mismatch, TcpListener::bind fails | libc-cosmo: extern-static socket constants |
| F-004 | Command::new fails on non-Linux | std patch: process/unix/common.rs switches to ErrorKind::WouldBlock check |
| F-005 | thread::sleep panics on FreeBSD | libc-cosmo: CLOCK_MONOTONIC extern-static |
| F-006 | cosmo loader aborts on OpenBSD 7.7+ | deferred: cosmo-side, not a Rust fix |
| F-007 | OpenBSD 7.6 installer kernel panic in my qemu | deferred: qemu/kernel interaction, out of scope |
| F-008 | Windows errno passthrough | same std patch as F-002 |
| F-009 | TcpListener::bind fails on Windows | same as F-003 via libc-cosmo |
| F-010 | Command::new("echo") fails on Windows | working as designed: echo is a cmd builtin, not a PE binary |
| F-011 | Instant::elapsed panics on macOS / OpenBSD | same as F-005, plus std patch in sys/time/unix.rs |
| F-013 | getrandom probe misclassifies ENOSYS | getrandom-cosmo: skip the probe under cfg(cosmo) |
| F-014 | no /etc/resolv.conf on Windows | cosmo-sysconf: runtime dispatch, GetAdaptersAddresses on Windows |
| F-015 | MSG_NOSIGNAL rejected on Windows | libc-cosmo: extern-static + one-line std patch |
| F-016 | async IO reactor is compile-time target_os | deferred: structural, needs a mio refactor or a cosmo-side epoll shim |
Twelve closed with the patterns this series built. Three genuinely open, and the character of each open finding is worth naming.
F-006 is cosmo-side. OpenBSD 7.7 tightened syscall-origin enforcement in ways cosmo's APE loader trips over. I could not run any cosmo binary on OpenBSD 7.7 or 7.8, C or Rust. That's something that would probably have to be addressed in the loader itself, but I'm not the person to say how. I poked around enough to convince myself it wasn't a Rust-side problem and then stopped.
F-007 is further out of scope than F-006. The OpenBSD 7.6 installer kernel-panicked on the qemu I was running. It isn't about cosmo and isn't about Rust; is a host-environment artefact that I recorded and moved on from. The fact that OpenBSD 7.4 is in the matrix via a prebuilt cloud image is the workaround.
F-016 is the one from the previous post, and it's the most interesting of the three. It's the only one that stops the series' thesis at the door, because neither the extern-static pattern nor a cfg(cosmo) gate can reach it. Async Rust under cosmo is Linux-only today, and I don't have a confident view of what it would take to change that.
Things I got wrong going in
I expected macOS to be the hard target, it was mostly easy. I expected Windows to be intractable, it came down to one honest-to-goodness Windows-shaped problem (F-014, DNS discovery) and a lot of Linux-constants-baked-at-compile-time. I expected OpenBSD to be a rounding error, is actually where cosmo itself hits walls, not where Rust does. And I expected TLS to be the wall for xh, is inconvenient but tractable, and the real wall was the mio reactor, which isn't a constant-divergence problem at all.
Thank you ๐
This was, honestly, a lot of fun ๐คฉ.. I learned more about syscall conventions, libc layouts, rustc targets, and the actual shape of how Rust links against the operating system than I had any right to from a handful of evenings of work, and the only reason any of that was possible is that I got to stand on the shoulders of some very large giants: Justine Tunney for Cosmopolitan and the APE format (still one of the wildest pieces of systems work I've ever read ๐ฅ), @ahgamut for rust-ape-example which is the entire scaffolding that made Rust-on-cosmocc possible in the first place, and the Rust ๐ฆ community in general for a language and standard library that were close enough to "already correct" that a handful of cfg(cosmo) gates could carry most of the weight.
Sooner or later, after a healthy amount of polishing, I'll release the full set of forks and patches publicly ๐.. It will most likely break at the next upstream commit on any of the repos it depends on, because is the nature of living on a branch that nobody upstream has opinions about yet. But the shape of what's there today is real, and the ideas transfer even if the code rots.
If you want to see any of it with your own eyes in the meantime, the three sync binaries from post 1 are still there:
Same disclaimer as before: these are binaries from a stranger on the internet, don't trust them with anything important, run them in a VM or a container if you want to poke at them seriously ๐ค.
Thanks for spending the time reading a slightly too-long journey into systems programming. It meant a lot that anyone came along for the ride ๐.
Happy hacking everyone ๐ฆ!