Top
Best
New

Posted by ingve 4 days ago

Zig Libc(ziglang.org)
355 points | 159 comments
OsamaJaber 4 days ago|
250 C files were deleted. 2032 to go. Watching Zig slowly eat libc from the inside is one of the more satisfying long term projects to follow
LexiMax 4 days ago|
That's something I've always admired about Zig.

A lot of languages claim to be a C replacement, but Zig is the second language I've seen that seemed like it had a reasonable plan to do so at any appreciable scale. The language makes working with the C ABI pretty easy, but it also has a build system that can seamlessly integrate Zig and C together, as well as having a translate-c that actually works shockingly well in the code I've put through it.

The only thing it didn't do was be 99% compatible with existing C codebases...which was the C++ strategy, the first language I can think of with such a plan. And frankly, I think Zig keeping C's relative simplicity while avoiding some of the pitfalls of the language proper was the better play.

WalterBright 3 days ago||
D can import C files directly, and can do C-source to D-source translation.

D can compile a project with a C and a D source file with:

    dmd foo.d bar.c
    ./foo
audunw 3 days ago|||
Do you have to bring up D in every Zig related post?

I do like D. I've written a game in it and enjoyed it a lot. I would encourage others to check it out.

But it's not a C replacement. BetterC feels like an afterthought. A nice bonus. Not a primary focus. E.g. the language is designed to use exceptions for error handling, so of course there's no feature for BetterC dedicated to error handling.

Being a better C is the one and only focus of Zig. So it has features for doing error handling without exceptions.

D is not going to replace C, perhaps for the same reasons subsets of C++ didn't.

I don't know if Zig and Rust will. But there's a better chance since they actually bring a lot of stuff to the table that arguably make them better at being a C-like language than C. I am really hyped to see how embedded development will be in Zig after the new IO interface lands.

cma256 3 days ago|||
He doesn't have to, he _gets_ to! Its knowledge exchange. Take it as a gift and not self-promotion. There's no money in this game so don't treat it like guerilla marketing. Treat it like excited people pushing the limits of technology.
cyber_kinetist 3 days ago||||
I think the history of D having a garbage collector (and arguably exceptions / RTTI) from the beginning really cemented its fate. We all know that there's a "BetterC" mode that turns it off - but because the D ecosystem initially started with the GC-ed runtime, most of the D code written so far (including most of the standard library) isn't compatible with this at all.

If D really wants to compete with others for a "better C replacement", I think the language might need some kind of big overhaul (a re-launch?). It's evident that there's a smaller, more beautiful language that can potentially be born from D, but in order for this language to succeed it needs to trim down all the baggage that comes from its GC-managed past. I think the best place to start is to properly remove GC / exception handling / RTTI from the languge cleanly, rewrite the standard library to work with BetterC mode, and probably also change the name to something else (needs a re-brand...)

ksec 2 days ago||||
>Do you have to bring up D in every Zig related post?

I dont think that is the case here, and in all previous encounter. I see this every time Ada was mentioned in Rust as well.

He is not brining up about D in every Zig post, he is simply replying whenever people said something about only in Zig, he is replying that D could do it as well. Which is fair.

Same with Ada, when Rust people claim to be the only language doing something, or the safest programming languages, there is nothing wrong in providing a valid, often missed out counter argument.

A subset of D could have been better C, or "Das C". Unfortunately I dont see anyone craving that out as a somewhat separate project.

WalterBright 3 days ago||||
My post was not about betterC, it was about the super easy interoperability of C and D. This capability has been in D for several years now, and has been very popular as there's no longer a need to write an adapter to use C source code. The ability to directly compile C code is part of the D compiler, and is known as ImportC.

One interesting result of ImportC is that it is an enhanced implementation of C in that it can do forward references, Compile Time Function Execution, and even imports! (It can also translate C source code to D source code!)

bachmeier 3 days ago||||
This is, like, the most ironic comment ever posted on HN. An article about cat nutrition could hit the front page and the Rust fanbois would hijack the conversation.

In this case, however, Walter was not the one that brought up D. He was replying to a comment by someone promoting Zig with the claim that only Zig and C++ have ever had a strategy to replace C. That is objectively false. There's no way to look at what D does in that area and make that sort of claim. Walter and anyone else is right to challenge false statements.

LexiMax 3 days ago|||
> claim that only Zig and C++ have ever had a strategy to replace C

What I actually said was that it was the second language I have seen to do so at any appreciable scale. I never claimed to know all languages. There was also an implication that I think that even if a language claims to be a C replacement, its ability to do so might exceed its ambition.

That said I also hold no ill will towards Walter Bright, and in fact was hoping that someone like him would hop into the conversation to try and sell people on why their language was also worthy of consideration. I don't even mind the response to Walter's post, because they bring real-world Dlang experience to the table as a rebuttal.

On the other hand, I find it difficult to find value in your post except as a misguided and arguably bad-faith attempt to stir the pot.

mg794613 3 days ago|||
No, he never stated that "claim that only Zig and C++ have ever had a strategy to replace C", you made that up. And "Walter was not the one that brought up D" , he actually was.

Did the text get changed? because it seems you claim exactly the opposite of what is in about ~5 sentences, so it also can't be credited to "misunderstanding".

But didn't find any "D evangelism" comments in his history (first page), but then again, he has 78801 karma points, so I am also not going to put energy in going through his online persona history.

jibal 3 days ago||||
This is a bad comment in so many ways.

Walter's short limited comment was quite relevant.

GoblinSlayer 3 days ago|||
C++ is more C-like than Zig and Rust, so it's more likely to become a C replacement.
LexiMax 3 days ago|||
I do feel like allowing for in-place source upgrading was critical to C++'s early successes. However, I feel like this ultimately worked against C++, since it also wed the language to many of C's warts and footguns.
WalterBright 3 days ago||
C++ cannot seem to let go of the preprocessor, which is an anchor hurting the language at every turn.

BTW, in my C days, I did a lot of clever stuff with the preprocessor. I was very proud of it. One day I decided to replace the clever macros with core C code, and was quite pleased with the clean result.

With D modules, imports, static if, manifest constants, and templates the macro processor can be put on the ash heap of history. Why doesn't C++ deprecate cpp?

bnolsen 1 day ago|||
Except for all the baggage it carries along with it including hacks to address baggage resulting in a very bloated language.
WhereIsTheTruth 3 days ago||||
This is the smart choice

You keep compatibility with C, can tap into its ecosystem, but you are no longer stuck with outdated tooling

D gives you faster iteration, clearer diagnostics, and a generally smoother experience, even if it doesn't go as far as Rust in terms of safety

I wish more languages would follow this strategy, ImportC is great, let's you port things one step at a time, if required/needed

Let's be honest: who wants to write or generate C bindings? And who wants to risk porting robust/tested/maintained C code incorrectly?

WalterBright 3 days ago||
> who wants to write or generate C bindings?

Not me, and not anyone else. Many D users have commented on how ImportC eliminates the tedium of interfacing to me.

And with D, you don't have to write .h interface files, either (although you can, but it turns out pretty much nobody bothers to).

AndyKelley 3 days ago||||
I've always admired your work, Walter. Keep it up!
WalterBright 3 days ago||
Thank you for the kind words, Andy!
LexiMax 3 days ago|||
> C-source to D-source translation.

I'm not so familiar with D, what is the state of this sort of feature? Is it a built-in tool, or are you talking about the ctod project I found?

In most languages, I've found that source translation features to be woefully lacking and almost always require human intervention. By contrast, it feels like Zig's `translate-c` goes the extra mile in trying to convert the source to something that Zig can work with as-is. It does this by making use of language features and compiler built-ins that are rather rare to see outside of `translate-c`.

Obviously the stacks of @as, @fooCast, and @truncate you are left with isn't idiomatic Zig, but I find it easier to start with working, yet non-idiomatic code than 90% working code that merely underwent a syntactic change.

WalterBright 3 days ago||
It's hardwired into the D compiler binary. It will even translate C macros into D code!

Well, most macros. The macros that do metaprogramming are not translatable. I read that Zig's translator has the same issue, which is hardly surprising since it is not possible.

So, yes, the translation is not perfect. But the result works out of the box most of the time, and what doesn't translate is easily fixed by a human. Another issue is every C compiler has their own wacky extensions, so it is impractical to deal with all those variants. We try to hit the common extensions, though.

If you just want to call C code, you don't have to translate it. The D compiler recognizes C files and will run its very own internal C compiler (ImportC) to compile it. As a bonus, the C code can use data structures and call functions written in D! The compatibility goes both ways.

tiffanyh 4 days ago||
Does this mean long term Zig won’t run on OpenBSD?

Because doesn’t OpenBSD block direct syscalls & force everything to go through libc.

https://news.ycombinator.com/item?id=38039689

AndyKelley 4 days ago||
This affects static libc only. If you pass -dynamic -lc then the libc functions are provided by the target system. Some systems only support dynamic libc, such as macOS. I think OpenBSD actually does support static libc though.
winterqt 4 days ago||
> I think OpenBSD actually does support static libc though.

How does that work, with syscalls being unable to be called except from the system’s libc? I’d be a bit surprised if any binary’s embedded libc would support this model.

mananaysiempre 4 days ago|||
For static executables, “the system’s libc” is of course not a thing. To support those, OpenBSD requires them to include an exhaustive list of all addresses of syscall instructions in a predefined place[1].

(With that said, OpenBSD promises no stability if you choose to bypass libc. What it promises instead is that it will change things in incompatible ways that will hurt. It’s up to you whether the pain that thus results from supporting OpenBSD is worth it.)

[1] https://nullprogram.com/blog/2025/03/06/

oguz-ismail2 4 days ago||||
> How does that work, with syscalls being unable to be called except from the system’s libc?

OpenBSD allows system calls being made from shared libraries whose names start with `libc.so.' and all static binaries, as long as they include an `openbsd.syscalls' section listing call sites.

GoblinSlayer 3 days ago||
Can't you just have one syscall(2) to rule them all? https://man7.org/linux/man-pages/man2/syscall.2.html
oguz-ismail2 3 days ago||
You can. There is a thread-unsafe implementation here <https://gist.github.com/oguz-ismail/72e34550af13e3841ed58e29...>. But the listing needs to be per system call number, so this one only supports system calls 1 (_exit) and 4 (write). It should be fairly easy to automatically generate the complete list but I didn't try it.
AndyKelley 4 days ago||||
Sorry I got mixed up with FreeBSD: https://codeberg.org/ziglang/zig/issues/30981 (original github link has more information)
pretendgeneer 4 days ago|||
Not all of libc is syscalls. E.g. strlen() is zib libc but open() goes to system libc.
tialaramex 3 days ago||
Good point. C's "freestanding" mode, analogous to Rust's nostd, does not provide any functions at all, just some type definitions and constants which obviously evaporate when compiled. Rust's nostd not only can compute how long a string is, it can unstably sort a slice, do atomic operations if they exist on your hardware, lots of fancy stuff but as a consequence even nostd has an actual library of code, a similar but maybe less organized situation occurs in C++. Most of the time this is simply better, why hand write your own crap sort when your compiler vendor can just provide an optimised sort for your platform? But on very, very tiny systems this might be unaffordable.

Anyway, C doesn't have Rust's core versus std distinction and so libc is a muddle of both the "Just useful library stuff" like strlen or qsort and features like open which are bound to the operating system specifics.

actionfromafar 4 days ago||
https://news.ycombinator.com/reply?id=46864849&goto=item%3Fi...
generichuman 4 days ago||
This is very exciting for zig projects linking C libraries. Though I'm curious about the following case:

Let's say I'm building a C program targeting Windows with MinGW & only using Zig as a cross compiler. Is there a way to still statically link MinGW's libc implementation or does this mean that's going away and I can only statically link ziglibc even if it looks like MinGW from the outside?

AndyKelley 4 days ago|
This use case is unchanged.

If you specify -target x86_64-windows-gnu -lc then some libc functions are provided by Zig, some are provided by vendored mingw-w64 C files, and you don't need mingw-w64 installed separately; Zig provides everything.

You can still pass --libc libc.txt to link against an externally provided libc, such as a separate mingw-w64 installation you have lying around, or even your own libc installation if you want to mess around with that.

Both situations unchanged.

generichuman 4 days ago|||
That's cool. I imagine I could also maintain a MinGW package that can be downloaded through the Zig package manager and statically linked without involving the zig libc? (Such that the user doesn't need to install anything but zig)

That's a good way to sell moving over to the zig build system, and eventually zig the language itself in some real-world scenarios imo.

dnautics 4 days ago|||
do you suspect it will be possible to implement printf??

while we're talking about printf, can i incept in you the idea of making an io.printf function that does print-then-flush?

Cloudef 4 days ago||
It's completely possible to implement printf. here is my impl (not 100% correct yet) of snprintf for my custom libc implemented on top of a platform I'm working on <https://zigbin.io/ab1e79> The va_arg stuff are extern because zig's va arg stuff is pretty broken at the moment. Here's a C++ game ported to web using said libc running on top of the custom platform and web frontend that implements the platform ABI <https://cloudef.pw/sorvi/#supertux.sorvi> (you might need javascript.options.wasm_js_promise_integration enabled if using firefox based browser)
dnautics 3 days ago||
yeah I just thought there are "compiler shenanigans" involved with printf! zig's va arg being broken is sad, I am so zig-pilled, I wish we could just call extern "C" functions with a tuple in place of va arg =D
Cloudef 3 days ago||
The only thing C compilers do for printf, is static analyze the format string for API usage errors. Afaik such isn't possible in zig currently. But idk why'd you downgrade yourself to using the printf interface, when std.Io.Writer has a `print` interface where fmt is comptime and args can be reflected so it catches errors without special compiler shenigans.
dnautics 3 days ago||
I'm thinking: do a translate-c and then statically catch errors using my zig-clr tool.
mastermage 3 days ago||
That just reminds me anyone know whether rust has something similar? Not wanting to start any Rust v. Zig debate. I am just wanting to be even more independant when it comes to some of my Rust projects.
erk__ 3 days ago|
There is a couple libc implementations:

- c-ward [0] a libc implementation in Rust

- relibc [1] a libc implementation in Rust mainly for use in the Redox os (but works with linux as well)

- rustix [2] safe bindings to posix apis without using C

[0]: https://github.com/sunfishcode/c-ward

[1]: https://gitlab.redox-os.org/redox-os/relibc/

[2]: https://github.com/bytecodealliance/rustix

jzelinskie 4 days ago||
Cool idea, for sure, but I can't help but wonder: for the code that's been ported, is there a concern that you'd have to perpetually watch out for CVEs in glibc/musl and determine if they also apply to the Zig implementations?
AndyKelley 4 days ago|
Yes but we already have to do that for our own standard library. For shared codepaths (e.g. math) it's strictly fewer potential bugs.
meisel 4 days ago||
> It’s kind of like enabling LTO (Link-Time Optimization) across the libc boundary, except it’s done properly in the frontend instead of too late, in the linker

Why is the linker too late? Is Zig able to do optimizations in the frontend that, e.g., a linker working with LLVM IR is not?

ibejoeb 4 days ago|
Seems like it ought to be able to do inlining and dead code stripping which, I think, wouldn't be viable at link time against optimized static libraries.
comex 4 days ago||
It is viable against the IR that static libraries contain when LTO is enabled.

LTO essentially means “load the entire compiler backend into the linker and do half of the compilation work at link time”.

It’s a great big hack, but it does work.

ibejoeb 4 days ago|||
Right, but I think that's what the question of "Why is the linker too late?" is getting at. With zig libc, the compiler can do it, so you don't need fat objects and all that.

---

expanding: so, this means that you can do cross-boundary optimizations without LTO and with pre-built artifacts. I think.

DannyBee 3 days ago||
Calling this "properly" is a stretch at best.

I will say first that C libc does this - the functions are inline defined in header files, but this is mainly a pre-LTO artifact.

Otherwise it has no particular advantage other than disk space, it's the equivalent of just catting all your source files together and compiling that. If you thikn it's better to do in the frontend, cool, you could make it so all the code gets seen by the frontend by fake compiling all the stuff, writing the original source to an object file special section, and then make the linker really call the frontend with all those special sections.

You can even do it without the linker if you want.

Now you have all the code in the frontend if that's what you want (I have no idea why you'd want this).

It has the disadvantage that it's the equivalent of this, without choice.

If you look far enough back, lots of C/C++ projects used to do this kind of thing when they needed performance in the days before LTO, or they just shoved the function definitions in header files, but stopped because it has a huge forced memory and compilation speed footprint.

Then we moved to precompiled headers to fix the latter, then LTO to fix the former and the latter.

Everything old is new again.

In the end, you are also much better off improving the ability to take lots of random object files with IR and make it optimize well than trying to ensure that all possible source code will be present to the frontend for a single compile. Lots of languages and compilers went down this path and it just doesn't work in practice for real users.

So doing stuff in the linker (and it's not really the linker, the linker is just calling the compiler with the code, whether that compiler is a library or a separate executable) is not a hack, it's the best compilation strategy you can realistically use, because the latter is essentially a dream land where nobody has third party libraries they link or subprojects that are libraries or multiple compilation processes and ....

Zig always seems to do this thing in blog posts and elsewhere where they add these remarks that often imply there is only one true way of doing it right and they are doing it. It often comes off as immature and honestly a turnoff from wanting to use it for real.

pjmlp 3 days ago||
Yeah, like their solutions to detecting use after free are hardly any different from using something like PurifyPlus.
gary_0 4 days ago||||
As I understand it, compiling each source file separately and linking together the result was historically kind of a hack too, or at least a compromise, because early unix machines didn't have enough memory to compile the whole program at once (or even just hold multiple source files in memory at a time). Although later on, doing it this way did allow for faster recompilation because you didn't need to re-ingest source files that hadn't been changed (although this stopped being true for template-heavy C++ code).
account42 3 days ago|||
It's hardly a hack when its how most languages work in the first place.
nesarkvechnep 4 days ago||
"Furthermore, when this work is combined with the recent std.Io changes, there is potential for users to seamlessly control how libc performs I/O - for example forcing all calls to read and write to participate in an io_uring event loop"

This is exciting! I particularly care more about kqueue but I guess the quote applies to it too.

anitil 4 days ago||
There are so many scary parts of libc, this is a really exciting project
LarsKrimi 4 days ago|
There are many useful functions too. Like "memfrob" and "strfry". I hope the Zig libc makes those available too

Just joking of course. Those are sadly only in glibc.. :)

voidUpdate 3 days ago||
Does anyone know if there is a timeline on when Zig might achieve 1.0? I've been interested in the language for a while, but I'm a bit concerned about writing anything important in it when it seems to be evolving so much at the moment
Zambyte 3 days ago||
Nobody knows, but for what it's worth, existing large projects that are used in production environments have been fairly good at keeping up with Zig releases. See: Bun, Ghostty, and Tigerbeetle for good examples of this. Because the semantics of Zig are relatively simple, porting to the latest version is usually as simple as bumping your compiler version, trying to build, making a fairly mindless, mechanical change, and repeating until it builds.

The biggest thing holding me back from using Zig for important projects is the willingness of my peers to adopt it, but I'm just building projects that I can build myself until they are convinced :)

jibal 3 days ago||
There's no timeline for 1.0

You might find this interesting: https://www.youtube.com/watch?v=x3hOiOcbgeA

squirrellous 4 days ago|
I’m sure this has crossed someone’s mind but why isn’t this called zlibc? :-)
lioeters 4 days ago||
I rather like "libz".
bnolsen 1 day ago||
Not to be confused with zlib.
kibibu 4 days ago|||
Perhaps to avoid confusion with zlib?

https://www.zlib.net/

account42 3 days ago||
Well we also have glib and glibc.
More comments...