diff --git a/doc/doxygen/riot.doxyfile b/doc/doxygen/riot.doxyfile index 9f5c6ff754..6bf18e0536 100644 --- a/doc/doxygen/riot.doxyfile +++ b/doc/doxygen/riot.doxyfile @@ -766,6 +766,7 @@ INPUT = ../../doc.txt \ src/build-system-basics.md \ src/kconfig/kconfig.md \ src/using-cpp.md \ + src/using-rust.md \ src/advanced-build-system-tricks.md \ src/emulators.md \ src/release-cycle.md \ diff --git a/doc/doxygen/src/using-rust.md b/doc/doxygen/src/using-rust.md new file mode 100644 index 0000000000..a9d93fd378 --- /dev/null +++ b/doc/doxygen/src/using-rust.md @@ -0,0 +1,133 @@ +Using Rust in RIOT {#using-rust} +================== + +[TOC] + +On supported CPUs, Rust can be used to develop RIOT applications. +Support is indicated in the `has_rust_target` feature, +and tested for in applications using the Makefile line +`FEATURES_REQUIRED += rust_target`. + +In addition to the regular RIOT build toolchain +and a recent nightly Rust toolchain for the given target, +using this also requires C2Rust with some patches applied to be installed; +see toolchain for installation instructions. +All these are readily available in the [official RIOT docker image], +which gets used by default if `BUILD_IN_DOCKER=1` is set. + +[official RIOT docker image]: https://hub.docker.com/r/riot/riotbuild + +Examples +-------- + +Two examples are provided: + +* ``rust-hello-world`` is minimal in the sense of setup and code complexity; it is the typical Hello World example. + + (Note that it is not necessarily minimal in terms of built size, + as Rust's regular printing infrastructure is more powerful and a bit heavier than your off-the-shelf ``printf``, + which embedded libcs already often trim down). + +* ``rust-gcoap`` is a set of demo CoAP resources + both from the [coap-message-demos] crate (containing platform and library independent examples) + and from the [riot-module-examples] crate (containing RIOT specific examples). + +There are [additional examples] available on GitLab, +maintained in coordination with the riot-wrappers crate. + +[coap-message-demos]: https://gitlab.com/chrysn/coap-message-demos +[riot-module-examples]: https://gitlab.com/etonomy/riot-module-examples +[additional examples]: https://gitlab.com/etonomy/riot-examples/ + +How it works +------------ + +The easy part of the story is that Rust code gets compiled into a static library +which is then linked together with the rest of the RIOT code; +if the main function happens to be implemented in Rust, so it is. + +The **RIOT build system** contains rules and metadata to facilitate building and linking: +it calls `cargo` (Rust's own build system), +sets up paths to work well with out-of-tree builds, +configures the Rust target depending on the board's CPU, +and unpacks the static library into object files to facilitate interaction with XFA. + +The [**riot-sys**] crate translates a selected subset of RIOT's header files for use in Rust; +this happens both using the [bindgen] crate (working from API information in header files) +and [C2Rust] \(translating static inline functions, and with some help from riot-sys, constant preprocessor initializers). +Functions exported by riot-sys are inherently unsafe to use (in Rust's sense of unsafe), +and may be somewhat volatile in their API due to mismatches between RIOT's / C's and Rust's API stability concepts. + +The [**riot-wrappers**] crate creates safe and idiomatic wrappers around the types and functions provided by riot-sys. +Thanks to Rust's strong zero-cost abstractions, these often come at no increased runtime cost. +For example, locking a [riot_wrappers::mutex::Mutex] can rely on it having been properly initialized at creation; +furthermore, the mutex is freed when it goes out of scope. + +Where practical, the wrappers are not accessed through own methods +but through established platform independent traits. +For example, the main API surface of an [I2CDevice] +is its implementation of the [corresponding embedded-hal I2C traits] for reading and writing. + +The wrapper are [documented together with riot-sys and some of the examples]. + +[**riot-sys**]: https://crates.io/crates/riot-sys +[**riot-wrappers**]: https://crates.io/crates/riot-wrappers +[bindgen]: https://crates.io/crates/bindgen +[C2Rust]: https://c2rust.com/ +[riot_wrappers::mutex::Mutex]: https://rustdoc.etonomy.org/riot_wrappers/mutex/struct.Mutex.html +[documented together with riot-sys and some of the examples]: https://rustdoc.etonomy.org/riot_wrappers/mutex/struct.Mutex.html +[I2CDevice]: https://rustdoc.etonomy.org/riot_wrappers/i2c/struct.I2CDevice.html +[corresponding embedded-hal I2C traits]: https://rustdoc.etonomy.org/embedded_hal/blocking/i2c/index.html + +Toolchain {#toolchain} +--------- + +To install the necessary Rust components, it is easiest use [**rustup**, installed as described on its website]. + +Using Rust on RIOT requires a nightly version of Rust, +because some transpiled expressions for RIOT make use of unstable features, +and because the RIOT wrappers use some unstable idioms. + +Make sure you have both the nightly **toolchain** +and the core library for the CPU (**target**) of your choice available: + +``` +$ rustup toolchain add nightly +$ rustup target add thumbv7m-none-eabi --toolchain nightly +``` + +(Substitute thumbv7m-none-eavi with the value of `RUST_TARGET` +in the output of `make info-build` of an application that has your current board selected, +or just add it later whenever the Rust compiler complains about not finding the core library for a given target). + + +While Rust comes with its own [cargo] dependency tracker for any Rust code, +it does not attempt to install **system components**. +To avoid playing the whack-a-mole of installing components whenever an install step fails, +consider installing this list of packages on Debian +(or an equivalent list on the distribution of your choice): + +``` +# apt install libclang-dev llvm llvm-dev cmake libssl-dev pkg-config +``` + +This encompass both components needed for riot-sys and for the later installation of C2Rust. + + +Installing **C2Rust** is special because +it can only be built using a particular nightly version +(as explained in its [introduction post]) +and needs some patches applied: + +```shell +$ rustup install nightly-2019-12-05 +$ rustup component add --toolchain nightly-2019-12-05 rustfmt rustc-dev +$ cargo +nightly-2019-12-05 install c2rust +$ git clone https://github.com/chrysn-pull-requests/c2rust -b for-riot +$ cd c2rust +$ cargo +nightly-2019-12-05 install --path c2rust +``` + +[cargo]: https://doc.rust-lang.org/cargo/ +[**rustup**, installed as described on its website]: https://rustup.rs/ +[introduction post]: https://immunant.com/blog/2019/08/introduction-to-c2rust/