Hello! The GitHub feature request template directed me here.
I don't keep up with the forums here (yet!) so this may already be a feature that's being discussed or proposed elsewhere -- if that's the case, please point me in the right direction.
Context:
I'm a new user of Tokio. It's got this great new JoinSet that I'd like to use. However, it's still a bit experimental, so it's part of their unstable API, which must be enabled with --cfg tokio_unstable
.
I've been using Rust for a few years, but so far I've never had to directly apply compiler flags, so I had to go and figure out how to do that. I ran into a couple issues along the way:
- Despite seeing some examples in the wild,
rustflags
does not seem to actually work from Cargo.toml.
(To be fair, Cargo did warn about an "unused manifest key". But of course, I'm doing this while I'm in the middle of hacking on a project so there were so many other warnings that I didn't notice until much later.) - If you specify a
cfg
key that doesn't exist, there's no error or warning. (And can be no warning. Because that--cfg foo
is applied to allrustc
invocations.) It just seems to not work and the user is left scratching their head.
Why Not a Crate Feature?
So, frustrated, I head over to the Tokio Discord for help, and immediately figure out my own problem.
But we also had a chat about why this isn't exposed as a feature:
In Cargo, features are transitive. If foo
depends on bar
, and bar
enables unstable_tokio
, foo
will get that feature enabled silently. Foo
doesn't don't know that bar
is likely to break in the future. And foo
may also accidentally depend on unstable features.
To avoid that behavior, the Tokio developers used this cfg
flag which must be specified as part of the top-level build, so that end users always opt in explicitly.
In searching for rustflags
in Cargo.toml above, I found out that the uuid-rs crate uses the same pattern for unstable features. Maybe this is a commonly known and used pattern?
Finally, The Feature Request:
It seems like folks are using unstable --cfg
flags to work around a shortcoming in Cargo. It would be nice if Cargo could handle this, so we could just use feature flags!
Benefits:
- Useable from
Cargo.toml
- Cargo can check if you reference a feature that's not (or no longer) present, or a typo.
- Makes it easier to follow semver rules by testing out unstable features before making them part of a stable feature set.
My initial (TBH not very well thought-out) brainstorm:
A new feature type. It could be called "opt-in features", or "non-transitive features", but "unstable" seems to describe this particular use case, so I'll use that here.
Within a crate, unstable features work just like stable ones. ex:
# file: foo/Cargo.toml
[features]
default = ["foo", "unstable_bar"]
# Defining an unstable feature:
[unstable_features]
unstable_bar = ["baz"]
# Using unstable features in direct dependencies:
[dependencies.third_party]
version = "*"
features = [ "unstable_whatever" ]
The new "unstable feature" functionality become apparent when transitive dependencies come into play:
# file: my-proj/Cargo.toml (errors)
[dependencies.foo]
version = "*"
This would yield some error like:
Crate 'foo' has been configured to use the following unstable features:
- crate: foo, features = [ "unstable_bar" ]
- crate: third_party, features = [ "unstable_whatever" ]
Unstable features may break semver guarantees, so require explicit opt-in. See: [docs].
And to fix it, the end user just explicitly opts in to the unstable features in their Cargo.toml:
# file: my-proj/Cargo.toml (fixed)
[dependencies.foo]
version = "*"
# Opt in to direct dependency's unstable feature.
features = [ "unstable_bar" ]
# Must also opt into all transitive unstable features:
[dependencies.third_party]
version = "*"
features = [ "unstable_whatever" ]
Other possibilities:
- If we're worried about a scourge of unstable features showing up in crates,
cargo publish
could deny crates that have unstable features enabled in their default configuration. - Might want to force a prefix (
unstable_
?) for these types of feature flags. - Maybe add some metadata to unstable features, like a link to docs about why they're unstable?