Closed jcsoo closed 5 years ago
Finally I'd like to include Yocto and Buildroot which are tools that allow you to build customized Linux installations.
The meta-rust seems to be related to this but I'm not familiar with Yocto or Buildroot.
OpenWrt and Android just need the appropriate targets for cross compilation.
There's an issue about this: #4
re: OpenWRT. Some time ago it was reported to me that Rust programs are too big to fit in a typical OpenWRT device and that proper support for dynamic linking would solve the problem. So, I've opened #5 to discuss that.
However Buildroot in particular seems like a prime target that could use some tooling on the Rust side
Could you elaborate on that? With tooling, are you referring to rustc
, cargo
and/or rustbuild
?
The meta-rust seems to be related to this but I'm not familiar with Yocto or Buildroot.
Interesting, I will take a look.
Could you elaborate on that? With tooling, are you referring to rustc, cargo and/or rustbuild?
I was thinking along the lines of a cargo subcommand that could do the proper cross-compiling for the target including non-rust dependencies (a big challenge, I think) and then use Buildroot to package everything along with a custom kernel into a bootable image. So hypothetically:
cargo install rust-buildroot
git clone <rust-buildroot-demo-repo> demo
cd demo
cargo buildroot --template rpi3-debian-latest --output /dev/rdisk4
to go from a bare Rust install to a bootable SD card with Rust code running as /sbin/init.
I don't know if any changes are needed to existing Rust tooling to make this happen, but I may start experimenting on the Buildroot side to see how far we can get.
A build.rs
and the gcc
crate will help with cross-compiling non-Rust dependencies.
I was thinking along the lines of a cargo subcommand that could do the proper cross-compiling for the target including non-rust dependencies (a big challenge, I think)
From my vague undestanding of what buildroot does. The easiest way would be to integrate Cargo itself into buildroot. AFAIK, buildroot will build a cross toolchain and cross compile a sysroot for the target device. So, in principle, to make Cargo use this custom sysroot and toolchain instead of the system ones we only have to change the linker Cargo uses. This means buildroot just has to e.g. set the CARGO_TARGET_MIPS_UNKNOWN_LINUX_MUSL_LINKER
env variable when it calls Cargo. The rest of the buildroot process would be the same, I think.
Rust code running as /sbin/init.
Did anyone write a init
in Rust yet?
A build.rs and the gcc crate will help with cross-compiling non-Rust dependencies.
We probably want to leave compiling C code up to buildroot. The interesting part is that all the Rust dependencies will have to link to "system" (actually, buildroot's) C libraries instead of trying to compile C code themselves. This would require coordination with crate authors to add a Cargo feature that disables compilation of C code (gcc
/build.rs
) to their crates.
Most -sys
crates just link to whatever static/dynamic library is available, rather than build code themselves. But build.rs
and gcc
are good for adding tricky blobs of custom C / asm, which can be especially handy for dealing with odd low level requirements.
The interesting part is that all the Rust dependencies will have to link to "system" (actually, buildroot's) C libraries instead of trying to compile C code themselves. This would require coordination with crate authors to add a Cargo feature that disables compilation of C code (gcc/build.rs) to their crates.
Is there a way to have gcc / build.rs use the buildroot environment, maybe by tweaking the PATH? I assume there are cases where there's custom C that needs to be built (as jdub just pointed out).
There are a lot of parallels with how containers are constructed using Dockerfiles.
Speaking of Docker, it will be nice if we can get all of this packaged up in a Docker image. I'll see if I can find some examples of Buildroot Docker images.
Did anyone write a init in Rust yet?
There's one here though it hasn't been updated since last year.
Simple single-process systems can probably get away without an init if they have a watchdog to reboot if the main process hangs. More complicated systems are likely to want something a bit more sophisticated to do process supervision and some of the other things an init typically does.
I'd love to have a Rust equivalent someday of daemontools or s6.
Is there a way to have gcc / build.rs use the buildroot environment, maybe by tweaking the PATH?
Yes, there are env variables to change the compiler, archiver, etc. that the gcc
crate uses. CC_mips_unknown_linux_musl
, for instance, changes the compiler that the gcc
crate will use to compile C code for the mips-unknown-linux-musl
target.
The meta-rust seems to be related to this but I'm not familiar with Yocto or Buildroot.
The meta-foo
pattern is the standard way of naming "layers" for the Yocto ecosystem. meta-rust
provides tooling for building Rust projects using the Yocto build system.
One important note about meta-rust
is that it compiles its own Rust compiler as part of the build process. This is in-line with the Yocto philosophy, which originally derived from the Gentoo Linux project, and values being able to compile everything from source. This means that meta-rust
does things the "right" way. It also means that meta-rust
tends to be at least a few releases behind on stable Rust, and takes a really, really, time to compile.
I released an alternative/companion to meta-rust
called meta-rust-bin
that uses the pre-compiled binaries from the rust-lang.org
website instead of compiling Rust from source and speeds things up considerably.
As we now have the @rust-embedded/embedded-linux team, I believe we can close this issue.
Marking this for a cleanup sweep. If we would like this to stay open, please provide an update to what this issue should be focused on.
I am closing this issue, please feel free to open another issue if you would like this discussed further.
Since it looks like we're breaking out topics from the Scope PR, here's a place to discuss the various classes of Linux devices and how they might be addressed in embedded-rust.
On one end there is uCLinux for devices without MMUs. I don't know how widely used this or any other similar projects are used, but it doesn't appear to be useful outside the embedded context.
On the other end there are all of the various traditional distros that happen to run on the Pi, BeagleBone and other single-board PCs.
In between are OpenWrt, Android and maybe ChromiumOS which are in between. There's also whatever Microsoft is offering for embedded Windows development - anyone know about that?
Finally I'd like to include Yocto and Buildroot which are tools that allow you to build customized Linux installations.
All of these are being used for embedded devices, but they don't necessarily need the same level of attention. The fuller featured Linux distributions really just need Rust libraries for Linux I/O support, and maybe intermediate ones like OpenWrt and Android just need the appropriate targets for cross compilation.
However Buildroot in particular seems like a prime target that could use some tooling on the Rust side. As motivation I'd like to point out the Nerves Project which is an Elixir (Erlang) toolset which makes it extremely easy to build flashable single-purpose Linux firmware.