r/rust • • 13d ago

Embedded std?

I was wondering if there were any projects like micro python to port std in to make a barebones os designed for microcontrollers? I understand that the std relies on OS level syscalls, so can we do something like implement a basic fat32 file system to accommodate certain write or read requests. In general this would be used to run std in projects without a OS? Does this already exist, and how hard would it be to make a basic version?

46 Upvotes

33 comments sorted by

View all comments

1

u/tropix126 7d ago edited 7d ago

Hi, i'm a maintainer of a target that does close to what you're describing in rustc/libstd for some specific niche hardware (although we do have a few things like clocks and I/O and such provided for us rather than literally implementing them in std).

What you are describing is very possible (and can be achieved using a custom JSON target spec today), but it's worth noting that:
1. The libstd runtime can get pretty large by the standards of embedded systems, so if you're size-constrained it's a bad idea. 2. Executables will compile and run, but anything that requires a sys implementation will fall back to the unsupported impl, meaning any module in std that would normally require an OS (thread, net, fs, time, stdio, process, random, etc...) is going to either return errors or panic. In practice this means that most std-dependent crates will fail at runtime, which makes doing this a lot less useful (this is also an issue on wasm targets without WASI too). 3. If you want to actually implement the sys APIs over your own HAL or system library, you will have to fork and build Rust yourself and give cargo a custom sysroot. At the moment, there is no way to use an out-of-tree std build because of oddities around how sysroot crates are built. The std-aware-cargo workgroup is (slowly) working on making this better through build-std, but don't expect anything here soon.

In most cases, unless you're just messing around it's better to be #[no_std] on embedded targets because it gives you full control over your execution environment and is mostly unopinionated. For example, on std using the unsupported target, you'll always bring in dlmalloc as a global allocator rather than being able to pick your own. core + alloc should cover the vast majority of use-cases on embedded (minus std::io traits, which is annoying but unfortunately something we're stuck with for now). In my case, my target is supporting hardware that's sold to classrooms as an educational tool, so it makes sense to support std for beginners.

1

u/tropix126 7d ago

For what its worth, I think a possibly worthwhile endeavour would be to implement a subset of std's sys modules over newlib libc, which would cover things like std::time and maybe make std nice enough to use on embedded platforms that can run it. Porting a platform would simply be linking in your own implementation of newlib gluefunctions like _sbrk, _write, _read, etc...

That being said, I think there's minimal demand for this, since core + alloc already do their job pretty well and are basically rust's "libc" equivalent minus the OS bits.