Removed mention of cargo workspaces from embedded unit testing post.

Cargo workspaces dont play well with cross-compilation.
This commit is contained in:
Gabe Venberg 2025-12-12 10:49:41 +01:00
parent 7cae618ef3
commit 72c83f347e

View file

@ -23,11 +23,10 @@ Fortunately, that realization leads us directly to...
In Rust, the minimum unit of compilation is the crate.
This means that if we want to separate our logic from our hardware interaction, we have to put them in separate crates.
Thankfully, Rust has a feature called [workspaces](https://doc.rust-lang.org/cargo/reference/workspaces.html) dedicated to managing several crates in a single project/repo.
So, what we will do is make a [virtual workspace](https://doc.rust-lang.org/cargo/reference/workspaces.html) at the top level of our repo,
containing 2 or more crates: one (or more, if it makes sense) for our main hardware layer that is set up for cross compilation and flashing using cargo-embed,
one `#![no-std]` crate containing only hardware independent logic that can be used on any architecture, and do not have cross-compilation explicitly setup.
So what we will do is split our crate into 2 or more crates within the same git repo:
One for our main hardware layer that is set up for cross compilation and flashing using cargo-embed,
and one (or more, if it makes sense) `#![no-std]` lib crate(s) containing only hardware independent logic that can be used on any architecture, and do not have cross-compilation explicitly setup.
The latter set of crate(s) are the ones that we will be able to put unit tests in.
## Implementation
@ -61,11 +60,9 @@ Lets say that we have a project that looks something like this:
`calibration.rs` and `main.rs` are the only modules that depend on hardware features, so they will be the modules going into `hardware_main`.
The rest will be going into `independent_logic`.
First we create the two new crates, with `hardware_main` being a binary crate and `independent_logic` being a library one, and we move the files to their respective crate.
First we create the two new crates, with `hardware_main` being a binary crate and `independent_logic` being a library crate, and we move the files to their respective crate.
Then, we move the existing `Cargo.toml`, `Embed.toml`, `build.rs`, `memory.x`, and `.cargo/config` into the `hardware_main`.
Then, we create a new `Cargo.toml` at the top level, with the only section being a `[workspace]` section,
including both of the crates in the workspace.
We edit the `Cargo.toml` of `hardware_main` to point to `independent_logic` as a [path dependency](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-path-dependencies), and remove any dependencies that are no longer used.
We edit the `Cargo.toml` of `independent_logic` to add any packages that our code depends on.
We edit `lib.rs` to declare all the modules in `independent_logic` (and declare the crate as `#![no_std]`),
@ -77,7 +74,6 @@ In the end, our file tree should look something like this:
{{<highlight console "linenos=false">}}
.
├── .gitignore
├── Cargo.toml
├── LICENCE
├── README.md
├── hardware_main
@ -103,6 +99,3 @@ In the end, our file tree should look something like this:
### Adding tests
Now that we have separated the crates from each other, we are free to add unit tests to `independent_logic` the same way we would for any 'normal' rust project.
However, we must keep in mind that we will only be able to run `cargo test` from inside the `independent_logic` crate.
Likewise, we will not be able to run `cargo build/check/embed` from the top level workspace, but must run it from the `hardware_main` crate, as that crate is bound to a specific target.
Cargo commands will generally also not work in the root workspace, as it will try to compile `hardware_main` for our local architecture, inevitably failing.