diff --git a/tests/rust_minimal/Cargo.lock b/tests/rust_minimal/Cargo.lock new file mode 100644 index 0000000000..10e357c086 Binary files /dev/null and b/tests/rust_minimal/Cargo.lock differ diff --git a/tests/rust_minimal/Cargo.toml b/tests/rust_minimal/Cargo.toml new file mode 100644 index 0000000000..14142f8a2a --- /dev/null +++ b/tests/rust_minimal/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rust-minimal" +version = "0.1.0" +authors = ["Christian Amsüss "] +edition = "2018" +resolver = "2" + +[lib] +crate-type = ["staticlib"] + +[dependencies] +riot-wrappers = "0.7" diff --git a/tests/rust_minimal/Makefile b/tests/rust_minimal/Makefile new file mode 100644 index 0000000000..37ef882eee --- /dev/null +++ b/tests/rust_minimal/Makefile @@ -0,0 +1,8 @@ +include ../Makefile.tests_common + +APPLICATION_RUST_MODULE = rust_minimal +BASELIBS += $(APPLICATION_RUST_MODULE).module + +FEATURES_REQUIRED += rust_target + +include $(RIOTBASE)/Makefile.include diff --git a/tests/rust_minimal/README.md b/tests/rust_minimal/README.md new file mode 100644 index 0000000000..f784f98e8c --- /dev/null +++ b/tests/rust_minimal/README.md @@ -0,0 +1,82 @@ +Test description +---------------- + +This test ensures that code produced through Rust can actually run; +it does that by simply printing "SUCCESS". + + +When things fail here +--------------------- + +This section is aimed at RIOT developers who are taken aback by this test failing +after they changed something completely unrelated. + +That can happen for two reasons: +For one, RIOT's API is not as strict as library APIs +(e.g. it is accepted that functions move between being `static inline` and not being), +and then, Rust is sometimes stricter than C when it comes to APIs +(e.g. no implicit numeric casting). + +The general strategy for addressing build failures resulting from this is: + +* Identify what breaks. + +* Update the `riot-sys` and `riot-wrappers` crates as necessary + to support both the old and the new version of the breaking piece. + + If actual workarounds (like an explicit cast) are needed to accommodate the old version, + a comment should indicate that this is for versions up to the current release, + to be eventually cleaned out when the crate bumps its minimum supported RIOT version. + +* Update the examples to use the new versions in a separate PR that just does + `cargo update` in the examples, and consequentally contains only Cargo.lock changes. + + Such a PR should be easy to get ACKed, as "CI says GO" is usually suffient for them. + +* Rebase the breaking PR on the one updating Cargo.lock. + +If old and new version can *not* be supported, +the affected crate should get a major release -- +but it's also grounds to revisit whether the change is actually as small as originally thought. +Then, the the Cargo.lock file can be updated in the very PR that introduces the breaking change. + +When, +for the above reasons or others, +a major release of creates is done, +their new versions should have a `.0-alpha.0` or similar release. +and a full release of the crate is done after the changing PR is merged. + +Common failure modes are: + +* Primitive types changed. + + This can trigger a change in Rust numeric internals, + which should then just take the larger of the different versions' types. + + If the type is publicly visible, it is usually already `usize` or a similar maximal type; + if not, and if using the new RIOT version means that the crate's API needs to change, + the crate needs to undergo a breaking release. + +* Functions are moved between static inline and linked. + + For the functions themselves, this is caught automatically because `riot-sys` + presents a unified view on symbols produced from linked and static functions. + If any such function takes a struct (even through a pointer), that struct's type changes. + The `inline_cast` function can be used to transmute the pointers with some safety checks. + +* Atomics are introduced. + + The C2Rust transpiler that allows using all the non-linked parts of the RIOT API + is incapable of handling atomics; + a workaround in `riot-sys`'s `riot-c2rust.h` file contains a list of headers + that do depend on `stdatomic.h` but don't really expose anything of that as their API; + they get included with a crude fake of atomics. + + If the addition of a board makes this test fail on that board only, + it is likely because that board's `board.h` pulls in stdatomic through one of the not yet cleared headers. + That file needs to be vetted for visible use of atomics, + and added to that list. + + diff --git a/tests/rust_minimal/src/lib.rs b/tests/rust_minimal/src/lib.rs new file mode 100644 index 0000000000..358a332ab2 --- /dev/null +++ b/tests/rust_minimal/src/lib.rs @@ -0,0 +1,15 @@ +// Copyright (C) 2020 Christian Amsüss +// +// This file is subject to the terms and conditions of the GNU Lesser +// General Public License v2.1. See the file LICENSE in the top level +// directory for more details. +#![no_std] + +use riot_wrappers::riot_main; +use riot_wrappers::println; + +riot_main!(main); + +fn main() { + println!("SUCCESS"); +} diff --git a/tests/rust_minimal/tests/01-run.py b/tests/rust_minimal/tests/01-run.py new file mode 100755 index 0000000000..026e7e6293 --- /dev/null +++ b/tests/rust_minimal/tests/01-run.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2021 Freie Universität Berlin +# 2021 Inria +# 2021 Kaspar Schleiser +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run + + +def testfunc(child): + child.expect_exact('SUCCESS') + + +if __name__ == "__main__": + sys.exit(run(testfunc))