Skip to content

Commit f0070c1

Browse files
committed
doc/guides: Introduce Rust Tutorial
1 parent e77a073 commit f0070c1

7 files changed

Lines changed: 496 additions & 0 deletions

File tree

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
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
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
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
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+
# Tell the build system to use the Rust crate here
70+
FEATURES_REQUIRED += rust_target
71+
# Make sure this matches the name of the Rust crate
72+
APPLICATION_RUST_MODULE = hello_world
73+
BASELIBS += $(APPLICATION_RUST_MODULE).module
74+
75+
include $(RIOTBASE)/Makefile.include
76+
```
77+
78+
:::note
79+
The `BUILD_IN_DOCKER=1` flag tells the build system to use the docker image provided by RIOT to build our program. This ensures that we have all the necessary dependencies to build our program. 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.
80+
:::
81+
82+
Now RIOT knows that you want to build a Rust application and will use the `hello_world` crate as the main module.
83+
84+
![The Makefile in Visual Studio Code](img/create_project/02_makefile.png)
85+
86+
## Step 3: Adjusting the Cargo.toml
87+
88+
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:
89+
90+
```toml
91+
[package]
92+
name = "hello-world"
93+
version = "0.1.0"
94+
edition = "2021"
95+
96+
[lib]
97+
crate-type = ["staticlib"]
98+
99+
[profile.release]
100+
# Setting the panic mode has little effect on the built code (as Rust on RIOT
101+
# supports no unwinding), but setting it allows builds on native without using
102+
# the nightly-only lang_items feature.
103+
panic = "abort"
104+
105+
[dependencies]
106+
riot-wrappers = { version = "0.9.1", features = [ "set_panic_handler", "panic_handler_format" ] }
107+
108+
rust_riotmodules = { path = "./RIOT/sys/rust_riotmodules/" }
109+
```
110+
111+
The most important part here are the dependencies. As mentioned in [Rust in Riot](/rust_tutorials/rust_in_riot/),
112+
`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.
113+
114+
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).
115+
116+
### IDE Setup
117+
118+
Due to the way the RIOT Rust integration works, you need to amend your
119+
normal Rust setup in your IDE to make it work with RIOT. Luckily RIOT
120+
provides a small makefile command that will help you with that. Run the following command in your terminal:
121+
122+
```bash
123+
make info-rust
124+
```
125+
126+
The output will look something like this:
127+
128+
```bash
129+
[ann@ann-laptop13 rust01-hello-world]$ make info-rust
130+
cargo version
131+
cargo 1.81.0 (2dbb1af80 2024-08-20)
132+
c2rust --version
133+
C2Rust 0.19.0
134+
To use this setup of Rust in an IDE, add these command line arguments to the `cargo check` or `rust-analyzer`:
135+
--profile release
136+
and export these environment variables:
137+
CARGO_BUILD_TARGET="thumbv7em-none-eabihf"
138+
RIOT_COMPILE_COMMANDS_JSON="/home/ann/projects/exercises/rust01-hello-world/bin/feather-nrf52840-sense/cargo-compile-commands.json"
139+
RIOTBUILD_CONFIG_HEADER_C="/home/ann/projects/exercises/rust01-hello-world/bin/feather-nrf52840-sense/riotbuild/riotbuild.h"
140+
You can also call cargo related commands with `make cargo-command CARGO_COMMAND="cargo check"`.
141+
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.
142+
```
143+
144+
In VSCode you can now go to the workspace settings `.vscode/settings.json`
145+
and add the following settings:
146+
147+
```json
148+
{
149+
"rust-analyzer.cargo.extraArgs": [
150+
"--profile",
151+
"release"
152+
],
153+
"rust-analyzer.cargo.target": "thumbv7em-none-eabihf",
154+
}
155+
```
156+
157+
and export the environment variables in your preferred way.
158+
You can also use the `make cargo-command` command to run cargo commands with the correct arguments.
159+
160+
## Step 4: Writing the Hello World Program
161+
162+
We are nearly done with setting up our project. The last thing we need to do i
163+
s to write the actual hello world program. Open the `src/lib.rs` file and replace its contents with the following code:
164+
165+
```rust
166+
#![no_std]
167+
168+
use riot_wrappers::riot_main;
169+
use riot_wrappers::println;
170+
171+
extern crate rust_riotmodules;
172+
```
173+
174+
`#![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.
175+
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,
176+
including `riot-wrappers` 😉
177+
178+
After that we import the functions that we will soon use to print to the console.
179+
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,
180+
this replaces the `println!` macro from the standard library, since, as mentioned before, we can't use it on embedded systems.
181+
182+
Now we need to actually write the `main` function. Add the following code to the `src/lib.rs` file:
183+
184+
```rust
185+
riot_main!(main);
186+
187+
fn main() {
188+
println!(
189+
"You are running RIOT using Rust on a(n) {} board.",
190+
riot_wrappers::BOARD
191+
);
192+
}
193+
```
194+
195+
![The Full Code in VSCode](img/create_project/03_lib.png)
196+
197+
Congratulations! You have now created your first Rust program for RIOT. 🎉
198+
199+
## Step 5: Building the Program
200+
201+
<Contact />
202+
203+
To build our program, we use the following command:
204+
205+
```bash
206+
make
207+
```
208+
209+
After building the program, we can run it using the following command to start the RIOT shell:
210+
211+
```bash
212+
make term
213+
```
214+
215+
You should see the following output:
216+
217+
```
218+
You are running RIOT using Rust on a(n) native board.
219+
```
220+
221+
![The Output in the Terminal](img/create_project/04_terminal_output.png)
222+
223+
## Conclusion
224+
225+
In this tutorial, you have learned how to create a new Rust project for RIOT and how to build and run it.
226+
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.
227+
228+
:::note
229+
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).
230+
231+
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.
232+
:::
65.8 KB
Loading
126 KB
Loading
77.1 KB
Loading
54.6 KB
Loading

0 commit comments

Comments
 (0)