Adding host unit tests to an embedded project

This is my first project trying to write embedded rust and my first time working on a project larger than one crate. I'm trying to write software for my Arduino in Rust. I've found Rahix's template which runs a simple blink program without any extra setup.

I've found Ferrous System's blog post on Testing an embedded app and tried adapting their project structure to mine, but I'm not familiar enough to know what I need to change on my project.

As far as I understand, I need to have a top-level workspace which contains three crates:

  1. cross - contains the main.rs file that runs on the Arduino. This is a #![no_std] crate and imports the logic crate
  2. logic - contains all the interesting things that will run on the Arduino and get unit tested. This is a #![cfg_attr(not(test), no_std)] crate
  3. local - contains all the unit tests for the project. This is a std crate. It imports the logic crate, and could, in principle, contain a main.rs, but I don't see how that's useful in this setup.

I got as far as putting Rahix's template as the cross crate, but then I get errors like:

LLVM ERROR: Expected a constant shift amount!
error: could not compile `core` (lib)

if I compile in release mode, and

error: ran out of registers during register allocation

if I just do a normal cargo run

I've tried looking up these errors, but I'm not sure if I'm even going down the right path. Does someone have guidance on how to adapt my project, a different technique, or other resources I can look at?

What Arduino board are you using? This code sample should be compatible with the Arduino Nano 3.x.

Thanks for the link to that repo. That seems useful in some situations, but the Rahix template is solving that same problem for my situation.

I've figured out a solution to my problem! I was able to make a single crate work. I added the no_std, no_main, and the embedded main function behind the not(test) feature with the cfg! macro. The part that made it really work is removing the build.target and unstable.build-std from the .cargo/config.toml file, and passing those in during cargo build or cargo run. Because of that, I could just do cargo test.

Hopefully others can find this useful

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.