- Feature Name: feature-metadata
- Start Date: 2023-09-08
- RFC PR: rust-lang/rfcs#3487
- Rust Issue: rust-lang/rust#0000
This RFC describes a new key under features
in Cargo.toml
to indicate that a
feature is private.
Please see the parent meta RFC for background information: [feature-metadata
].
[Cargo features](link to features doc) are one of the main means to support conditional build and optional dependency configuration in Rust crates. Often these are for configuration options that a library user may want, but another common use case is hiding API that shouldn't be available to downstream users. Examples include:
- Debugging, benchmarking or test-related features that expose unstable internal API
- Intermediate features that are enabled by user-facing features but not meant to be used on their own (e.g. a feature enabling dependency features)
A way to hide these features from user-facing configuration will make options easier to understand and lowers the chance of library users accidentally using unstable internal API.
There will be a new flag allowed within [features]
: public
. This is boolean
flag defaulting to true
that indicates whether or not downstream crates should
be allowed to use this feature.
[features]
foo = { enables = [], public = false}
Attempting to use a private feature on a downstream crate will result in messages like the following:
error: feature `baz` on crate `mycrate` is private and cannot be used by
downstream crates
public
is a boolean value that defaults to true
. It can be thought of as
pub
in Rust source files, with the exception of being true by default. If set
to false
, Cargo should forbid its use with an error message on any downstream
crates.
The default true
is not consistent with public_private_dependencies
or
Rust's pub
, but is a reasonable default to be consistent with the current
behavior. This means that either feature = []
or
feature = { "enables" = [] }
will result in the same configuration.
The name public
was chosen in favor of pub
to be consistent with the
public_private_dependencies
RFC, and to match the existing style of using
non-truncated words as keys.
In general, marking a feature public = false
should make tooling treat the
feature as non-public API. This is described as the following:
- The feature is always usable within the same crate:
- Enabled by other features, e.g.
foo = { enables = [some-private-feature] }
, is allowed - Referenced in
[[bench]]
and[[test]]
targetrequired-features
- Using the feature on the command-line is allowed
- Enabled by other features, e.g.
- Users may explicitly specifying the private features for their dependencies
on the command-line (e.g.
--features somecrate/private-feature
) which would otherwise be forbidden - The feature should not be accepted by
cargo add --features
- The feature should not be reported from
cargo add
's feature output report- A future tool like
cargo info
shouldn't display information about these features
- A future tool like
- Once
rustdoc
is able to consume feature metadata,rustdoc
should not document these features unless--document-private-items
is specified
Attempting to use a private feature in any of the forbidden cases should result in an error. Exact details of how features work will likely be refined during implementation and experimentation.
This feature requires adjustments to the index for full support. This RFC
proposes that it would be acceptable for the first implementation to simply
strip private features from the manifest; this means that there will be no way
to cfg
based on these features.
Full support does not need to happen immediately, since it will require this
information be present in the index. The feature-deprecation
RFC describes
a way to add attributes to features in a forward-compatible way under a
features3
key, which would be suitible for any additional information needed
here.
- Added complexity to Cargo. Parsing is trivial, but exact implementation details do add test surface area
- Added Cargo arguments if escape hatches for
public
are created - This adds confusion to the
cfg
diagnostics introduced in rust-lang/rust#109005
- Currently,
docs.rs
will hide features from its autogenerated feature list if they start with a leading underscore. This convention would work here, but it would not be consistent with the Rust language (leading underscores indicate unused variables, lang items are used to indicate visibility)
docs.rs
treats features with a leading_
as private / hidden- Ivy has a visibility attribute for its configuration (mentioned in cargo #10882)
- Discussion on stable/unstable/nightly-only features rust-lang/cargo#10881
- Are the semantics of
public
proposed in this RFC suitable? Should private features be usable in examples or integration tests without a--features
argument? - Does
public
need to be in the index?
- A
stable
field can be set false to indicate API-unstable or nightly-only features (something such asstable = 3.2
could be used to indicate when a feature was stabilized). See also: rust-lang/cargo#10882 - The
public
option could be used to allow optional dev dependencies. See: rust-lang/cargo#1596