Dependency rand_core / getrandom (std)

I've used those examples ("rust-exercises") to build, flash and run Rust code for a Nordicsemi ARM uC, e.g. via

cargo build --bin blinky
cargo run --bin blinky -- --allow-erase-all

Now I want to use the repository (containing the HAL etc.) as a subfolder in another no_std-software project (repo) to run that code on the controller.

I've created a source file ./examples/ containing the source code from nrf52-code/radio-app/src/bin/blinky.rs.
And I've extended the project's Cargo.toml with configuration from the example's nrf52-code/radio-app/Cargo.toml.

When I invoke

nrf52-code/radio-app/src/bin/blinky.rs

then I get errors showing that the dependency rand_core pulls another dependency get_random which needs std.

In the "rust-exercises" cargo tree shows that rand_core does not add this get_random dependency.
I can't see what triggers it in case of our software project. rand_core supports both std and no_std configurations. So I assume my problem is related to some std / no_std configuration.

Excerpt of cargo tree as it shows in the "rust-exercises":

radio_app v0.0.0 (/mnt/daten/dev/rust-exercises.git/nrf52-code/radio-app)
    β”œβ”€β”€ dk v0.0.0 (/mnt/daten/dev/rust-exercises.git/nrf52-code/boards/dk)
        └── nrf52840-hal v0.16.0
            β”œβ”€β”€ nrf-hal-common v0.16.0
                β”œβ”€β”€ rand_core v0.6.4

Here a part of cargo tree as it shows in our project:

radio_app v0.0.0 (/mnt/daten/dev/rust-exercises.git/nrf52-code/radio-app)
|   β”œβ”€β”€ dk v0.0.0 (/mnt/daten/dev/rust-exercises.git/nrf52-code/boards/dk)
|       └── nrf52840-hal v0.16.0
|           β”œβ”€β”€ nrf-hal-common v0.16.0
|               β”œβ”€β”€ rand_core v0.6.4
|                   └── getrandom v0.2.12
|                   β”œβ”€β”€ cfg-if v1.0.0
|                   └── libc v0.2.153
|
[dev-dependencies]
β”œβ”€β”€ rand v0.8.5
β”‚   β”œβ”€β”€ libc v0.2.153
β”‚   β”œβ”€β”€ rand_chacha v0.3.1
β”‚   β”‚   β”œβ”€β”€ ppv-lite86 v0.2.17
β”‚   β”‚   └── rand_core v0.6.4 (*)
β”‚   └── rand_core v0.6.4 (*)

How can I figure out what's missing -- or where std is enabled -- for rand_core?

It looks like you have a dev-dependency on the rand crate with its default std feature enabled, which in turn depends on the std feature of rand_core. When building examples or tests, features from dev-dependencies and regular dependencies are unified.

Are you able to change your rand dev-dependency to have default-features = false?

If not, another solution would be to move the "blinky" binary’s code from examples/blinky.rs to src/bin/blinky.rs so it is compiled as a β€œregular” binary crate rather than an β€œexample,” and can be built without building dev-dependencies.

1 Like

Thanks.

I almost didn't notice this rand_core under dev-dependencies, and when I did I thought it's probaby not important, because it doesn't list getrandom as a "child" dependency.

How come the cargo tree doesn't show the getrandom etc under the itemrand_core in dev-dependencies? (it almost caused me to not add the part to the first post).

I can see that rand is mentioned twice in our Cargo.toml:

[dependencies]
[...]
rand = { version = "0.8.3", optional = true }
[dev-dependencies]
[...]
rand = { version = "0.8.3", default-features = false }

The default-features = false has not been provided before.
Anyway, I'm getting now lots of issues from other dependencies.

error[E0463]: can't find crate for `std`
  |
  = note: the `thumbv7em-none-eabihf` target may not support the standard library
  = note: `std` is required by `os_str_bytes` because it does not declare `#![no_std]`

error[E0463]: can't find crate for `std`
  |
  = note: the `thumbv7em-none-eabihf` target may not support the standard library
  = note: `std` is required by `strsim` because it does not declare `#![no_std]`

error: cannot find macro `vec` in this scope
   --> /home/sn/.cargo/registry/src/index.crates.io-6f17d22bba15001f/strsim-0.10.0/src/lib.rs:336:25
    |
336 |     let mut distances = vec![0; (a_len + 2) * (b_len + 2)];
    |                         ^^^

So I'll try the other approach, and see how that can work with our project structure.

This looks like an bug in cargo tree, actually - it probably should not deduplicate dependencies between "main" and "dev" blocks, since, well, they might actually be different, as it is in this case. For now, it just shows that rand_core is referenced by the main crate, and then in dev-dependencies it adds this dependency with a "see above" mark (an asterisk).

And this is expected, if these other dependencies are not no_std themselves.

Thanks for the hints, and sorry for not reacting quicker, I've occupied otherwise for a few days.

Not sure whether I understand this correctly, the two quotes above seem to contradict each other.

Reading about dependency resolution I'd say that cargo should handle [dev-dependencies] and "main"'s dependencies separately:

Features enabled on dev-dependencies will not be unified when those same dependencies are used as a normal dependency, unless those dev-dependencies are currently being built.

which it doesn't in my case.

The "non-dev" part of the project builds without std, so I think anything with std would come from the examples and dev-dependencies.

Here's how our project setup roughly looks like, in case it can contribute to understand:

benches/
  mod.rs
Cargo.toml
examples/
  demo1.rs
  demo2.rs
  demo_nrf52.rs
src/
  hasher/...
  lib.rs
  util/...
  hss/...
tests/...

The whole point of dev-dependencies is that they are used by tests, examples, and benchmarks. If your dev-dependencies require std then your tests, examples, and benchmarks do too.

cargo tree by default includes build-dependencies and dev-dependencies, but you can use cargo tree --edges normal if you want to exclude build- and dev-dependencies.

If you need more fine-grained control of dependencies (e.g. you have tests that require std but example binaries that should not) then you can either make those into "normal" (not "example") binaries, or move them into a separate package, or make them optional dev-dependencies and (manually) enable different Cargo features when building different targets.

Note that the required-features key helps with this, though it still requires a bit more manual command-line-option passing than I would like.

So for my use case I should have thought about tihs earlier: for now it's okay if I have a quick & dirty solution running.

The Cargo.toml doesn't mention the folders benches, examples and tests, so I assume those folders are all kind of default conventions for commands like rustup run nightly cargo bench, cargo test and cargo run --example ....

Now I've

  • moved all those folders or "problematic" files inside temporarily away (I've kept examples/sst_demo_nrf52.rs)
  • removed [dev-dependencies] from my Cargo.toml
  • did a cargo clean

With that I can at least currently cross-build via cargo build --target=thumbv7em-none-eabihf --example sst_demo_nrf52.

I'll try to look into a nicer solution, but can't spend too much time on it, and for now it seems to work (I'll try the binary tomorrow).