Description
The basic idea is to have "feature sets". When writing a package, you can specify a list of "features" for a dependency to be built with. And in the dependency, it can do various operations depending on a feature. So for example, the top-level package:
[dependencies.db]
features = ["postgres"]
Then, in the manifest for db
:
[features.postgres]
[dependencies.postgres]
git = "https://github.com/sfackler/rust-postgres"
When a dependency is specified as part of a feature, it is only built when that feature is specified.
The "features" for a crate would also be exposed as a --cfg
flag to rustc for that package and as a comma-separated list of features in an environment variable, CARGO_FEATURES
. The following would work:
#[cfg(cargo_feature = "postgres")]
fn connect() { ... }
(Specifically, a --cfg cargo_feature="$FEAT"
would be passed for every feature. See this gist for an example of how this can work)
There is some subtlety in this feature. Consider the following:
Main manifest:
[dependencies.db]
features = ["postgres"]
[dependencies.foo]
git = "..."
Foo manifest:
[dependencies.db]
features = ["sqlite"]
The problem is that transitive dependencies may have a different set of features.
To solve this, a package which supports features can specify a list of mutually exclusive features. When this package is used as a dependency, every feature specified in the dependency graph will be taken as a list and compared against the mutually exclusive feature lists. For example, db
could have:
[package]
name = "db"
mutually_exclusive_features = [["postgres", "sqlite", "mysql"], ["awesome", "lame"]]
If not specified, no features are mutually exclusive.