riot-os / rust-riot-sys Goto Github PK
View Code? Open in Web Editor NEWThe Rust riot-sys crate, used for modules and applications on RIOT OS
The Rust riot-sys crate, used for modules and applications on RIOT OS
When trying to generate bindings for the bmx280
device driver, I noticed that the size of the struct bmx280_params_t
differs from C to Rust. I used the module USEMODULE += bmp280_i2c
and added these lines to rust-riot-sys/riot-headers.h
to generate the bindings:
#include "bmx280.h"
#include "bmx280_params.h"
The struct contains an i2c_dev
of type i2c_t
which seems to be the reason for the difference. I used the following programs to print the sizes. In C:
#include <stdio.h>
#include <bmx280.h>
int main(void) {
printf("sizeof bmx280_params_t = %d\n", sizeof(bmx280_params_t));
printf("sizeof i2c_t = %d\n", sizeof(i2c_t));
}
sizeof bmx280_params_t = 32
sizeof i2c_t = 4
In Rust:
use riot_wrappers::{println, riot_main};
use riot_sys::{bmx280_params_t, i2c_t};
use core::mem::size_of;
riot_main!(main);
fn main() {
println!("sizeof bmx280_params_t = {}", size_of::<bmx280_params_t>());
println!("sizeof i2c_t = {}", size_of::<i2c_t>());
}
sizeof bmx280_params_t = 28
sizeof i2c_t = 1
In the file RIOT/drivers/include/periph/i2c.h
the type is defined as follows:
#ifndef HAVE_I2C_T
typedef uint_fast8_t i2c_t;
#endif
For native, xtensa, risc-v and arm, it seems like all the fast integer types are defined through internal compiler defines like typedef __INT_FAST8_TYPE__ int_fast8_t;
These types differ since RIOT is compiled by gcc and the Rust bindings are created with llvm. I did some tests and got the following types using different architectures. The cells show the actual type when using gcc / clang:
Bit | Native (x86-64) | Xtensa | RISC-V | ARM |
---|---|---|---|---|
8 | char / char | int / char | int / char | int / char |
16 | long int / short | int / short | int / short | int / short |
32 | long int / int | int / int | int / int | int / int |
64 | long int / long int | long long int / long long int |
long long int / long long int |
long long int / long long int |
One workaround is to redefine these macros when generating the bindings so that they match the types used by gcc. For the uint_fast8_t
this can be done by adding the following lines to riot-bindgen.h
and riot-c2rust.h
:
#undef __UINT_FAST8_TYPE__
#define __UINT_FAST8_TYPE__ unsigned int
Alternatively, this also works:
#define HAVE_I2C_T
typedef unsigned int i2c_t
However there should be a better way that actually guarantees that the same type is used when compiling RIOT and creating the bindings.
There are build errors cropping up with:
--- stderr
/__w/rust-riot-wrappers/rust-riot-wrappers/RIOT/sys/include/auto_init_utils.h:35:10: fatal error: 'preprocessor_successor.h' file not found
thread 'main' panicked at /github/home/.cargo/git/checkouts/rust-riot-sys-d12733b89271907c/c985a6b/build.rs:224:10:
Unable to generate bindings: ClangDiagnostic("/__w/rust-riot-wrappers/rust-riot-wrappers/RIOT/sys/include/auto_init_utils.h:35:10: fatal error: 'preprocessor_successor.h' file not found\n")
I've now traced this down to being caused by compile-commands.json files where the -I.../bin/native/preprocessor
entry is not in the first of the included files.
When building on Alpine (which is muslibc based), building Rust based RIOT applications fails:
--- stderr
thread 'main' panicked at 'Unable to find libclang: "the `libclang` shared library at /usr/lib/libclang.so.13.0.1 could not be opened: Dynamic loading not supported"', /root/.cargo/registry/src/github.com-1ecc6299db9ec823/bindgen-0.60.1/src/lib.rs:2172:31
stack backtrace:
0: rust_begin_unwind
at /rustc/d394408fb38c4de61f765a3ed5189d2731a1da91/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/d394408fb38c4de61f765a3ed5189d2731a1da91/library/core/src/panicking.rs:142:14
2: core::result::unwrap_failed
at /rustc/d394408fb38c4de61f765a3ed5189d2731a1da91/library/core/src/result.rs:1814:5
3: core::result::Result<T,E>::expect
4: core::ops::function::FnOnce::call_once
5: lazy_static::lazy::Lazy<T>::get::{{closure}}
6: std::sync::once::Once::call_once::{{closure}}
7: std::sync::once::Once::call_inner
at /rustc/d394408fb38c4de61f765a3ed5189d2731a1da91/library/std/src/sync/once.rs:434:21
8: std::sync::once::Once::call_once
9: <bindgen::ensure_libclang_is_loaded::LIBCLANG as core::ops::deref::Deref>::deref
10: bindgen::ensure_libclang_is_loaded
11: bindgen::Bindings::generate
12: bindgen::Builder::generate
13: build_script_build::main
14: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
make: *** [/tmp/RIOT/makefiles/cargo-targets.inc.mk:44: /tmp/RIOT/examples/rust-hello-world/bin/microbit-v2/target/thumbv7em-none-eabihf/release/librust_hello_world.a] Error 101
I've tested this inside the container set up per immunant/c2rust#724 with maribu's resolution (RUSTFLAGS=-Ctarget-feature=-crt-static cargo install --locked c2rust
) with an extra of (the former is generally needed for RIOT, the latter target specific and make would have told us later anyway):
$ apk add git gcc-arm-none-eabi newlib-arm-none-eabi
$ rustup target add thumbv7em-none-eabihf
Then run (ideally after RIOT-OS/RIOT#18904 is in, or apply it manually):
$ make -C examples/rust-hello-world BOARD=microbit-v2
When switching riot-sys's bindgen dependency to /static
(btw, we don't really use the default features it seems...), the build script instead segfaults in a way similar to rust-lang/rust-bindgen#2333:
error: failed to run custom build command for `riot-sys v0.7.9 (/tmp/riot-sys)`
Caused by:
process didn't exit successfully: `/tmp/RIOT/examples/rust-hello-world/bin/microbit-v2/target/release/build/riot-sys-1835746e88917b5e/build-script-build` (signal: 11, SIGSEGV: invalid memory reference)
CC @maribu who originally found this.
[edit: more precise setup instructions]
The way bindgen derives Debug for packed structs has long raised warnigns about unaligned references; recently, these warnings were made into errors (breaking previously working builds under the update policy that it's OK to do that on unsound behavior).
Starting v0.7.8, the compiler change is counteracted by a #![warn(unaligned_references)]
, but that only stops the screaming and not the pain. (The pain is not that bad on most RIOT boards as their processors are rather tolerant of unaligned access, but it's still UB under Rust's memory model).
There's an issue on the bindgen side, but no clear path forward -- disabling Debug for riot-sys generated structs will be a breaking change, and worse, some riot-wrappers structs rely on thee to provide their Debug (and they may lose that silently if generics are involved, or visibly).
I don't have a good plan forward here yet, but at least it's documented now.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.