Skip to content

Commit 47dec48

Browse files
committed
doc/guides: Introduce Rust Tutorial
fix: update rust in riot to modern port, deprecate old guide fix: update deprecation notice to specify removal date
1 parent 05b965a commit 47dec48

File tree

8 files changed

+556
-255
lines changed

8 files changed

+556
-255
lines changed

doc/doxygen/src/using-rust.md

Lines changed: 2 additions & 255 deletions
Original file line numberDiff line numberDiff line change
@@ -1,258 +1,5 @@
11
Using Rust in RIOT {#using-rust}
22
==================
33

4-
[TOC]
5-
6-
On supported CPUs, Rust can be used to develop RIOT applications.
7-
Support is indicated in the `has_rust_target` feature,
8-
and tested for in applications using the Makefile line
9-
`FEATURES_REQUIRED += rust_target`.
10-
11-
In addition to the regular RIOT build toolchain
12-
and a recent nightly Rust toolchain for the given target,
13-
using this also requires C2Rust with some patches applied to be installed;
14-
see <a href="#toolchain">toolchain</a> for installation instructions.
15-
All these are readily available in the [official RIOT docker image],
16-
which gets used by default if `BUILD_IN_DOCKER=1` is set.
17-
18-
[official RIOT docker image]: https://hub.docker.com/r/riot/riotbuild
19-
20-
Examples
21-
--------
22-
23-
Two examples are provided:
24-
25-
* ``rust-hello-world`` is minimal in the sense of setup and code complexity; it is the typical Hello World example.
26-
27-
(Note that it is not necessarily minimal in terms of built size,
28-
as Rust's regular printing infrastructure is more powerful and a bit heavier than your off-the-shelf ``printf``,
29-
which embedded libcs already often trim down).
30-
31-
* ``rust-gcoap`` is a set of demo CoAP resources
32-
both from the [coap-message-demos] crate (containing platform and library independent examples)
33-
and from the [riot-module-examples] crate (containing RIOT specific examples).
34-
35-
There are [additional examples] available on GitLab,
36-
maintained in coordination with the riot-wrappers crate.
37-
38-
[coap-message-demos]: https://gitlab.com/chrysn/coap-message-demos
39-
[riot-module-examples]: https://gitlab.com/etonomy/riot-module-examples
40-
[additional examples]: https://gitlab.com/etonomy/riot-examples/
41-
42-
IDE / editor setup
43-
------------------
44-
45-
Users of Rust often take advantage of autocompletion or inline help.
46-
To use this on RIOT projects,
47-
some flags and environment variables have to be set,
48-
which are listed by `make info-rust`.
49-
These can be configured in the IDE's project setup
50-
or exported as environment variables.
51-
52-
How it works
53-
------------
54-
55-
The easy part of the story is that Rust code gets compiled into a static library
56-
which is then linked together with the rest of the RIOT code;
57-
if the main function happens to be implemented in Rust, so it is.
58-
59-
The **RIOT build system** contains rules and metadata to facilitate building and linking:
60-
it calls `cargo` (Rust's own build system),
61-
sets up paths to work well with out-of-tree builds,
62-
configures the Rust target depending on the board's CPU,
63-
and unpacks the static library into object files to facilitate interaction with XFA.
64-
65-
The [**riot-sys**] crate translates a selected subset of RIOT's header files for use in Rust;
66-
this happens both using the [bindgen] crate (working from API information in header files)
67-
and [C2Rust] \(translating static inline functions, and with some help from riot-sys, constant preprocessor initializers).
68-
Functions exported by riot-sys are inherently unsafe to use (in Rust's sense of unsafe),
69-
and may be somewhat volatile in their API due to mismatches between RIOT's / C's and Rust's API stability concepts.
70-
71-
The [**riot-wrappers**] crate creates safe and idiomatic wrappers around the types and functions provided by riot-sys.
72-
Thanks to Rust's strong zero-cost abstractions, these often come at no increased runtime cost.
73-
For example, locking a [riot_wrappers::mutex::Mutex] can rely on it having been properly initialized at creation;
74-
furthermore, the mutex is freed when it goes out of scope.
75-
76-
Where practical, the wrappers are not accessed through own methods
77-
but through established platform independent traits.
78-
For example, the main API surface of an [I2CDevice]
79-
is its implementation of the [corresponding embedded-hal I2C traits] for reading and writing.
80-
81-
The wrappers are [documented together with riot-sys and some of the examples].
82-
83-
[**riot-sys**]: https://crates.io/crates/riot-sys
84-
[**riot-wrappers**]: https://crates.io/crates/riot-wrappers
85-
[bindgen]: https://crates.io/crates/bindgen
86-
[C2Rust]: https://c2rust.com/
87-
[riot_wrappers::mutex::Mutex]: https://rustdoc.etonomy.org/riot_wrappers/mutex/struct.Mutex.html
88-
[documented together with riot-sys and some of the examples]: https://rustdoc.etonomy.org/
89-
[I2CDevice]: https://rustdoc.etonomy.org/riot_wrappers/i2c/struct.I2CDevice.html
90-
[corresponding embedded-hal I2C traits]: https://rustdoc.etonomy.org/embedded_hal/blocking/i2c/index.html
91-
92-
Library components in Rust
93-
--------------------------
94-
95-
It is possible to use Rust in different modules than the application itself.
96-
97-
Such modules are usually pseudomodules (although they may be mixed with C in regular modules as well).
98-
They always depend on the `rust_riotmodules` module / crate,
99-
which collects all enabled modules into a single crate by means of optional features.
100-
101-
If the application is not written in Rust,
102-
that then depends on `rust_riotmodules_standalone`,
103-
which adds a panic handler and serves as a root crate.
104-
105-
If the application is written in Rust,
106-
`rust_riotmodules` needs to be added as a dependency of the application.
107-
(This helps deduplicate between application and library code,
108-
and also avoids symbol name clashes).
109-
This is done by adding a dependency on the local `rust_riotmodules` crate (which is a no-op when no such modules are enabled),
110-
and placing an `extern crate rust_riotmodules;` statement in the code.
111-
(The latter is needed even after most `extern crate` was abolished in 2018,
112-
because crates depended on but not used otherwise are usually not linked in).
113-
114-
Toolchain {#toolchain}
115-
---------
116-
117-
To install the necessary Rust components, it is easiest use [**rustup**, installed as described on its website].
118-
119-
Using Rust on RIOT needs the latest stable version of Rust.
120-
121-
Make sure you have the core library for the CPU (**target**) of your choice available:
122-
123-
```
124-
$ rustup target add thumbv7m-none-eabi
125-
```
126-
127-
Substitute thumbv7m-none-eabi with the value of `RUST_TARGET`
128-
in the output of `make info-build` of an application that has your current board selected
129-
(or just add it later whenever the Rust compiler complains about not finding the core library for a given target).
130-
Using the beta or nightly toolchains will work just as well
131-
if they are selected through rustup's override mechanism.
132-
133-
134-
While Rust comes with its own [cargo] dependency tracker for any Rust code,
135-
it does not attempt to install **system components**.
136-
To avoid playing the whack-a-mole of installing components whenever an install step fails,
137-
consider installing this list of packages on Debian
138-
(or an equivalent list on the distribution of your choice):
139-
140-
```
141-
# apt install libclang-dev llvm llvm-dev cmake libssl-dev pkg-config
142-
```
143-
144-
This encompass both components needed for riot-sys and for the later installation of C2Rust.
145-
146-
147-
In addition to the Rust compiler you'll need to install the C2Rust transpiler;
148-
as this is using some recent fixes, it is best installed as:
149-
150-
<!-- The locked works around <https://github.com/dtolnay/proc-macro2/issues/475> as closed in <https://github.com/immunant/c2rust/pull/1197>; there is no newer release that could be tested. -->
151-
```shell
152-
$ cargo install c2rust --git https://github.com/immunant/c2rust --tag v0.19.0 --locked
153-
```
154-
155-
If multiple versions of LLVM are installed locally, it may be necessary to prefix it with the selected LLVM version:
156-
157-
```
158-
$ LLVM_CONFIG_PATH=/usr/bin/llvm-config-16 cargo install …
159-
```
160-
161-
[cargo]: https://doc.rust-lang.org/cargo/
162-
[**rustup**, installed as described on its website]: https://rustup.rs/
163-
164-
Maintenance
165-
-----------
166-
167-
The [riot-sys] and [riot-wrappers] crates are currently maintained as parts of the RIOT project.
168-
While being released via crates.io on demand, usually RIOT uses a fixed version from the git repositories that are [easily updated].
169-
170-
The autogenerated bindings of the C API are slightly stricter than C's API,
171-
and thus occasionally require additional work when C APIs change subtly.
172-
The riot-sys crate takes the brunt of these changes --
173-
it changes automatically, and no attempt is currently made to reflect these changes in a SemVer compatible manner.
174-
The riot-wrappers crate smooths this out,
175-
and provides an API that aims to be more stable than the C API.
176-
It does that by generously converting types that changed,
177-
and [introspecting generated bindings] or using [information provided by riot-sys].
178-
179-
The typical workflow of (C-nonbreaking, Rust-breaking) API changes is as follows:
180-
181-
* A PR subtly alters a type (eg. `uint8_t *` to `void *` in [#17990]).
182-
183-
Consequently, builds of Rust examples break.
184-
185-
* A PR is opened on riot-wrappers to smooth over the change, like [aab605f4] <!-- commit reference rather than PR as that was still on GitLab back then -->.
186-
187-
The PR is tested against current master in its CI (albeit not for the full set of boards).
188-
To test whether it also works for the changed API,
189-
a commit titled "REMOVEME Test with updated riot-wrappes" can be added to the original PR;
190-
it alters `.cargo/config.toml` to point to the changed branch,
191-
and removes any Cargo.lock files in the RIOT tree.
192-
193-
That PR is then merged.
194-
195-
* The version of riot-wrappers that works both with the previous and the new code
196-
is pulled into the RIOT master branch by updating the Cargo.lock files.
197-
The PR can look like [#18181], and verifies that the new riot-wrappers works on all boards.
198-
199-
That PR is then merged.
200-
201-
* For the next builds (up to the merging of) the original PR,
202-
the REMOVEME commit can be removed.
203-
204-
It is good practice to rebase it onto the latest master after the update to riot-wrappers has been merged,
205-
as this helps keeping bisectability up.
206-
207-
The PR now contains no Rust specific changes, and can be merged.
208-
209-
There are a few variations that can occur:
210-
211-
* Sometimes casting is not enough, and a type must be extracted from a signature.
212-
[See the phydat callback type change] for an example.
213-
214-
* When neither casting nor type detection is sufficient,
215-
a marker can be introduced through riot-sys;
216-
it detects a keyword's presence in the source and passes it as [information provided by riot-sys] to riot-wrappers.
217-
[See the coap_request_ctx_t change] for an example.
218-
219-
In that case, a riot-sys PR is opened in parallel to the riot-wrappers PR.
220-
221-
This method helps keeping changes backportable easily:
222-
riot-sys and riot-wrappers are expected to work with the latest released version of RIOT all the time,
223-
and avoid flag-day changes.
224-
(Keeping riot-sys and riot-wrappers compatible with the latest release is also important to retain the ability to backport fixes).
225-
226-
* When functions are moved from being static and not being static,
227-
their names go from `riot_sys::inline::name` to `riot_sys::name` (or vice versa).
228-
229-
riot-sys [has a list] of items that are always publicly exported directly as `riot_sys::name`;
230-
just add the function there.
231-
232-
If non-generic types are referenced in them, they go from `riot_sys::inline::my_type_t` to `riot_sys::my_type_t`.
233-
The [inline_cast] function family helps making that cast a bit safer.
234-
235-
* Things fail around atomics.
236-
237-
Until [C2Rust's support for atomics has improved],
238-
riot-sys requires all exported headers to use the better supported `atomic_utils.h`.
239-
240-
If it is unavoidable that atomics are part of header files
241-
(and not actually used in any static inline functions),
242-
riot-sys's [atomics workarounds] can be extended as a last resort.
243-
244-
245-
[riot-wrappers]: https://github.com/RIOT-OS/rust-riot-wrappers/
246-
[riot-sys]: https://github.com/RIOT-OS/rust-riot-sys/
247-
[easily updated]: https://github.com/RIOT-OS/RIOT/pull/17491#issuecomment-1143209437
248-
[introspecting generated bindings]: https://github.com/RIOT-OS/rust-riot-wrappers/blob/db9d163e3eddcb7154edcf25db7207e4123964ee/src/helpers.rs#L3
249-
[information provided by riot-sys]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/build.rs#L591
250-
[#17990]: https://github.com/RIOT-OS/RIOT/pull/17990
251-
[aab605f4]: https://github.com/RIOT-OS/rust-riot-wrappers/commit/aab605f464a279608ef0a8ad2afd5ae43179e330
252-
[#18181]: https://github.com/RIOT-OS/RIOT/pull/18181
253-
[See the phydat callback type change]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/6/files#diff-ccb7946e3b4122ea3ce23fa9bc54eba63d75f7a6142fd4afdd9908b1bead50e0
254-
[See the coap_request_ctx_t change]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/4/files
255-
[has a list]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/build.rs#L533
256-
[inline_cast]: https://github.com/RIOT-OS/rust-riot-wrappers/blob/db9d163e3eddcb7154edcf25db7207e4123964ee/src/lib.rs#L68
257-
[C2Rust's support for atomics has improved]: https://github.com/immunant/c2rust/issues/436
258-
[atomics workarounds]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/riot-c2rust.h#L79
4+
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/).
5+
This page will be removed after release 2025.11.

0 commit comments

Comments
 (0)