For background, this is somewhat related to some ongoing bugs in Cargo and how it unifies build-dependencies
and dev-dependencies
, and this recent comment on that in particular:
Rust API guidelines state that Cargo features are both additive and that when gating std
support, it should be under an eponymous std
Cargo feature:
Many crates to do this to facilitate no_std
use, gating all std
-dependent functionality under a default-enabled std
feature.
For no_std
users, this means they wind up with Cargo.toml dependency sections that look like this:
[dependencies]
aaa = { version = "...", default-features = false }
bbb = { version = "...", default-features = false }
ccc = { version = "...", default-features = false }
ddd = { version = "...", default-features = false }
eee = { version = "...", default-features = false }
fff = { version = "...", default-features = false }
ggg = { version = "...", default-features = false }
hhh = { version = "...", default-features = false }
(This is exacerbated by diagnostics for which crate is linking std
being bad, but I digress...)
Failure to track down a single one of those unintentionally activated std
features is enough to prevent linking, and this is often in a hierarchy of transitive dependencies.
I feel like the tension here is between these two things:
- Crate authors who want to expose a subset of functionality to
no_std
users don't want that to come at the cost of additional complexity tostd
users, and when push comes to shove will typically optimize for the latter -
no_std
users must track down every last crate failing to#![no_std]
or, after doing so, doing anextern crate std
I am wondering if making std
features more of a first-class concept, rather than a "guideline", could help find a better balance between these to.
The goal: make it easy for crates which link against std
to activate the std
feature in all of their dependent crates without those dependent crates having to do default = ["std"]
Here are a couple ideas along those lines. Now granted, these may be the sorts of things that only make sense when bumping editions, but if that's the case, better we start thinking about them sooner than later:
Declarative activation of std
for all dependencies
I'm imagining something like this in Cargo.toml
:
[package]
name = "..."
edition = "202X"
std-features = true
Now, I'm not sure the [package]
section is the right place for this (I chose it because [features]
seems quite overloaded), or if std-features
is a good name, or if a boolean value is the right way to express this, but let me just get to the core idea: a declarative way to activate the std
features of all dependencies as an alternative to each of those dependencies doing default = ["std"]
.
Declarative deactivation of std
-dependent features for no_std
users
Alternatively, perhaps instead asking the whole ecosystem to flip its defaults, Cargo could provide a more declarative way for no_std
crates to shut the default-on std
features off. Here's the same idea, in reverse:
[package]
name = "..."
edition = "202X"
std-features = false
This could potentially allow embedded/WASM or other no_std
users to declaratively say "I don't want std
features in my dependencies or any default-on features that depend on std
", eliminating all of that default-features = false
boilerplate.
Other options?
I'm sure there are many other mechanisms this could be tied to: a whitelist of targets a particular crate is intended to be built for perhaps? If a crate only targets no_std
platforms, regardless of how this is implemented, it sure would be nice if there were an easier way to request that dependencies to not link with any std
-dependent features.
I would be very curious to hear any other idea about how the end goal of "make it easy to deactivate std
-dependent features of (transitive) dependencies" can be accomplished.