Skip to content

Commit 3e68dd8

Browse files
committed
doc/guides: Introduce Rust Tutorial
1 parent 05b965a commit 3e68dd8

7 files changed

Lines changed: 495 additions & 0 deletions

File tree

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
---
2+
title: "Creating a Project"
3+
description: "Create a new project with a simple hello world program"
4+
---
5+
6+
import GitSetup from '@components/gitsetup.mdx';
7+
import Contact from '@components/contact.astro';
8+
9+
## Step 1: Create a new project
10+
11+
<GitSetup />
12+
13+
#### Open VS Code
14+
15+
Now that we have added RIOT as a submodule to our project, we can start writing our hello world program.
16+
You can use any text editor to create this file. We will use Visual Studio Code in this example. To open Visual Studio Code in the directory, you can use the following command:
17+
18+
```bash title="Open Visual Studio Code"
19+
code .
20+
```
21+
22+
## Step 2: Initialize Rust
23+
24+
Now that Visual Studio Code is open, we need to tell Rust what kind of project we want to create. We do this by running the following command in the terminal:
25+
26+
```bash title="Create a new Rust project"
27+
cargo new hello_world --lib
28+
```
29+
30+
This command creates a new project called `hello_world` with a library crate type.
31+
The `--lib` flag tells Rust that we want to create a library crate instead of a binary crate.
32+
A library crate is a collection of functions and types that can be used by other programs, while a binary crate is an executable program.
33+
RIOT then calls our `main` function when the program starts.
34+
35+
You should now have 3 new files within your project directory:
36+
37+
- `Cargo.toml`: This file contains metadata about your project and its dependencies.
38+
- `src/lib.rs`: This file contains the source code for your library crate.
39+
- `Cargo.lock`: This file contains information about the exact versions of your dependencies.
40+
- This file is automatically generated by Cargo and should not be edited manually so don't worry about it for now.
41+
42+
![The project structure](img/create_project/01_project_structure.png)
43+
44+
## Step 3: Creating the Makefile
45+
46+
Now that we have created our hello world program, we need to create a Makefile to build our program. The Makefile is a build automation tool that allows us to define how our program should be built. We create a new file called `Makefile` in the root directory of our project and add the following code:
47+
48+
```makefile title="Makefile"
49+
# name of your application
50+
APPLICATION = hello-world
51+
52+
# If no BOARD is found in the environment, use this default:
53+
BOARD ?= native
54+
55+
# Build in Docker by default (set to 0 to build locally)
56+
BUILD_IN_DOCKER ?= 1
57+
58+
# This has to be the absolute path to the RIOT base directory:
59+
RIOTBASE ?= $(CURDIR)/RIOT
60+
61+
# Comment this out to disable code in RIOT that does safety checking
62+
# which is not needed in a production environment but helps in the
63+
# development process:
64+
DEVELHELP ?= 1
65+
66+
# Change this to 0 show compiler invocation lines by default:
67+
QUIET ?= 1
68+
69+
# Make sure this matches the name of the Rust crate
70+
APPLICATION_RUST_MODULE = hello_world
71+
72+
include $(RIOTBASE)/Makefile.include
73+
```
74+
75+
:::note
76+
The `BUILD_IN_DOCKER=1` flag tells the build system to use the docker image provided by RIOT to build our program.
77+
This ensures that we have all the necessary dependencies to build our program.
78+
If you have already built RIOT on your system, you can omit this flag and the build system will use the toolchain installed on your system.
79+
:::
80+
81+
Now RIOT knows that you want to build a Rust application and will use the `hello_world` crate as the main module.
82+
83+
![The Makefile in Visual Studio Code](img/create_project/02_makefile.png)
84+
85+
## Step 3: Adjusting the Cargo.toml
86+
87+
Next, we need to adjust the `Cargo.toml` file to tell Cargo that we want to build for RIOT. Open the `Cargo.toml` file and replace its contents with the following:
88+
89+
```toml title="Cargo.toml"
90+
[package]
91+
name = "hello-world"
92+
version = "0.1.0"
93+
edition = "2021"
94+
95+
[lib]
96+
crate-type = ["staticlib"]
97+
98+
[profile.release]
99+
# Setting the panic mode has little effect on the built code (as Rust on RIOT
100+
# supports no unwinding), but setting it allows builds on native without using
101+
# the nightly-only lang_items feature.
102+
panic = "abort"
103+
104+
[dependencies]
105+
riot-wrappers = { version = "0.9.1", features = [ "set_panic_handler", "panic_handler_format" ] }
106+
107+
rust_riotmodules = { path = "./RIOT/sys/rust_riotmodules/" }
108+
```
109+
110+
The most important part here are the dependencies. As mentioned in [Rust in Riot](/rust_tutorials/rust_in_riot/),
111+
`riot-wrappers` is a crate that provides a set of wrappers around RIOT's C functions to make them usable from Rust in a safe way.
112+
113+
The other configuration options are not that important for now, but you can read more about them in the [Cargo documentation](https://doc.rust-lang.org/cargo/reference/manifest.html).
114+
115+
### IDE Setup
116+
117+
Due to the way the RIOT Rust integration works, you need to amend your
118+
normal Rust setup in your IDE to make it work with RIOT. Luckily RIOT
119+
provides a small makefile command that will help you with that. Run the following command in your terminal:
120+
121+
```bash
122+
make info-rust
123+
```
124+
125+
The output will look something like this:
126+
127+
```bash title="Output of make info-rust"
128+
[ann@ann-laptop13 rust01-hello-world]$ make info-rust
129+
cargo version
130+
cargo 1.81.0 (2dbb1af80 2024-08-20)
131+
c2rust --version
132+
C2Rust 0.19.0
133+
To use this setup of Rust in an IDE, add these command line arguments to the `cargo check` or `rust-analyzer`:
134+
--profile release
135+
and export these environment variables:
136+
CARGO_BUILD_TARGET="thumbv7em-none-eabihf"
137+
RIOT_COMPILE_COMMANDS_JSON="/home/ann/projects/exercises/rust01-hello-world/bin/feather-nrf52840-sense/cargo-compile-commands.json"
138+
RIOTBUILD_CONFIG_HEADER_C="/home/ann/projects/exercises/rust01-hello-world/bin/feather-nrf52840-sense/riotbuild/riotbuild.h"
139+
You can also call cargo related commands with `make cargo-command CARGO_COMMAND="cargo check"`.
140+
Beware that the way command line arguments are passed in is not consistent across cargo commands, so adding `--profile release` or other flags from above as part of CARGO_COMMAND may be necessary.
141+
```
142+
143+
In VSCode you can now go to the workspace settings `.vscode/settings.json`
144+
and add the following settings:
145+
146+
```json title=".vscode/settings.json"
147+
{
148+
"rust-analyzer.cargo.extraArgs": [
149+
"--profile",
150+
"release"
151+
],
152+
"rust-analyzer.cargo.target": "thumbv7em-none-eabihf",
153+
}
154+
```
155+
156+
and export the environment variables in your preferred way.
157+
You can also use the `make cargo-command` command to run cargo commands with the correct arguments.
158+
159+
## Step 4: Writing the Hello World Program
160+
161+
We are nearly done with setting up our project. The last thing we need to do i
162+
s to write the actual hello world program. Open the `src/lib.rs` file and replace its contents with the following code:
163+
164+
```rust title="src/lib.rs"
165+
#![no_std]
166+
167+
use riot_wrappers::riot_main;
168+
use riot_wrappers::println;
169+
170+
extern crate rust_riotmodules;
171+
```
172+
173+
`#![no_std]` tells the Rust compiler that we are building a program that does not depend on the standard library, which is not available on the hardware we are targeting.
174+
This does mean that we can't use some of the standard library features like `std::io` or `std::collections`, however, there are a lot of `no_std` compatible crates available that provide similar functionality,
175+
including `riot-wrappers` 😉
176+
177+
After that we import the functions that we will soon use to print to the console.
178+
The `riot_main` macro helps RIOT figure out what our main function is and `println` is a macro that we can use to print to the console,
179+
this replaces the `println!` macro from the standard library, since, as mentioned before, we can't use it on embedded systems.
180+
181+
Now we need to actually write the `main` function. Add the following code to the `src/lib.rs` file:
182+
183+
```rust title="src/lib.rs"
184+
riot_main!(main);
185+
186+
fn main() {
187+
println!(
188+
"You are running RIOT using Rust on a(n) {} board.",
189+
riot_wrappers::BOARD
190+
);
191+
}
192+
```
193+
194+
![The Full Code in VSCode](img/create_project/03_lib.png)
195+
196+
Congratulations! You have now created your first Rust program for RIOT. 🎉
197+
198+
## Step 5: Building the Program
199+
200+
<Contact />
201+
202+
To build our program, we use the following command:
203+
204+
```bash title="Build the program"
205+
make
206+
```
207+
208+
After building the program, we can run it using the following command to start the RIOT shell:
209+
210+
```bash title="Connect to the RIOT shell"
211+
make term
212+
```
213+
214+
You should see the following output:
215+
216+
```txt title="Output in the terminal"
217+
You are running RIOT using Rust on a(n) native board.
218+
```
219+
220+
![The Output in the Terminal](img/create_project/04_terminal_output.png)
221+
222+
## Conclusion
223+
224+
In this tutorial, you have learned how to create a new Rust project for RIOT and how to build and run it.
225+
You have also learned how to write a simple hello world program in Rust and how to use the `riot-wrappers` crate to interact with RIOT's C functions.
226+
227+
:::note
228+
The source code for this tutorial can be found [HERE](https://github.com/RIOT-OS/RIOT/tree/master/examples/lang_support/official/rust-hello-world).
229+
230+
If your project is not working as expected, you can compare your code with the code in this repository to see if you missed anything.
231+
:::
65.8 KB
Loading
173 KB
Loading
77.1 KB
Loading
54.6 KB
Loading

0 commit comments

Comments
 (0)