A native, Zig-style libc for swiftlang

I'd like to propose extending swiftlang with a native libc implementation, built the way Zig's libc subproject is doing it — incrementally replacing vendored C source with native language wrappers.

Not to be scoped to Embedded Swift alone but it serves as an example, moving toward Concurrency support (e.g. the mutex work in swiftlang/swift#89707), and that naturally extends to wanting custom executor support. This in turn needs consistent low-level primitives to build things like event-loop-style executors for IoT targets on.

But the case for a native libc doesn't depend any target targets specifically —

once support for custom executors land, a native, incrementally-adopted libc seems worth pursuing at the swiftlang level.

6 Likes

Sorry, but hate the idea. What I'd like to see instead is a completely new Swift library that fully replaces the functionality of a libc but with both a Swift implementation and interface, a libswift using absolutely new architecture and abstractions instead. Over time, we could port the Swift stdlib and fundamental packages like swift-crypto or NIO to rely on this new libswift and slowly remove the dependency on the platform libc from Swift on all platforms.

Basically, we have been building on old libc foundations for far too long now, time to cut libc out instead and create something new, which provides no familiar libc functions (whether we provide a @c interface also for these new Swift functions in libswift is an optional stretch goal :wink:).

8 Likes

these do not exclude each other. copy, customize
a completely independent version on top is the next evolutionary step.

They are significantly different efforts that may have some overlap. Go has already made the jump, avoiding the C dependency as much as possible, and I have seen devs rave about the fact that they can avoid the old platform libc altogether when compiling and running their Go executables. Such a libswift approach is not without its drawbacks, ie rather than just pulling in the platform libc, you now need to port libswift to every Swift platform and then maintain it yourself.

But if you're going to go to all the trouble of reimplementing such base functionality in Swift, better to rethink these old platform libcs with new approaches that are possible with hindsight and providing a purely Swift interface instead.

4 Likes

For additional context, I briefly made some noises about something similar before, though that was more about a more consistent surface layer for accessing libc rather than a libc implementation per se, and I don't really know in detail what Zig has done.

I'd be curious about the idea, but the resultant library cross-dependencies will be potentially significant...

Zig's whole value is staying ABI/API-compatible with the platform libc while swapping the guts underneath. That's not incidental — every C library you import, every syscall wrapper, assumes the standard libc contract (errno, malloc crossing library boundaries, FILE*). Break that and you don't lose some old functions, you lose Swift's C interop story, one of its actual strengths. A from-scratch libswift either can't talk to any of that, or quietly reimplements libc semantics under a new name — Zig's approach with extra steps.

On the Go comparison: Go only skips libc on Linux, because Linux's raw syscall ABI is stable enough to hit directly. Everywhere else (Darwin included) Go still goes through the platform's libc-equivalent. That's "skip libc where the OS explicitly allows it," which Swift can already do on Linux, not "avoid libc" as a general strategy. Getting Started with the Static Linux SDK

And Finagolfin already named the cost: a libswift needs porting to and maintaining on every Swift platform indefinitely, with none of musl/glibc's decades of hardening to lean on. Incremental vendor-then-replace gets you a working implementation the whole time instead of a multi-year gap.

Nicer Swift-native APIs can still come later on top — compatibility first doesn't foreclose that, incompatibility first forecloses the easy way back.

1 Like

I like both ideas but an embedded-friendly Swift libc is more _readily_ useful.

I sure hope not.. I think the idea would be to write this essentially dependency free. Otherwise I wouldn’t bother.

No, you wouldn't lose it at all, you simply have the choice of replacing that dependency with a modern libswift. If you prefer building on libc, linking against it will continue to be available, as most do today. Any large Swift project would simply have some proportion of Swift packages that build on libswift, and some that continue building on libc: replacing the libc dependency with libswift in the stdlib and popular core packages like Foundation or NIO would have no bearing on an arbitrary Swift package's choices.

Swift can do so today only if you avoid the full stdlib and core libraries like Foundation, which depend on libc extensively. A Swift stdlib and corelibs built on libswift would allow you to avoid the libc and use Foundation. :smiley:

No reason libswift could not incrementally vendor and replace libc also: you'd simply be slowly replacing the libc calls with new Swift ones. If wanted, you keep the old libc calls around in stdlib/Foundation for backward compatibility using conditional compilation.

Compatibility will foreclose completely new designs, which is what we need, as C is antiquated by now. But you're right that libswift can't go back, while wrong that it can't coexist with libc in the same Swift codebase.

This is the crux of the matter: do you have new ideas to replace the old libc architecture and abstractions with? If so, might as well ditch the libc interface too; if not, better to keep it. Since most don't, they keep it.