# The Future of Rust Without Libc?

**URL:** <https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423>\
**Category:** help\
**Created:** [May 11, 2025, 9:13pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423 "2025-05-11T21:13:15Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![esnfps](https://avatars.discourse-cdn.com/v4/letter/e/d07c76/32.png) [@esnfps](https://users.rust-lang.org/u/esnfps)\
**Post date:** [May 11, 2025, 9:13pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/1 "2025-05-11T21:13:15Z")

</div>

Are/were they any attempts to have Rust's std free of c dependency, something like zig?

I’ve seen some interesting examples, including:

> **[GitHub - bytecodealliance/rustix: Safe Rust bindings to POSIX-ish APIs](https://github.com/bytecodealliance/rustix)**
>
> Safe Rust bindings to POSIX-ish APIs

Is there hope that the Rust standard library will be entirely free of any dependency on libc in the future?

---

<div class="post-metadata">

**Author:** ![nerditation](https://avatars.discourse-cdn.com/v4/letter/n/e79b87/32.png) [@nerditation](https://users.rust-lang.org/u/nerditation)\
**Post date:** [May 12, 2025, 12:31am UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/2 "2025-05-12T00:31:36Z")

</div>

> [@esnfps](#):
>
> ... free of any dependency on libc ...

I don't understand the point. this is just not what rust is aiming for.

for one, rust doesn't have a runtime, it is not that kind of (sometimes referred to as "batteries-included") language that provides "everything" you need to write your (cross-platform) application, like java, python, etc. rust brands itself as a "system" language, and it is intended to be seaminglessly interopable with the operating system and native libraries through ffi.

although people _love_ to "rewrite" FOOBAR in rust, the rust ecosystem consistes of large portion of "bindings", and practically, any non-trivial application would inevitably have dependencies on some native libraries, so your app end up linking against `libc` anyway, what's the point of "getting rid of" `libc` for the rust part?

for another, the language itself doesn't need `libc` at all, you can even implement your own `libc` in rust (although some features needs nightly rust for now, notably, varadic functions). it's the `std` crate that has a dependency on `libc`, we all know rust can support many target architecture platforms, though many of them are `#![no_std]` only.

removing the `libc` dependency from `std` just means we need to re-implement the features of `libc` in `std`, it's not just re-inventing the wheels, it's also throwing away already existing good wheels for no benefits whatsoever.

what's more, `libc` **is** the syscall "stub" library for posix systems. linux is the only exception to have a stable syscall ABI because the kernel and userland are maintained by separate groups of people. all other systems, posix-like or not, have **no** stable syscall ABI guarantees at all, the only supported way to call the kernel is through some userland stub library, such as `ntdll.dll` for Windows, `libSystem.dylib` for Macos, and for posix systems, it's just `libc.so` --- it's just linux also provides stable syscall guarentee _in addition to_ `libc`s (plural because there exist different `libc` implementations).

even the "redox" operating system, which is written in rust, has a `libc`, called [`relibc`](https://gitlab.redox-os.org/redox-os/relibc), and in what language is it written? you guessed it, rust!

the convention to call the system interfacing library `libc` is for historical reasons: it originated from unix, since `C` is originally just for unix. the C lauguage is eventually adapted by everyone and standardized, and in the standard, the supporting library is called the (C) standard library, **not** referenced as `libc` officially. but informally, people would usually use the term "C standard library", "C runtime library", and "libc", interchangably. though depending on context, "libc" may mean different things.

also, for posix systems, the C standard library is typically provided through `libc`, or in other words, `libc` can be seen as a superset of the C standard library on such systems.

also, there's some relevant discussion in [this recent thread](https://users.rust-lang.org/t/why-is-cargo-clean-required-to-get-my-inline-asm-to-work/127717) regarding syscall stability and libc.

---

<div class="post-metadata">

**Author:** ![Karl-Goethebier](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/karl-goethebier/32/43481_2.png) [@Karl-Goethebier](https://users.rust-lang.org/u/Karl-Goethebier)\
**Post date:** [May 12, 2025, 8:27am UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/3 "2025-05-12T08:27:43Z")

</div>

> [@nerditation](#):
>
> rust doesn't have a runtime

Then it is probably the only language that just has a manual page about “Runtime”:

> You may have heard the claim that Rust doesn’t have a runtime. While that’s true at a high level—it doesn’t have a garbage collector, an interpreter, or a built-in user-level scheduler—it’s not really true in the strictest sense. Specifically, Rust does have some special code that runs before your main function and in response to certain special conditions in your code, which really is a form of bare-bones runtime. (from [Rust for Rustaceans](https://rust-for-rustaceans.com/), page 215

---

<div class="post-metadata">

**Author:** ![ZiCog](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/zicog/32/12216_2.png) [@ZiCog](https://users.rust-lang.org/u/ZiCog)\
**Post date:** [May 12, 2025, 9:00am UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/4 "2025-05-12T09:00:26Z")

</div>

Yeah, we can quibble about the definition of "run-time". And I will..

Sure there is code that gets run before main(). Setting up the stack and initialising static data etc. C, C++ and many others have that too. And it may have bits of code tied to panics or whatever. I'm not prepared to call that a run time in the sense used in Javascript, Python, Java and other such languages. None of it is being run as the code you wrote runs. Ergo not "run time". Correct me if I'm wrong here.

---

<div class="post-metadata">

**Author:** ![newpavlov](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/newpavlov/32/6207_2.png) [@newpavlov](https://users.rust-lang.org/u/newpavlov)\
**Post date:** [May 12, 2025, 9:27am UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/5 "2025-05-12T09:27:43Z")

</div>

I think you are looking for this issue:

> <https://github.com/rust-lang/rfcs/issues/2610>
>
> e.g. \`x86\_64-linux\` (or \`x86\_64-unknown-linux-rust\`).
> 
> These would be the spir…itual successor of \[steed\]: a standard library, free of C dependencies, for Linux systems. Steed implemented (or planned to) the Rust standard library using raw Linux system calls instead of libc's API. These libc-less targets would also implement \`std\` using raw system calls.
> 
> \[steed\]: https://github.com/japaric/steed
> 
> Even though steed has been inactive for over a year people continue to star it on GitHub and currently has over 500 stars so it seems there's still interest for something like it.
> 
> What we learned during development is that maintaining a standard library out of tree is a lot of work because things get quickly out sync so if there's still interest for something like steed I would recommend writing an RFC to add support for libc-less targets (e.g. \`x86\_64-linux\`) to rust-lang/rust; this would be equivalent to importing and developing steed as part of rust-lang/rust.
> 
> An RFC is also a good way to (re-)evaluate the ROI of making a libc-less standard library. One of the goals of steed was hassle-free cross compilation but today that's solved by the Linux/MUSL targets + \`rust-lld\` (works on stable). The other goal was better optimizations (plain LTO doesn't optimize across FFI) but cross-language LTO is a now thing (\`-Z cross-lang-lto\`). There may be less costly ways to achieve the same results.
> 
> The rest of this post describes the status of steed as of 2017-10-20 (date of last commit).
> 
> What we had working:
> 
> 1. standard I/O (\`std::io::{stdin,stderr,stdout}\`)
> 2. filesystem operations (\`std::fs\`)
> 3. collections (\`std::collections\`) (but see (a) below)
> 4. \`std::sync::Mutex\` (courtesy of \`parking\_lot\`)
> 5. \`std::env\`
> 6. UDP and TCP sockets (\`std::net\`) (but see (d) below)
> 7. minimal support for threads and TLS
> 8. \`#\[test\]\` support (but see (c) below)
> 
> You can check the \[examples directory\] to get an idea of what you could write with it.
> 
> \[examples directory\]: https://github.com/japaric/steed/tree/23882a1c408b922c132e9d00f0a61c4c9002c2d8/examples
> 
> What was missing:
> 
> a. a proper allocator. steed used a bump pointer allocator that never freed memory
> b. all the math stuff (e.g. \`f32::sin\`). These days one can use \[\`libm\`\].
> c. unwinding, all the steed targets used \`-C panic=abort\`
> d. hostname lookup
> e. \`errno\`. It was unclear whether we should implement it or not. It seems to only be required by \`std::io::Error::last\_os\_error\`. Linux system calls have a \`Result\`-like API so \`errno\` is not required to propagate errors from syscalls to the \`std\` API.
> 
> and much more stuff; you can check \[the issue tracker\] for the full list.
> 
> \[\`libm\`\]: https://github.com/rust-lang-nursery/libm
> \[the issue tracker\]: https://github.com/japaric/steed/issues
> 
> \---
> 
> cc @tbu- @briansmith

I would **love** for this to be implemented, but the issue is almost 7 years old and there is disappointingly little work on it. Amusingly (in a bad way), even the green-field WASI target [depends](https://internals.rust-lang.org/t/10836) on libc by default (in a MUSL-like fashion) and there is no alternative to it.

---

<div class="post-metadata">

**Author:** ![Karl-Goethebier](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/karl-goethebier/32/43481_2.png) [@Karl-Goethebier](https://users.rust-lang.org/u/Karl-Goethebier)\
**Post date:** [May 12, 2025, 9:31am UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/6 "2025-05-12T09:31:18Z")

</div>

> Show me yours, I’ll show you mine ([Jill Lepore](https://en.wikipedia.org/wiki/Jill_Lepore) on arguments)

Facts:

> Every programming language specifies an execution model, and many implement at least part of that model in a runtime system. One possible definition of runtime system behavior, among others, is "any behavior not directly attributable to the program itself". This definition includes putting parameters onto the stack before function calls, parallel execution of related behaviors, and disk I/O.

> By this definition, essentially every language has a runtime system, including compiled languages, interpreted languages, and embedded domain-specific languages. Even API-invoked standalone execution models, such as Pthreads(POSIX threads), have a runtime system that implements the execution model's behavior.

From [Runtime System](https://en.wikipedia.org/wiki/Runtime_system)

---

<div class="post-metadata">

**Author:** ![ZiCog](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/zicog/32/12216_2.png) [@ZiCog](https://users.rust-lang.org/u/ZiCog)\
**Post date:** [May 12, 2025, 11:06am UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/7 "2025-05-12T11:06:46Z")

</div>

> [@Karl-Goethebier](#):
>
> Facts:

Not really. Just one persons definition of what turns out to be a very fuzzy idea of "run time".

For example I think it's absurd to say that the way a compiler arranges to push parameters onto the stack before function calls is a "run-time". I can do the exact same thing in assembler. Where is the run time then? Just because I get a compiler to write that for me does not introduce a run time.

But sticking to what is stated in that definition, where is the "behaviour of my Rust code that is not directly attributable to the program itself" ?

Sure there is behaviour in libraries that does not appear in my source. Sure there is behaviour in the OS sys calls I make that does not appear in my source.

They are not in the Rust language itself. There is no run time in Rust.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/kornel/32/4823_2.png) [@kornel](https://users.rust-lang.org/u/kornel)\
**Post date:** [May 13, 2025, 3:14pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/8 "2025-05-13T15:14:50Z")

</div>

It would be nice to have it as a MUSL alternative on Linux.

However, many other operating systems don't have such a direct stable kernel API, and don't allow bypassing `libc` or its equivalent (MSVCRT, libSystem, etc.).

Go tried not to use libc at all, and had ran into compatibility issues ([1](https://go.dev/doc/go1.5#net), [2](http://garrett.damore.org/2015/09/on-go-portability-and-system-interfaces.html)).

---

<div class="post-metadata">

**Author:** ![khimru](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/khimru/32/31344_2.png) [@khimru](https://users.rust-lang.org/u/khimru)\
**Post date:** [May 13, 2025, 3:27pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/9 "2025-05-13T15:27:03Z")

</div>

> [@kornel](#):
>
> MSVCRT

I think you meant NTDLL.DLL. It's a library that's providing Win32 API to applications and, notably, it doesn't include libc, it's literally a thin wrapper around syscalls, not too much different from Linux's [vDSO](https://en.wikipedia.org/wiki/VDSO) – except in Linux [vDSO](https://en.wikipedia.org/wiki/VDSO) is optional extra-efficient way to access syscalls while in Windows it's the only way.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/scottmcm/32/4286_2.png) [@scottmcm](https://users.rust-lang.org/u/scottmcm)\
**Post date:** [May 13, 2025, 7:39pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/10 "2025-05-13T19:39:16Z")

</div>

> [@esnfps](#):
>
> Is there hope that the Rust standard library will be entirely free of any dependency on libc in the future?

What's your goal from this? How does std not depending on c make a material difference to you?

Your TCB includes C anyway. It's not practical to get rid of that.

---

<div class="post-metadata">

**Author:** ![simonbuchan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/simonbuchan/32/19939_2.png) [@simonbuchan](https://users.rust-lang.org/u/simonbuchan)\
**Post date:** [May 13, 2025, 9:34pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/11 "2025-05-13T21:34:53Z")

</div>

Directly calling ntdll ("Windows Native API") is not supported or (officially) documented, though. Windows reserves, and has previously used, the right to change the native API.

Since the Linux syscall API is officially documented and supported, the actual comparison would be the publicly documented APIs like kernel32, user32, etc...; the Windows libc equivalents msvcrt and ucrt are implemented on top of these, and indeed Rust does, to my knowledge, directly call to these.

However, as @kornel has said, there's lots of platforms (to some extent including Linux!), where libc is the only actually supported public API, as frustrating as that is.

There's actually quite a few reasons you might not want to use libc, primarily for me the large amount of global in process state that it drags in and applies to seemingly random calls, sometimes differently per platform, sometimes without documentation, mostly without thread safety. At least if you're writing against some specific os syscall you can generally trust some other thread isn't calling setenv() via some other API and toasting you.

Hopefully as some of these platforms notice that there's been another language invented since 1970 they might clean this up, but for now this is still C's world, we're just living in it.

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://users.rust-lang.org/u/Vorpal)\
**Post date:** [May 13, 2025, 9:45pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/12 "2025-05-13T21:45:40Z")

</div>

And yet, even Redox, an OS written in Rust, has libc as its stable API/ABI. (It would be nice if it took the opportunity to make a no-global-state API the stable API, and put a libc emulation layer on top instead.)

It can't avoid it entirely, as it aims for POSIX compatibility.\[1\] But it would be nice to make the libc part of POSIX in particular an emulation layer on top in cases where there is a saner API (errno, I'm looking at you).

* * *

1. If _I_ made a clean slate OS I would probably be looking at Midori for inspiration instead. Async first and async everything would be pretty neat. I wouldn't be doing managed code like Midori, so you would still end up with process barriers though. But I think building an OS on a queue similar to io-uring as the core primitive would be interesting. Almost no blocking syscalls. Fuschia would also be interesting as a source of inspiration.

---

<div class="post-metadata">

**Author:** ![khimru](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/khimru/32/31344_2.png) [@khimru](https://users.rust-lang.org/u/khimru)\
**Post date:** [May 13, 2025, 9:52pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/13 "2025-05-13T21:52:47Z")

</div>

> [@simonbuchan](#):
>
> Directly calling ntdll ("Windows Native API") is not supported or (officially) documented, though. Windows reserves, and has previously used, the right to change the native API.

Who told you that? Sure, normally you want to call something like [OpenFile](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-openfile) from kernel32.dll, to be portable and support Windows 9X and Windows CE, but [NtOpenFile](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile) is also perfectly documented and stable.

The fact that your program wouldn't support Windows 9X or Windows CE is probably not a big deal in a modern world with both OSes being well and truly dead.

---

<div class="post-metadata">

**Author:** ![simonbuchan](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/simonbuchan/32/19939_2.png) [@simonbuchan](https://users.rust-lang.org/u/simonbuchan)\
**Post date:** [May 13, 2025, 10:07pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/14 "2025-05-13T22:07:33Z")

</div>

There's a small handful of APIs (nowhere near enough to use as a platform API) that have effectively "leaked out" into the public API for various reasons, yes. Those are fine to use, technically, though they are generally identical to the actual public API and don't have a link library so there's really no legitimate reason to use them, especially since you already have to use kernel32 to even load it in.

---

<div class="post-metadata">

**Author:** ![system](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/system/32/51372_2.png) [@system](https://users.rust-lang.org/u/system)\
**Post date:** [August 11, 2025, 10:08pm UTC](https://users.rust-lang.org/t/the-future-of-rust-without-libc/129423/15 "2025-08-11T22:08:19Z")

</div>

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.
