Ignore feature in optional dependency to avoid transitive dep flag conflict

I'm working on an embedded crate and would like to use a feature flag to select between hardware variants 833 and 840.
This flag should affect not just my code but also which crates I depend on.

Here's a snippet from my Cargo.toml:

[dependencies]
nrf52840-hal = { version = "0.11", optional = true }
nrf52833-hal = { version = "0.11", optional = true }

[features]
nrf52840 = ["nrf52840-hal"]
nrf52833 = ["nrf52833-hal"]
default = ["nrf52840"]

where my crate uses features to select the correct optional dependency.

Unfortunately, it seems that even if a dependency is optional, Cargo still considers its features when compiling transitive dependencies.

In my case both hal crates depend on nrf-hal-common and use feature flags themselves to select hardware.
But Cargo considers both features set, which causes a compilation error in the nrf-hal-common crate.

Basically, nrf52833-hal/Cargo.toml has:

[dependencies.nrf-hal-common]
version = "0.11.0"
features = ["52833"]
default-features = false

The nrf52840-hal has:

[dependencies.nrf-hal-common]
version = "0.11.0"
features = ["52840"]
default-features = false

and so nrf-hal-common is being compiled with features = ["52833" "52840"] and failing.

The only option that (I think) might work is to have a wrapper crate for each hardware variant that depends on the appropriate hal crate.
But since I need to use hardware features anyway (for my application code), also having to have separate crates would make me sad.

Is there a tidier way to resolve this?

Are you using --no-default-features when you try to build the other feature? Otherwise, you will have both the default and your manual selection added together.

I didn't know about --no-default-features, but it does resolve the issue, thanks!

I had tried

[dependencies]
nrf52840-hal = { version = "0.11", optional = true, default-features = false }
nrf52833-hal = { version = "0.11", optional = true, default-features = false }

in my Cargo.toml already, but it has no effect.
I guess default-features applies to just the crate it's specified on, whereas --no-default-features applies transitively to the full tree?

It's still very unsettling to me that cargo adds in features of "optional" dependencies.
I couldn't find any discussion or design docs that suggest this is intentional, do you think that'd be worth filing a bug report about?

No, the command-line option just applies to the root crate, where you have default = ["nrf52840"]. So if you want to select a different feature without also applying your defaults, you need to build with --no-default-features --features nrf52833.

1 Like

Ah! Gotcha, I was entirely confused about the issue.
I was assuming cargo build --release --features=nrf52833 would override the default nrf52840 feature on my crate, when it actually adds on.

This explanation makes much more sense.
Thanks for the help!

2 Likes

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.