Bringing Rust back to Genode
Initial support for the Rust programming language was contributed to Genode release 16.05 by Waylon Cude, but it failed to get traction and was removed again with release 20.05. With the 23.05 release, we bring back Rust support from a different angle.
Contrary to the first iteration that focussed on low-level runtime library support and integration into the Genode build system, our objective this time was to facilitate using the existing Rust ecosystem in Genode. Specifically, the integration effort was guided by the following:
Make use of the native build system, cargo, to make the existing ecosystem accessible.
Aim for a seamless integration into the Genode OS Framework using the Goa build tool.
Instead of introducing our own Genode target triples, leverage Genode's FreeBSD based C library interface to use existing supported standard library targets.
Strive to use the upstream toolchain, or at least stay as close to upstream as possible.
While our approach proved fairly practical, we had to sidestep a few problems in the initial proof of concept implementation.
The naïve approach of just linking the pre-compiled x86_64-unknown-freebsd Rust std library target against Genode's FreeBSD libc port got surprisingly far. After adding the signal(3) interface and a few dummy implementations, the remaining issue turned out to be that due to an API change in FreeBSD 12, the libc crate links to a versioned symbol in order to use the original interface. The upcoming API raise to FreeBSD 12 will eliminate this particular issue, but versioned symbols have been introduced elsewhere due to other API changes.
In order to investigate the feasibility of the general approach and get a working prototype running, we decided to build a toolchain with a custom libc crate that already incorporates the API bump to FreeBSD 12. With the local libc crate and a few configuration settings, the only remaining piece of the puzzle was a little wrapper that provides a few linking fixes for the toolchain bootstrap process, which would otherwise be handled by goa.
We provide a pre-compiled Rust toolchain to try out here: https://genode.org/files/rust-genode-23.05.tar.xz (sha256sum c8a82f35f4a69e6102223c82ed404bcbe65b3241fa53ec785a1a64faaba85f01).
To make use of it on x86_64 Linux, first install Rust's rustup toolchain manager by a method of your choosing and follow the instructions:
$ rustup toolchain install stable-x86_64-unknown-linux-gnu $ wget https://genode.org/files/rust-genode-23.05.tar.xz $ sha256sum rust-genode-23.05.tar.xz $ tar xvf rust-genode-23.05.tar.xz -C path/to/dir $ rustup toolchain link rust-genode path/to/dir/rust-genode-23.05 $ rustup default rust-genode
In case you're wondering, we need the stable toolchain to provide the standard tools such as cargo. If you don't have it already, please also follow the instructions to install Genode's toolchain.
Since precompiled packages are only provided at Sculpt releases, next you will need to build the required runtime packages so they feature the necessary libc extensions. For this, please follow the Getting started instructions to get a working Genode build environment. Once you have a working development environment at path/to/genode, please do the following:
path/to/genode $ ./tool/depot/create FORCE=1 REBUILD= UPDATE_VERSIONS=1 \ genodelabs/bin/x86_64/vfs genodelabs/bin/x86_64/posix \ genodelabs/bin/x86_64/init genodelabs/bin/x86_64/libc \ genodelabs/bin/x86_64/base-linux
With the toolchains and the necessary packages in place, it's time to try out Goa's Rust support:
$ git clone https://github.com/genodelabs/goa $ cd goa goa $ export PATH="$PATH:$(pwd)/bin" goa $ goa run -C examples/hello_rust --versions-from-genode-dir path/to/genode \ --depot-dir path/to/genode/depot
If all goes well, this should print Hello Genode Rust world!
With the proof of concept in place, we want to explore a number of improvements on the status quo:
Our first steps make us confident that we might be able to make our Rust support work without a custom toolchain. For that, we are exploring two directions:
Extend our linker to support versioned symbols. As our lack of support for support versioned symbols currently is the only reason for a custom toolchain, we might be able to use Rust's packaged FreeBSD std library unmodified. This would double as a proof of the ABI compatibility of our POSIX interface. On the other hand, in the long run we might into other differences between FreeBSD and our runtime, such as thread local storage, that may make this direction unfeasible long-term.
Compile the std library parts from source along with the target project. We have already looked into building a custom std library via -Z build-std, but so far have been unsuccessful in making the required freebsd12 configuration flag for the libc crate work. The advantage of this approach is that we would be able to adapt to future differences without having to outright provide a custom toolchain.
Making a commonly used Rust-based tool work on Genode will deepen our faith in the Rust port and - last but not least - showcase the use of the Rust ecosystem for end users. We aim to have a first popular software project running on Genode with the next release.
Once Rust has proven itself on top of our POSIX runtime, we can start exploring its feasibility in our native OS Framework. For now this is more a moonshot goal than a near term priority, but we hope that the present work will provide a starting point for any commercial interest and I would be excited to see what can be archived with two of my favorite pieces of software working together.
This article was amended on 2023-05-31 to fix incomplete build instructions. I apologize for the inconvenience.