mirror of
https://github.com/rust-lang/cargo
synced 2024-08-28 19:59:27 +00:00
Stabilize namespaced and weak dependency features.
This commit is contained in:
parent
2478331215
commit
43a063c80a
|
@ -20,7 +20,7 @@ atty = "0.2"
|
||||||
bytesize = "1.0"
|
bytesize = "1.0"
|
||||||
cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" }
|
cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" }
|
||||||
cargo-util = { path = "crates/cargo-util", version = "0.1.2" }
|
cargo-util = { path = "crates/cargo-util", version = "0.1.2" }
|
||||||
crates-io = { path = "crates/crates-io", version = "0.33.1" }
|
crates-io = { path = "crates/crates-io", version = "0.34.0" }
|
||||||
crossbeam-utils = "0.8"
|
crossbeam-utils = "0.8"
|
||||||
curl = { version = "0.4.41", features = ["http2"] }
|
curl = { version = "0.4.41", features = ["http2"] }
|
||||||
curl-sys = "0.4.50"
|
curl-sys = "0.4.50"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "crates-io"
|
name = "crates-io"
|
||||||
version = "0.33.1"
|
version = "0.34.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
repository = "https://github.com/rust-lang/cargo"
|
repository = "https://github.com/rust-lang/cargo"
|
||||||
|
|
|
@ -55,8 +55,6 @@ pub struct NewCrate {
|
||||||
pub repository: Option<String>,
|
pub repository: Option<String>,
|
||||||
pub badges: BTreeMap<String, BTreeMap<String, String>>,
|
pub badges: BTreeMap<String, BTreeMap<String, String>>,
|
||||||
pub links: Option<String>,
|
pub links: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub v: Option<u32>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
|
|
@ -15,8 +15,6 @@ Deprecated, use `cargo metadata --no-deps` instead.\
|
||||||
|
|
||||||
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
||||||
let ws = args.workspace(config)?;
|
let ws = args.workspace(config)?;
|
||||||
config
|
config.shell().print_json(&ws.current()?.serialized())?;
|
||||||
.shell()
|
|
||||||
.print_json(&ws.current()?.serialized(config))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -642,7 +642,6 @@ unstable_cli_options!(
|
||||||
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
|
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
|
||||||
mtime_on_use: bool = ("Configure Cargo to update the mtime of used files"),
|
mtime_on_use: bool = ("Configure Cargo to update the mtime of used files"),
|
||||||
multitarget: bool = ("Allow passing multiple `--target` flags to the cargo subcommand selected"),
|
multitarget: bool = ("Allow passing multiple `--target` flags to the cargo subcommand selected"),
|
||||||
namespaced_features: bool = ("Allow features with `dep:` prefix"),
|
|
||||||
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
|
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
|
||||||
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
|
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
|
||||||
host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
|
host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
|
||||||
|
@ -652,7 +651,6 @@ unstable_cli_options!(
|
||||||
terminal_width: Option<Option<usize>> = ("Provide a terminal width to rustc for error truncation"),
|
terminal_width: Option<Option<usize>> = ("Provide a terminal width to rustc for error truncation"),
|
||||||
timings: Option<Vec<String>> = ("Display concurrency information"),
|
timings: Option<Vec<String>> = ("Display concurrency information"),
|
||||||
unstable_options: bool = ("Allow the usage of unstable options"),
|
unstable_options: bool = ("Allow the usage of unstable options"),
|
||||||
weak_dep_features: bool = ("Allow `dep_name?/feature` feature syntax"),
|
|
||||||
// TODO(wcrichto): move scrape example configuration into Cargo.toml before stabilization
|
// TODO(wcrichto): move scrape example configuration into Cargo.toml before stabilization
|
||||||
// See: https://github.com/rust-lang/cargo/pull/9525#discussion_r728470927
|
// See: https://github.com/rust-lang/cargo/pull/9525#discussion_r728470927
|
||||||
rustdoc_scrape_examples: Option<String> = ("Allow rustdoc to scrape examples from reverse-dependencies for documentation"),
|
rustdoc_scrape_examples: Option<String> = ("Allow rustdoc to scrape examples from reverse-dependencies for documentation"),
|
||||||
|
@ -707,6 +705,10 @@ const STABILIZED_NAMED_PROFILES: &str = "The named-profiles feature is now alway
|
||||||
const STABILIZED_FUTURE_INCOMPAT_REPORT: &str =
|
const STABILIZED_FUTURE_INCOMPAT_REPORT: &str =
|
||||||
"The future-incompat-report feature is now always enabled.";
|
"The future-incompat-report feature is now always enabled.";
|
||||||
|
|
||||||
|
const STABILIZED_WEAK_DEP_FEATURES: &str = "Weak dependency features are now always available.";
|
||||||
|
|
||||||
|
const STABILISED_NAMESPACED_FEATURES: &str = "Namespaced features are now always available.";
|
||||||
|
|
||||||
fn deserialize_build_std<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
|
fn deserialize_build_std<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
|
@ -873,8 +875,8 @@ impl CliUnstable {
|
||||||
"multitarget" => self.multitarget = parse_empty(k, v)?,
|
"multitarget" => self.multitarget = parse_empty(k, v)?,
|
||||||
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
|
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
|
||||||
"terminal-width" => self.terminal_width = Some(parse_usize_opt(v)?),
|
"terminal-width" => self.terminal_width = Some(parse_usize_opt(v)?),
|
||||||
"namespaced-features" => self.namespaced_features = parse_empty(k, v)?,
|
"namespaced-features" => stabilized_warn(k, "1.60", STABILISED_NAMESPACED_FEATURES),
|
||||||
"weak-dep-features" => self.weak_dep_features = parse_empty(k, v)?,
|
"weak-dep-features" => stabilized_warn(k, "1.60", STABILIZED_WEAK_DEP_FEATURES),
|
||||||
"credential-process" => self.credential_process = parse_empty(k, v)?,
|
"credential-process" => self.credential_process = parse_empty(k, v)?,
|
||||||
"rustdoc-scrape-examples" => {
|
"rustdoc-scrape-examples" => {
|
||||||
if let Some(s) = v {
|
if let Some(s) = v {
|
||||||
|
|
|
@ -208,7 +208,7 @@ impl Package {
|
||||||
self.targets().iter().any(|t| t.is_example() || t.is_bin())
|
self.targets().iter().any(|t| t.is_example() || t.is_bin())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialized(&self, config: &Config) -> SerializedPackage {
|
pub fn serialized(&self) -> SerializedPackage {
|
||||||
let summary = self.manifest().summary();
|
let summary = self.manifest().summary();
|
||||||
let package_id = summary.package_id();
|
let package_id = summary.package_id();
|
||||||
let manmeta = self.manifest().metadata();
|
let manmeta = self.manifest().metadata();
|
||||||
|
@ -222,27 +222,19 @@ impl Package {
|
||||||
.filter(|t| t.src_path().is_path())
|
.filter(|t| t.src_path().is_path())
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
let features = if config.cli_unstable().namespaced_features {
|
// Convert Vec<FeatureValue> to Vec<InternedString>
|
||||||
// Convert Vec<FeatureValue> to Vec<InternedString>
|
let features = summary
|
||||||
summary
|
.features()
|
||||||
.features()
|
.iter()
|
||||||
.iter()
|
.map(|(k, v)| {
|
||||||
.map(|(k, v)| {
|
(
|
||||||
(
|
*k,
|
||||||
*k,
|
v.iter()
|
||||||
v.iter()
|
.map(|fv| InternedString::new(&fv.to_string()))
|
||||||
.map(|fv| InternedString::new(&fv.to_string()))
|
.collect(),
|
||||||
.collect(),
|
)
|
||||||
)
|
})
|
||||||
})
|
.collect();
|
||||||
.collect()
|
|
||||||
} else {
|
|
||||||
self.manifest()
|
|
||||||
.original()
|
|
||||||
.features()
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
|
||||||
|
|
||||||
SerializedPackage {
|
SerializedPackage {
|
||||||
name: package_id.name(),
|
name: package_id.name(),
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
//! Feature resolver.
|
//! Feature resolver.
|
||||||
//!
|
//!
|
||||||
//! This is a new feature resolver that runs independently of the main
|
//! This is a new feature resolver that runs independently of the main
|
||||||
//! dependency resolver. It is enabled when the user specifies `resolver =
|
//! dependency resolver. It has several options which can enable new feature
|
||||||
//! "2"` in `Cargo.toml`.
|
//! resolution behavior.
|
||||||
//!
|
//!
|
||||||
//! One of its key characteristics is that it can avoid unifying features for
|
//! One of its key characteristics is that it can avoid unifying features for
|
||||||
//! shared dependencies in some situations. See `FeatureOpts` for the
|
//! shared dependencies in some situations. See `FeatureOpts` for the
|
||||||
//! different behaviors that can be enabled. If no extra options are enabled,
|
//! different behaviors that can be enabled. If no extra options are enabled,
|
||||||
//! then it should behave exactly the same as the dependency resolver's
|
//! then it should behave exactly the same as the dependency resolver's
|
||||||
//! feature resolution. This can be verified by setting the
|
//! feature resolution.
|
||||||
//! `__CARGO_FORCE_NEW_FEATURES=compare` environment variable and running
|
|
||||||
//! Cargo's test suite (or building other projects), and checking if it
|
|
||||||
//! panics. Note: the `features2` tests will fail because they intentionally
|
|
||||||
//! compare the old vs new behavior, so forcing the old behavior will
|
|
||||||
//! naturally fail the tests.
|
|
||||||
//!
|
//!
|
||||||
//! The preferred way to engage this new resolver is via
|
//! The preferred way to engage this new resolver is via
|
||||||
//! `resolve_ws_with_opts`.
|
//! `resolve_ws_with_opts`.
|
||||||
|
@ -59,22 +54,12 @@ pub struct ResolvedFeatures {
|
||||||
///
|
///
|
||||||
/// The value is the `name_in_toml` of the dependencies.
|
/// The value is the `name_in_toml` of the dependencies.
|
||||||
activated_dependencies: ActivateMap,
|
activated_dependencies: ActivateMap,
|
||||||
/// This is only here for legacy support when the new resolver is not enabled.
|
|
||||||
///
|
|
||||||
/// This is the set of features enabled for each package.
|
|
||||||
legacy_features: Option<HashMap<PackageId, Vec<InternedString>>>,
|
|
||||||
/// This is only here for legacy support when the new resolver is not enabled.
|
|
||||||
///
|
|
||||||
/// This is the set of optional dependencies enabled for each package.
|
|
||||||
legacy_dependencies: Option<HashMap<PackageId, HashSet<InternedString>>>,
|
|
||||||
opts: FeatureOpts,
|
opts: FeatureOpts,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options for how the feature resolver works.
|
/// Options for how the feature resolver works.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct FeatureOpts {
|
pub struct FeatureOpts {
|
||||||
/// Use the new resolver instead of the old one.
|
|
||||||
new_resolver: bool,
|
|
||||||
/// Build deps and proc-macros will not share share features with other dep kinds.
|
/// Build deps and proc-macros will not share share features with other dep kinds.
|
||||||
decouple_host_deps: bool,
|
decouple_host_deps: bool,
|
||||||
/// Dev dep features will not be activated unless needed.
|
/// Dev dep features will not be activated unless needed.
|
||||||
|
@ -132,7 +117,6 @@ impl FeatureOpts {
|
||||||
let mut opts = FeatureOpts::default();
|
let mut opts = FeatureOpts::default();
|
||||||
let unstable_flags = ws.config().cli_unstable();
|
let unstable_flags = ws.config().cli_unstable();
|
||||||
let mut enable = |feat_opts: &Vec<String>| {
|
let mut enable = |feat_opts: &Vec<String>| {
|
||||||
opts.new_resolver = true;
|
|
||||||
for opt in feat_opts {
|
for opt in feat_opts {
|
||||||
match opt.as_ref() {
|
match opt.as_ref() {
|
||||||
"build_dep" | "host_dep" => opts.decouple_host_deps = true,
|
"build_dep" | "host_dep" => opts.decouple_host_deps = true,
|
||||||
|
@ -159,15 +143,6 @@ impl FeatureOpts {
|
||||||
enable(&vec!["all".to_string()]).unwrap();
|
enable(&vec!["all".to_string()]).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This env var is intended for testing only.
|
|
||||||
if let Ok(env_opts) = std::env::var("__CARGO_FORCE_NEW_FEATURES") {
|
|
||||||
if env_opts == "1" {
|
|
||||||
opts.new_resolver = true;
|
|
||||||
} else {
|
|
||||||
let env_opts = env_opts.split(',').map(|s| s.to_string()).collect();
|
|
||||||
enable(&env_opts)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let HasDevUnits::Yes = has_dev_units {
|
if let HasDevUnits::Yes = has_dev_units {
|
||||||
// Dev deps cannot be decoupled when they are in use.
|
// Dev deps cannot be decoupled when they are in use.
|
||||||
opts.decouple_dev_deps = false;
|
opts.decouple_dev_deps = false;
|
||||||
|
@ -175,10 +150,6 @@ impl FeatureOpts {
|
||||||
if let ForceAllTargets::Yes = force_all_targets {
|
if let ForceAllTargets::Yes = force_all_targets {
|
||||||
opts.ignore_inactive_targets = false;
|
opts.ignore_inactive_targets = false;
|
||||||
}
|
}
|
||||||
if unstable_flags.weak_dep_features {
|
|
||||||
// Force this ON because it only works with the new resolver.
|
|
||||||
opts.new_resolver = true;
|
|
||||||
}
|
|
||||||
Ok(opts)
|
Ok(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +158,6 @@ impl FeatureOpts {
|
||||||
match behavior {
|
match behavior {
|
||||||
ResolveBehavior::V1 => FeatureOpts::default(),
|
ResolveBehavior::V1 => FeatureOpts::default(),
|
||||||
ResolveBehavior::V2 => FeatureOpts {
|
ResolveBehavior::V2 => FeatureOpts {
|
||||||
new_resolver: true,
|
|
||||||
decouple_host_deps: true,
|
decouple_host_deps: true,
|
||||||
decouple_dev_deps: has_dev_units == HasDevUnits::No,
|
decouple_dev_deps: has_dev_units == HasDevUnits::No,
|
||||||
ignore_inactive_targets: true,
|
ignore_inactive_targets: true,
|
||||||
|
@ -306,18 +276,11 @@ impl ResolvedFeatures {
|
||||||
features_for: FeaturesFor,
|
features_for: FeaturesFor,
|
||||||
dep_name: InternedString,
|
dep_name: InternedString,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let Some(legacy) = &self.legacy_dependencies {
|
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
||||||
legacy
|
self.activated_dependencies
|
||||||
.get(&pkg_id)
|
.get(&(pkg_id, is_build))
|
||||||
.map(|deps| deps.contains(&dep_name))
|
.map(|deps| deps.contains(&dep_name))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
} else {
|
|
||||||
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
|
||||||
self.activated_dependencies
|
|
||||||
.get(&(pkg_id, is_build))
|
|
||||||
.map(|deps| deps.contains(&dep_name))
|
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Variant of `activated_features` that returns `None` if this is
|
/// Variant of `activated_features` that returns `None` if this is
|
||||||
|
@ -336,15 +299,11 @@ impl ResolvedFeatures {
|
||||||
pkg_id: PackageId,
|
pkg_id: PackageId,
|
||||||
features_for: FeaturesFor,
|
features_for: FeaturesFor,
|
||||||
) -> CargoResult<Vec<InternedString>> {
|
) -> CargoResult<Vec<InternedString>> {
|
||||||
if let Some(legacy) = &self.legacy_features {
|
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
||||||
Ok(legacy.get(&pkg_id).map_or_else(Vec::new, |v| v.clone()))
|
if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
|
||||||
|
Ok(fs.iter().cloned().collect())
|
||||||
} else {
|
} else {
|
||||||
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
bail!("features did not find {:?} {:?}", pkg_id, is_build)
|
||||||
if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
|
|
||||||
Ok(fs.iter().cloned().collect())
|
|
||||||
} else {
|
|
||||||
bail!("features did not find {:?} {:?}", pkg_id, is_build)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,14 +311,16 @@ impl ResolvedFeatures {
|
||||||
///
|
///
|
||||||
/// Used by `cargo fix --edition` to display any differences.
|
/// Used by `cargo fix --edition` to display any differences.
|
||||||
pub fn compare_legacy(&self, legacy: &ResolvedFeatures) -> DiffMap {
|
pub fn compare_legacy(&self, legacy: &ResolvedFeatures) -> DiffMap {
|
||||||
let legacy_features = legacy.legacy_features.as_ref().unwrap();
|
|
||||||
self.activated_features
|
self.activated_features
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|((pkg_id, for_host), new_features)| {
|
.filter_map(|((pkg_id, for_host), new_features)| {
|
||||||
let old_features = match legacy_features.get(pkg_id) {
|
let old_features = legacy
|
||||||
Some(feats) => feats.iter().cloned().collect(),
|
.activated_features
|
||||||
None => BTreeSet::new(),
|
.get(&(*pkg_id, *for_host))
|
||||||
};
|
// The new features may have for_host entries where the old one does not.
|
||||||
|
.or_else(|| legacy.activated_features.get(&(*pkg_id, false)))
|
||||||
|
.map(|feats| feats.iter().cloned().collect())
|
||||||
|
.unwrap_or_else(|| BTreeSet::new());
|
||||||
// The new resolver should never add features.
|
// The new resolver should never add features.
|
||||||
assert_eq!(new_features.difference(&old_features).next(), None);
|
assert_eq!(new_features.difference(&old_features).next(), None);
|
||||||
let removed_features: BTreeSet<_> =
|
let removed_features: BTreeSet<_> =
|
||||||
|
@ -427,17 +388,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
||||||
) -> CargoResult<ResolvedFeatures> {
|
) -> CargoResult<ResolvedFeatures> {
|
||||||
use crate::util::profile;
|
use crate::util::profile;
|
||||||
let _p = profile::start("resolve features");
|
let _p = profile::start("resolve features");
|
||||||
|
|
||||||
if !opts.new_resolver {
|
|
||||||
// Legacy mode.
|
|
||||||
return Ok(ResolvedFeatures {
|
|
||||||
activated_features: HashMap::new(),
|
|
||||||
activated_dependencies: HashMap::new(),
|
|
||||||
legacy_features: Some(resolve.features_clone()),
|
|
||||||
legacy_dependencies: Some(compute_legacy_deps(resolve)),
|
|
||||||
opts,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let track_for_host = opts.decouple_host_deps || opts.ignore_inactive_targets;
|
let track_for_host = opts.decouple_host_deps || opts.ignore_inactive_targets;
|
||||||
let mut r = FeatureResolver {
|
let mut r = FeatureResolver {
|
||||||
ws,
|
ws,
|
||||||
|
@ -460,8 +410,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
||||||
Ok(ResolvedFeatures {
|
Ok(ResolvedFeatures {
|
||||||
activated_features: r.activated_features,
|
activated_features: r.activated_features,
|
||||||
activated_dependencies: r.activated_dependencies,
|
activated_dependencies: r.activated_dependencies,
|
||||||
legacy_features: None,
|
|
||||||
legacy_dependencies: None,
|
|
||||||
opts: r.opts,
|
opts: r.opts,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -826,19 +774,3 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
||||||
.proc_macro()
|
.proc_macro()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes a map of PackageId to the set of optional dependencies that are
|
|
||||||
/// enabled for that dep (when the new resolver is not enabled).
|
|
||||||
fn compute_legacy_deps(resolve: &Resolve) -> HashMap<PackageId, HashSet<InternedString>> {
|
|
||||||
let mut result: HashMap<PackageId, HashSet<InternedString>> = HashMap::new();
|
|
||||||
for pkg_id in resolve.iter() {
|
|
||||||
for (_dep_id, deps) in resolve.deps(pkg_id) {
|
|
||||||
for dep in deps {
|
|
||||||
if dep.is_optional() {
|
|
||||||
result.entry(pkg_id).or_default().insert(dep.name_in_toml());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,8 +23,6 @@ struct Inner {
|
||||||
package_id: PackageId,
|
package_id: PackageId,
|
||||||
dependencies: Vec<Dependency>,
|
dependencies: Vec<Dependency>,
|
||||||
features: Rc<FeatureMap>,
|
features: Rc<FeatureMap>,
|
||||||
has_namespaced_features: bool,
|
|
||||||
has_overlapping_features: Option<InternedString>,
|
|
||||||
checksum: Option<String>,
|
checksum: Option<String>,
|
||||||
links: Option<InternedString>,
|
links: Option<InternedString>,
|
||||||
}
|
}
|
||||||
|
@ -37,15 +35,11 @@ impl Summary {
|
||||||
features: &BTreeMap<InternedString, Vec<InternedString>>,
|
features: &BTreeMap<InternedString, Vec<InternedString>>,
|
||||||
links: Option<impl Into<InternedString>>,
|
links: Option<impl Into<InternedString>>,
|
||||||
) -> CargoResult<Summary> {
|
) -> CargoResult<Summary> {
|
||||||
// ****CAUTION**** If you change anything here than may raise a new
|
// ****CAUTION**** If you change anything here that may raise a new
|
||||||
// error, be sure to coordinate that change with either the index
|
// error, be sure to coordinate that change with either the index
|
||||||
// schema field or the SummariesCache version.
|
// schema field or the SummariesCache version.
|
||||||
let mut has_overlapping_features = None;
|
|
||||||
for dep in dependencies.iter() {
|
for dep in dependencies.iter() {
|
||||||
let dep_name = dep.name_in_toml();
|
let dep_name = dep.name_in_toml();
|
||||||
if features.contains_key(&dep_name) {
|
|
||||||
has_overlapping_features = Some(dep_name);
|
|
||||||
}
|
|
||||||
if dep.is_optional() && !dep.is_transitive() {
|
if dep.is_optional() && !dep.is_transitive() {
|
||||||
bail!(
|
bail!(
|
||||||
"dev-dependencies are not allowed to be optional: `{}`",
|
"dev-dependencies are not allowed to be optional: `{}`",
|
||||||
|
@ -53,8 +47,7 @@ impl Summary {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (feature_map, has_namespaced_features) =
|
let feature_map = build_feature_map(config, pkg_id, features, &dependencies)?;
|
||||||
build_feature_map(config, pkg_id, features, &dependencies)?;
|
|
||||||
Ok(Summary {
|
Ok(Summary {
|
||||||
inner: Rc::new(Inner {
|
inner: Rc::new(Inner {
|
||||||
package_id: pkg_id,
|
package_id: pkg_id,
|
||||||
|
@ -62,8 +55,6 @@ impl Summary {
|
||||||
features: Rc::new(feature_map),
|
features: Rc::new(feature_map),
|
||||||
checksum: None,
|
checksum: None,
|
||||||
links: links.map(|l| l.into()),
|
links: links.map(|l| l.into()),
|
||||||
has_namespaced_features,
|
|
||||||
has_overlapping_features,
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -87,46 +78,6 @@ impl Summary {
|
||||||
&self.inner.features
|
&self.inner.features
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an error if this Summary is using an unstable feature that is
|
|
||||||
/// not enabled.
|
|
||||||
pub fn unstable_gate(
|
|
||||||
&self,
|
|
||||||
namespaced_features: bool,
|
|
||||||
weak_dep_features: bool,
|
|
||||||
) -> CargoResult<()> {
|
|
||||||
if !namespaced_features {
|
|
||||||
if self.inner.has_namespaced_features {
|
|
||||||
bail!(
|
|
||||||
"namespaced features with the `dep:` prefix are only allowed on \
|
|
||||||
the nightly channel and requires the `-Z namespaced-features` flag on the command-line"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if let Some(dep_name) = self.inner.has_overlapping_features {
|
|
||||||
bail!(
|
|
||||||
"features and dependencies cannot have the same name: `{}`",
|
|
||||||
dep_name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !weak_dep_features {
|
|
||||||
for (feat_name, features) in self.features() {
|
|
||||||
for fv in features {
|
|
||||||
if matches!(fv, FeatureValue::DepFeature { weak: true, .. }) {
|
|
||||||
bail!(
|
|
||||||
"optional dependency features with `?` syntax are only \
|
|
||||||
allowed on the nightly channel and requires the \
|
|
||||||
`-Z weak-dep-features` flag on the command line\n\
|
|
||||||
Feature `{}` had feature value `{}`.",
|
|
||||||
feat_name,
|
|
||||||
fv
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn checksum(&self) -> Option<&str> {
|
pub fn checksum(&self) -> Option<&str> {
|
||||||
self.inner.checksum.as_deref()
|
self.inner.checksum.as_deref()
|
||||||
}
|
}
|
||||||
|
@ -181,16 +132,12 @@ impl Hash for Summary {
|
||||||
|
|
||||||
/// Checks features for errors, bailing out a CargoResult:Err if invalid,
|
/// Checks features for errors, bailing out a CargoResult:Err if invalid,
|
||||||
/// and creates FeatureValues for each feature.
|
/// and creates FeatureValues for each feature.
|
||||||
///
|
|
||||||
/// The returned `bool` indicates whether or not the `[features]` table
|
|
||||||
/// included a `dep:` prefixed namespaced feature (used for gating on
|
|
||||||
/// nightly).
|
|
||||||
fn build_feature_map(
|
fn build_feature_map(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
pkg_id: PackageId,
|
pkg_id: PackageId,
|
||||||
features: &BTreeMap<InternedString, Vec<InternedString>>,
|
features: &BTreeMap<InternedString, Vec<InternedString>>,
|
||||||
dependencies: &[Dependency],
|
dependencies: &[Dependency],
|
||||||
) -> CargoResult<(FeatureMap, bool)> {
|
) -> CargoResult<FeatureMap> {
|
||||||
use self::FeatureValue::*;
|
use self::FeatureValue::*;
|
||||||
let mut dep_map = HashMap::new();
|
let mut dep_map = HashMap::new();
|
||||||
for dep in dependencies.iter() {
|
for dep in dependencies.iter() {
|
||||||
|
@ -210,7 +157,6 @@ fn build_feature_map(
|
||||||
(*feature, fvs)
|
(*feature, fvs)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let has_namespaced_features = map.values().flatten().any(|fv| fv.has_dep_prefix());
|
|
||||||
|
|
||||||
// Add implicit features for optional dependencies if they weren't
|
// Add implicit features for optional dependencies if they weren't
|
||||||
// explicitly listed anywhere.
|
// explicitly listed anywhere.
|
||||||
|
@ -372,7 +318,7 @@ fn build_feature_map(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((map, has_namespaced_features))
|
Ok(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FeatureValue represents the types of dependencies a feature can have.
|
/// FeatureValue represents the types of dependencies a feature can have.
|
||||||
|
|
|
@ -31,9 +31,8 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
|
||||||
VERSION
|
VERSION
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let config = ws.config();
|
|
||||||
let (packages, resolve) = if opt.no_deps {
|
let (packages, resolve) = if opt.no_deps {
|
||||||
let packages = ws.members().map(|pkg| pkg.serialized(config)).collect();
|
let packages = ws.members().map(|pkg| pkg.serialized()).collect();
|
||||||
(packages, None)
|
(packages, None)
|
||||||
} else {
|
} else {
|
||||||
let (packages, resolve) = build_resolve_graph(ws, opt)?;
|
let (packages, resolve) = build_resolve_graph(ws, opt)?;
|
||||||
|
@ -152,11 +151,10 @@ fn build_resolve_graph(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Get a Vec of Packages.
|
// Get a Vec of Packages.
|
||||||
let config = ws.config();
|
|
||||||
let actual_packages = package_map
|
let actual_packages = package_map
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
|
.filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
|
||||||
.map(|pkg| pkg.serialized(config))
|
.map(|pkg| pkg.serialized())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mr = MetadataResolve {
|
let mr = MetadataResolve {
|
||||||
|
|
|
@ -287,7 +287,6 @@ fn transmit(
|
||||||
license_file: license_file.clone(),
|
license_file: license_file.clone(),
|
||||||
badges: badges.clone(),
|
badges: badges.clone(),
|
||||||
links: links.clone(),
|
links: links.clone(),
|
||||||
v: None,
|
|
||||||
},
|
},
|
||||||
tarball,
|
tarball,
|
||||||
)
|
)
|
||||||
|
|
|
@ -293,8 +293,6 @@ impl<'cfg> RegistryIndex<'cfg> {
|
||||||
{
|
{
|
||||||
let source_id = self.source_id;
|
let source_id = self.source_id;
|
||||||
let config = self.config;
|
let config = self.config;
|
||||||
let namespaced_features = self.config.cli_unstable().namespaced_features;
|
|
||||||
let weak_dep_features = self.config.cli_unstable().weak_dep_features;
|
|
||||||
|
|
||||||
// First up actually parse what summaries we have available. If Cargo
|
// First up actually parse what summaries we have available. If Cargo
|
||||||
// has run previously this will parse a Cargo-specific cache file rather
|
// has run previously this will parse a Cargo-specific cache file rather
|
||||||
|
@ -309,11 +307,6 @@ impl<'cfg> RegistryIndex<'cfg> {
|
||||||
// minimize the amount of work being done here and parse as little as
|
// minimize the amount of work being done here and parse as little as
|
||||||
// necessary.
|
// necessary.
|
||||||
let raw_data = &summaries.raw_data;
|
let raw_data = &summaries.raw_data;
|
||||||
let max_version = if namespaced_features || weak_dep_features {
|
|
||||||
INDEX_V_MAX
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
};
|
|
||||||
Ok(summaries
|
Ok(summaries
|
||||||
.versions
|
.versions
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -328,7 +321,7 @@ impl<'cfg> RegistryIndex<'cfg> {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.filter(move |is| {
|
.filter(move |is| {
|
||||||
if is.v > max_version {
|
if is.v > INDEX_V_MAX {
|
||||||
debug!(
|
debug!(
|
||||||
"unsupported schema version {} ({} {})",
|
"unsupported schema version {} ({} {})",
|
||||||
is.v,
|
is.v,
|
||||||
|
@ -339,11 +332,6 @@ impl<'cfg> RegistryIndex<'cfg> {
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.filter(move |is| {
|
|
||||||
is.summary
|
|
||||||
.unstable_gate(namespaced_features, weak_dep_features)
|
|
||||||
.is_ok()
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1299,8 +1299,6 @@ impl TomlManifest {
|
||||||
me.features.as_ref().unwrap_or(&empty_features),
|
me.features.as_ref().unwrap_or(&empty_features),
|
||||||
project.links.as_deref(),
|
project.links.as_deref(),
|
||||||
)?;
|
)?;
|
||||||
let unstable = config.cli_unstable();
|
|
||||||
summary.unstable_gate(unstable.namespaced_features, unstable.weak_dep_features)?;
|
|
||||||
|
|
||||||
let metadata = ManifestMetadata {
|
let metadata = ManifestMetadata {
|
||||||
description: project.description.clone(),
|
description: project.description.clone(),
|
||||||
|
|
|
@ -116,21 +116,33 @@ an external package to handle GIF images. This can be expressed like this:
|
||||||
gif = { version = "0.11.1", optional = true }
|
gif = { version = "0.11.1", optional = true }
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional dependencies implicitly define a feature of the same name as the
|
By default, this optional dependency implicitly defines a feature that looks
|
||||||
dependency. This means that the same `cfg(feature = "gif")` syntax can be used
|
like this:
|
||||||
in the code, and the dependency can be enabled just like a feature such as
|
|
||||||
`--features gif` (see [Command-line feature
|
|
||||||
options](#command-line-feature-options) below).
|
|
||||||
|
|
||||||
> **Note**: A feature in the `[feature]` table cannot use the same name as a
|
```toml
|
||||||
> dependency. Experimental support for enabling this and other extensions is
|
[features]
|
||||||
> available on the nightly channel via [namespaced
|
gif = ["dep:gif"]
|
||||||
> features](unstable.md#namespaced-features).
|
```
|
||||||
|
|
||||||
Explicitly defined features can enable optional dependencies, too. Just
|
This means that this dependency will only be included if the `gif`
|
||||||
include the name of the optional dependency in the feature list. For example,
|
feature is enabled.
|
||||||
let's say in order to support the AVIF image format, our library needs two
|
The same `cfg(feature = "gif")` syntax can be used in the code, and the
|
||||||
other dependencies to be enabled:
|
dependency can be enabled just like any feature such as `--features gif` (see
|
||||||
|
[Command-line feature options](#command-line-feature-options) below).
|
||||||
|
|
||||||
|
In some cases, you may not want to expose a feature that has the same name
|
||||||
|
as the optional dependency.
|
||||||
|
For example, perhaps the optional dependency is an internal detail, or you
|
||||||
|
want to group multiple optional dependencies together, or you just want to use
|
||||||
|
a better name.
|
||||||
|
If you specify the optional dependency with the `dep:` prefix anywhere
|
||||||
|
in the `[features]` table, that disables the implicit feature.
|
||||||
|
|
||||||
|
> **Note**: The `dep:` syntax is only available starting with Rust 1.60.
|
||||||
|
> Previous versions can only use the implicit feature name.
|
||||||
|
|
||||||
|
For example, let's say in order to support the AVIF image format, our library
|
||||||
|
needs two other dependencies to be enabled:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -138,10 +150,13 @@ ravif = { version = "0.6.3", optional = true }
|
||||||
rgb = { version = "0.8.25", optional = true }
|
rgb = { version = "0.8.25", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
avif = ["ravif", "rgb"]
|
avif = ["dep:ravif", "dep:rgb"]
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example, the `avif` feature will enable the two listed dependencies.
|
In this example, the `avif` feature will enable the two listed dependencies.
|
||||||
|
This also avoids creating the implicit `ravif` and `rgb` features, since we
|
||||||
|
don't want users to enable those individually as they are internal details to
|
||||||
|
our crate.
|
||||||
|
|
||||||
> **Note**: Another way to optionally include a dependency is to use
|
> **Note**: Another way to optionally include a dependency is to use
|
||||||
> [platform-specific dependencies]. Instead of using features, these are
|
> [platform-specific dependencies]. Instead of using features, these are
|
||||||
|
@ -185,10 +200,31 @@ jpeg-decoder = { version = "0.1.20", default-features = false }
|
||||||
parallel = ["jpeg-decoder/rayon"]
|
parallel = ["jpeg-decoder/rayon"]
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note**: The `"package-name/feature-name"` syntax will also enable
|
The `"package-name/feature-name"` syntax will also enable `package-name`
|
||||||
> `package-name` if it is an optional dependency. Experimental support for
|
if it is an optional dependency. Often this is not what you want.
|
||||||
> disabling that behavior is available on the nightly channel via [weak
|
You can add a `?` as in `"package-name?/feature-name"` which will only enable
|
||||||
> dependency features](unstable.md#weak-dependency-features).
|
the given feature if something else enables the optional dependency.
|
||||||
|
|
||||||
|
> **Note**: The `?` syntax is only available starting with Rust 1.60.
|
||||||
|
|
||||||
|
For example, let's say we have added some serialization support to our
|
||||||
|
library, and it requires enabling a corresponding feature in some optional
|
||||||
|
dependencies.
|
||||||
|
That can be done like this:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1.0.133", optional = true }
|
||||||
|
rgb = { version = "0.8.25", optional = true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
serde = ["dep:serde", "rgb?/serde"]
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, enabling the `serde` feature will enable the serde
|
||||||
|
dependency.
|
||||||
|
It will also enable the `serde` feature for the `rgb` dependency, but only if
|
||||||
|
something else has enabled the `rgb` dependency.
|
||||||
|
|
||||||
### Command-line feature options
|
### Command-line feature options
|
||||||
|
|
||||||
|
|
|
@ -263,7 +263,45 @@ explaining the format of the entry.
|
||||||
"yanked": false,
|
"yanked": false,
|
||||||
// The `links` string value from the package's manifest, or null if not
|
// The `links` string value from the package's manifest, or null if not
|
||||||
// specified. This field is optional and defaults to null.
|
// specified. This field is optional and defaults to null.
|
||||||
"links": null
|
"links": null,
|
||||||
|
// An unsigned 32-bit integer value indicating the schema version of this
|
||||||
|
// entry.
|
||||||
|
//
|
||||||
|
// If this not specified, it should be interpreted as the default of 1.
|
||||||
|
//
|
||||||
|
// Cargo (starting with version 1.51) will ignore versions it does not
|
||||||
|
// recognize. This provides a method to safely introduce changes to index
|
||||||
|
// entries and allow older versions of cargo to ignore newer entries it
|
||||||
|
// doesn't understand. Versions older than 1.51 ignore this field, and
|
||||||
|
// thus may misinterpret the meaning of the index entry.
|
||||||
|
//
|
||||||
|
// The current values are:
|
||||||
|
//
|
||||||
|
// * 1: The schema as documented here, not including newer additions.
|
||||||
|
// This is honored in Rust version 1.51 and newer.
|
||||||
|
// * 2: The addition of the `features2` field.
|
||||||
|
// This is honored in Rust version 1.60 and newer.
|
||||||
|
"v": 2,
|
||||||
|
// This optional field contains features with new, extended syntax.
|
||||||
|
// Specifically, namespaced features (`dep:`) and weak dependencies
|
||||||
|
// (`pkg?/feat`).
|
||||||
|
//
|
||||||
|
// This is separated from `features` because versions older than 1.19
|
||||||
|
// will fail to load due to not being able to parse the new syntax, even
|
||||||
|
// with a `Cargo.lock` file.
|
||||||
|
//
|
||||||
|
// Cargo will merge any values listed here with the "features" field.
|
||||||
|
//
|
||||||
|
// If this field is included, the "v" field should be set to at least 2.
|
||||||
|
//
|
||||||
|
// Registries are not required to use this field for extended feature
|
||||||
|
// syntax, they are allowed to include those in the "features" field.
|
||||||
|
// Using this is only necessary if the registry wants to support cargo
|
||||||
|
// versions older than 1.19, which in practice is only crates.io since
|
||||||
|
// those older versions do not support other registries.
|
||||||
|
"features2": {
|
||||||
|
"serde": ["dep:serde", "chrono?/serde"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,6 @@ Each new feature described below should explain how to use it.
|
||||||
* [avoid-dev-deps](#avoid-dev-deps) — Prevents the resolver from including dev-dependencies during resolution.
|
* [avoid-dev-deps](#avoid-dev-deps) — Prevents the resolver from including dev-dependencies during resolution.
|
||||||
* [minimal-versions](#minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest.
|
* [minimal-versions](#minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest.
|
||||||
* [public-dependency](#public-dependency) — Allows dependencies to be classified as either public or private.
|
* [public-dependency](#public-dependency) — Allows dependencies to be classified as either public or private.
|
||||||
* [Namespaced features](#namespaced-features) — Separates optional dependencies into a separate namespace from regular features, and allows feature names to be the same as some dependency name.
|
|
||||||
* [Weak dependency features](#weak-dependency-features) — Allows setting features for dependencies without enabling optional dependencies.
|
|
||||||
* Output behavior
|
* Output behavior
|
||||||
* [out-dir](#out-dir) — Adds a directory where artifacts are copied to.
|
* [out-dir](#out-dir) — Adds a directory where artifacts are copied to.
|
||||||
* [terminal-width](#terminal-width) — Tells rustc the width of the terminal so that long diagnostic messages can be truncated to be more readable.
|
* [terminal-width](#terminal-width) — Tells rustc the width of the terminal so that long diagnostic messages can be truncated to be more readable.
|
||||||
|
@ -252,68 +250,6 @@ dir-name = "lto" # Emits to target/lto instead of target/release-lto
|
||||||
lto = true
|
lto = true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Namespaced features
|
|
||||||
* Original issue: [#1286](https://github.com/rust-lang/cargo/issues/1286)
|
|
||||||
* Tracking Issue: [#5565](https://github.com/rust-lang/cargo/issues/5565)
|
|
||||||
|
|
||||||
The `namespaced-features` option makes two changes to how features can be
|
|
||||||
specified:
|
|
||||||
|
|
||||||
* Features may now be defined with the same name as a dependency.
|
|
||||||
* Optional dependencies can be explicitly enabled in the `[features]` table
|
|
||||||
with the `dep:` prefix, which enables the dependency without enabling a
|
|
||||||
feature of the same name.
|
|
||||||
|
|
||||||
By default, an optional dependency `foo` will define a feature `foo =
|
|
||||||
["dep:foo"]` *unless* `dep:foo` is mentioned in any other feature, or the
|
|
||||||
`foo` feature is already defined. This helps prevent unnecessary boilerplate
|
|
||||||
of listing every optional dependency, but still allows you to override the
|
|
||||||
implicit feature.
|
|
||||||
|
|
||||||
This allows two use cases that were previously not possible:
|
|
||||||
|
|
||||||
* You can "hide" an optional dependency, so that external users cannot
|
|
||||||
explicitly enable that optional dependency.
|
|
||||||
* There is no longer a need to create "funky" feature names to work around the
|
|
||||||
restriction that features cannot shadow dependency names.
|
|
||||||
|
|
||||||
To enable namespaced-features, use the `-Z namespaced-features` command-line
|
|
||||||
flag.
|
|
||||||
|
|
||||||
An example of hiding an optional dependency:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
regex = { version = "1.4.1", optional = true }
|
|
||||||
lazy_static = { version = "1.4.0", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
regex = ["dep:regex", "dep:lazy_static"]
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example, the "regex" feature enables both `regex` and `lazy_static`.
|
|
||||||
The `lazy_static` feature does not exist, and a user cannot explicitly enable
|
|
||||||
it. This helps hide internal details of how your package is implemented.
|
|
||||||
|
|
||||||
An example of avoiding "funky" names:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
bigdecimal = "0.1"
|
|
||||||
chrono = "0.4"
|
|
||||||
num-bigint = "0.2"
|
|
||||||
serde = {version = "1.0", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
serde = ["dep:serde", "bigdecimal/serde", "chrono/serde", "num-bigint/serde"]
|
|
||||||
```
|
|
||||||
|
|
||||||
In this case, `serde` is a natural name to use for a feature, because it is
|
|
||||||
relevant to your exported API. However, previously you would need to use a
|
|
||||||
name like `serde1` to work around the naming limitation if you wanted to also
|
|
||||||
enable other features.
|
|
||||||
|
|
||||||
### Build-plan
|
### Build-plan
|
||||||
* Tracking Issue: [#5579](https://github.com/rust-lang/cargo/issues/5579)
|
* Tracking Issue: [#5579](https://github.com/rust-lang/cargo/issues/5579)
|
||||||
|
|
||||||
|
@ -898,29 +834,6 @@ error[E0308]: mismatched types
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
```
|
```
|
||||||
|
|
||||||
### Weak dependency features
|
|
||||||
* Tracking Issue: [#8832](https://github.com/rust-lang/cargo/issues/8832)
|
|
||||||
|
|
||||||
The `-Z weak-dep-features` command-line options enables the ability to use
|
|
||||||
`dep_name?/feat_name` syntax in the `[features]` table. The `?` indicates that
|
|
||||||
the optional dependency `dep_name` will not be automatically enabled. The
|
|
||||||
feature `feat_name` will only be added if something else enables the
|
|
||||||
`dep_name` dependency.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[dependencies]
|
|
||||||
serde = { version = "1.0.117", optional = true, default-features = false }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
std = ["serde?/std"]
|
|
||||||
```
|
|
||||||
|
|
||||||
In this example, the `std` feature enables the `std` feature on the `serde`
|
|
||||||
dependency. However, unlike the normal `serde/std` syntax, it will not enable
|
|
||||||
the optional dependency `serde` unless something else has included it.
|
|
||||||
|
|
||||||
### per-package-target
|
### per-package-target
|
||||||
* Tracking Issue: [#9406](https://github.com/rust-lang/cargo/pull/9406)
|
* Tracking Issue: [#9406](https://github.com/rust-lang/cargo/pull/9406)
|
||||||
* Original Pull Request: [#9030](https://github.com/rust-lang/cargo/pull/9030)
|
* Original Pull Request: [#9030](https://github.com/rust-lang/cargo/pull/9030)
|
||||||
|
@ -1375,3 +1288,13 @@ The profile `strip` option has been stabilized in the 1.59 release. See the
|
||||||
Support for generating a future-incompat report has been stabilized
|
Support for generating a future-incompat report has been stabilized
|
||||||
in the 1.59 release. See the [future incompat report chapter](future-incompat-report.md)
|
in the 1.59 release. See the [future incompat report chapter](future-incompat-report.md)
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
|
### Namespaced features
|
||||||
|
|
||||||
|
Namespaced features has been stabilized in the 1.60 release.
|
||||||
|
See the [Features chapter](features.md#optional-dependencies) for more information.
|
||||||
|
|
||||||
|
### Weak dependency features
|
||||||
|
|
||||||
|
Weak dependency features has been stabilized in the 1.60 release.
|
||||||
|
See the [Features chapter](features.md#dependency-features) for more information.
|
||||||
|
|
|
@ -36,7 +36,8 @@ Caused by:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn invalid2() {
|
fn same_name() {
|
||||||
|
// Feature with the same name as a dependency.
|
||||||
let p = project()
|
let p = project()
|
||||||
.file(
|
.file(
|
||||||
"Cargo.toml",
|
"Cargo.toml",
|
||||||
|
@ -59,14 +60,24 @@ fn invalid2() {
|
||||||
.file("bar/src/lib.rs", "")
|
.file("bar/src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build")
|
p.cargo("tree -f")
|
||||||
.with_status(101)
|
.arg("{p} [{f}]")
|
||||||
.with_stderr(
|
.with_stderr("")
|
||||||
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
[ERROR] failed to parse manifest at `[..]`
|
foo v0.0.1 ([..]) []
|
||||||
|
└── bar v1.0.0 ([..]) []
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
Caused by:
|
p.cargo("tree --features bar -f")
|
||||||
features and dependencies cannot have the same name: `bar`
|
.arg("{p} [{f}]")
|
||||||
|
.with_stderr("")
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v0.0.1 ([..]) [bar,baz]
|
||||||
|
└── bar v1.0.0 ([..]) []
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
|
@ -4,99 +4,6 @@ use super::features2::switch_to_resolver_2;
|
||||||
use cargo_test_support::registry::{Dependency, Package};
|
use cargo_test_support::registry::{Dependency, Package};
|
||||||
use cargo_test_support::{project, publish};
|
use cargo_test_support::{project, publish};
|
||||||
|
|
||||||
#[cargo_test]
|
|
||||||
fn gated() {
|
|
||||||
// Need namespaced-features to use `dep:` syntax.
|
|
||||||
Package::new("bar", "1.0.0").publish();
|
|
||||||
let p = project()
|
|
||||||
.file(
|
|
||||||
"Cargo.toml",
|
|
||||||
r#"
|
|
||||||
[package]
|
|
||||||
name = "foo"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bar = { version = "1.0", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
foo = ["dep:bar"]
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.file("src/lib.rs", "")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
p.cargo("check")
|
|
||||||
.with_status(101)
|
|
||||||
.with_stderr(
|
|
||||||
"\
|
|
||||||
[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
|
|
||||||
|
|
||||||
Caused by:
|
|
||||||
namespaced features with the `dep:` prefix are only allowed on the nightly channel \
|
|
||||||
and requires the `-Z namespaced-features` flag on the command-line
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cargo_test]
|
|
||||||
fn dependency_gate_ignored() {
|
|
||||||
// Dependencies with `dep:` features are ignored in the registry if not on nightly.
|
|
||||||
Package::new("baz", "1.0.0").publish();
|
|
||||||
Package::new("bar", "1.0.0")
|
|
||||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
|
||||||
.feature("feat", &["dep:baz"])
|
|
||||||
.publish();
|
|
||||||
let p = project()
|
|
||||||
.file(
|
|
||||||
"Cargo.toml",
|
|
||||||
r#"
|
|
||||||
[package]
|
|
||||||
name = "foo"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bar = "1.0"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.file("src/lib.rs", "")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
p.cargo("check")
|
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
|
||||||
.with_stderr(
|
|
||||||
"\
|
|
||||||
[UPDATING] [..]
|
|
||||||
[ERROR] no matching package named `bar` found
|
|
||||||
location searched: registry `crates-io`
|
|
||||||
required by package `foo v0.1.0 ([..]/foo)`
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.run();
|
|
||||||
|
|
||||||
// Publish a version without namespaced features, it should ignore 1.0.0
|
|
||||||
// and use this instead.
|
|
||||||
Package::new("bar", "1.0.1")
|
|
||||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
|
||||||
.feature("feat", &["baz"])
|
|
||||||
.publish();
|
|
||||||
p.cargo("check")
|
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
|
||||||
"\
|
|
||||||
[UPDATING] [..]
|
|
||||||
[DOWNLOADING] crates ...
|
|
||||||
[DOWNLOADED] bar [..]
|
|
||||||
[CHECKING] bar v1.0.1
|
|
||||||
[CHECKING] foo v0.1.0 [..]
|
|
||||||
[FINISHED] [..]
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn dependency_with_crate_syntax() {
|
fn dependency_with_crate_syntax() {
|
||||||
// Registry dependency uses dep: syntax.
|
// Registry dependency uses dep: syntax.
|
||||||
|
@ -120,8 +27,7 @@ fn dependency_with_crate_syntax() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -156,8 +62,7 @@ fn namespaced_invalid_feature() {
|
||||||
.file("src/main.rs", "")
|
.file("src/main.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build -Z namespaced-features")
|
p.cargo("build")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -188,8 +93,7 @@ fn namespaced_invalid_dependency() {
|
||||||
.file("src/main.rs", "")
|
.file("src/main.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build -Z namespaced-features")
|
p.cargo("build")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -223,8 +127,8 @@ fn namespaced_non_optional_dependency() {
|
||||||
.file("src/main.rs", "")
|
.file("src/main.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build -Z namespaced-features")
|
p.cargo("build")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -261,8 +165,7 @@ fn namespaced_implicit_feature() {
|
||||||
.file("src/main.rs", "fn main() {}")
|
.file("src/main.rs", "fn main() {}")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -271,8 +174,7 @@ fn namespaced_implicit_feature() {
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
p.cargo("check -Z namespaced-features --features baz")
|
p.cargo("check --features baz")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[DOWNLOADING] crates ...
|
[DOWNLOADING] crates ...
|
||||||
|
@ -307,8 +209,7 @@ fn namespaced_shadowed_dep() {
|
||||||
.file("src/main.rs", "fn main() {}")
|
.file("src/main.rs", "fn main() {}")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build -Z namespaced-features")
|
p.cargo("build")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -344,9 +245,7 @@ fn namespaced_shadowed_non_optional() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features")
|
p.cargo("check").run();
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
|
@ -370,7 +269,7 @@ fn namespaced_implicit_non_optional() {
|
||||||
.file("src/main.rs", "fn main() {}")
|
.file("src/main.rs", "fn main() {}")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build -Z namespaced-features").masquerade_as_nightly_cargo().with_status(101).with_stderr(
|
p.cargo("build").with_status(101).with_stderr(
|
||||||
"\
|
"\
|
||||||
[ERROR] failed to parse manifest at `[..]`
|
[ERROR] failed to parse manifest at `[..]`
|
||||||
|
|
||||||
|
@ -411,8 +310,7 @@ fn namespaced_same_name() {
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("run -Z namespaced-features")
|
p.cargo("run")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -424,8 +322,7 @@ fn namespaced_same_name() {
|
||||||
.with_stdout("")
|
.with_stdout("")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("run -Z namespaced-features --features baz")
|
p.cargo("run --features baz")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[DOWNLOADING] crates ...
|
[DOWNLOADING] crates ...
|
||||||
|
@ -473,8 +370,7 @@ fn no_implicit_feature() {
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("run -Z namespaced-features")
|
p.cargo("run")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -486,8 +382,7 @@ fn no_implicit_feature() {
|
||||||
.with_stdout("")
|
.with_stdout("")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("run -Z namespaced-features --features regex")
|
p.cargo("run --features regex")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr_unordered(
|
.with_stderr_unordered(
|
||||||
"\
|
"\
|
||||||
[DOWNLOADING] crates ...
|
[DOWNLOADING] crates ...
|
||||||
|
@ -503,8 +398,7 @@ fn no_implicit_feature() {
|
||||||
.with_stdout("regex")
|
.with_stdout("regex")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("run -Z namespaced-features --features lazy_static")
|
p.cargo("run --features lazy_static")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[ERROR] Package `foo v0.1.0 [..]` does not have feature `lazy_static`. \
|
[ERROR] Package `foo v0.1.0 [..]` does not have feature `lazy_static`. \
|
||||||
|
@ -538,8 +432,7 @@ fn crate_syntax_bad_name() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features --features dep:bar")
|
p.cargo("check --features dep:bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -574,8 +467,7 @@ fn crate_syntax_in_dep() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -608,8 +500,7 @@ fn crate_syntax_cli() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features --features dep:bar")
|
p.cargo("check --features dep:bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -619,8 +510,7 @@ fn crate_syntax_cli() {
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
switch_to_resolver_2(&p);
|
switch_to_resolver_2(&p);
|
||||||
p.cargo("check -Z namespaced-features --features dep:bar")
|
p.cargo("check --features dep:bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -653,8 +543,7 @@ fn crate_required_features() {
|
||||||
.file("src/main.rs", "fn main() {}")
|
.file("src/main.rs", "fn main() {}")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -685,8 +574,7 @@ fn json_exposed() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("metadata -Z namespaced-features --no-deps")
|
p.cargo("metadata --no-deps")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_json(
|
.with_json(
|
||||||
r#"
|
r#"
|
||||||
{
|
{
|
||||||
|
@ -775,8 +663,7 @@ fn crate_feature_with_explicit() {
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z namespaced-features --features f1")
|
p.cargo("check --features f1")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -814,8 +701,7 @@ fn optional_explicit_without_crate() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("build -Z namespaced-features")
|
p.cargo("build")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -856,13 +742,11 @@ fn tree() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("tree -e features -Z namespaced-features")
|
p.cargo("tree -e features")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -e features --features a -Z namespaced-features")
|
p.cargo("tree -e features --features a")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
foo v0.1.0 ([ROOT]/foo)
|
foo v0.1.0 ([ROOT]/foo)
|
||||||
|
@ -876,8 +760,7 @@ foo v0.1.0 ([ROOT]/foo)
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -e features --features a -i bar -Z namespaced-features")
|
p.cargo("tree -e features --features a -i bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
bar v1.0.0
|
bar v1.0.0
|
||||||
|
@ -895,8 +778,7 @@ bar v1.0.0
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -e features --features bar -Z namespaced-features")
|
p.cargo("tree -e features --features bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
foo v0.1.0 ([ROOT]/foo)
|
foo v0.1.0 ([ROOT]/foo)
|
||||||
|
@ -910,8 +792,7 @@ foo v0.1.0 ([ROOT]/foo)
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -e features --features bar -i bar -Z namespaced-features")
|
p.cargo("tree -e features --features bar -i bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
bar v1.0.0
|
bar v1.0.0
|
||||||
|
@ -948,13 +829,11 @@ fn tree_no_implicit() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("tree -e features -Z namespaced-features")
|
p.cargo("tree -e features")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -e features --all-features -Z namespaced-features")
|
p.cargo("tree -e features --all-features")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
foo v0.1.0 ([ROOT]/foo)
|
foo v0.1.0 ([ROOT]/foo)
|
||||||
|
@ -964,8 +843,7 @@ foo v0.1.0 ([ROOT]/foo)
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -e features -i bar --all-features -Z namespaced-features")
|
p.cargo("tree -e features -i bar --all-features")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
bar v1.0.0
|
bar v1.0.0
|
||||||
|
@ -1116,8 +994,7 @@ fn publish() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("publish --token sekrit -Z namespaced-features")
|
p.cargo("publish --token sekrit")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
|
|
@ -558,8 +558,7 @@ fn index_cache_rebuild() {
|
||||||
fs::remove_file(p.root().join("Cargo.lock")).unwrap();
|
fs::remove_file(p.root().join("Cargo.lock")).unwrap();
|
||||||
|
|
||||||
// This should rebuild the cache and use 1.0.1.
|
// This should rebuild the cache and use 1.0.1.
|
||||||
p.cargo("check -Znamespaced-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
|
|
@ -20,100 +20,6 @@ fn require(enabled_features: &[&str], disabled_features: &[&str]) -> String {
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
|
||||||
fn gated() {
|
|
||||||
// Need -Z weak-dep-features to enable.
|
|
||||||
Package::new("bar", "1.0.0").feature("feat", &[]).publish();
|
|
||||||
let p = project()
|
|
||||||
.file(
|
|
||||||
"Cargo.toml",
|
|
||||||
r#"
|
|
||||||
[package]
|
|
||||||
name = "foo"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bar = { version = "1.0", optional = true }
|
|
||||||
|
|
||||||
[features]
|
|
||||||
f1 = ["bar?/feat"]
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.file("src/lib.rs", "")
|
|
||||||
.build();
|
|
||||||
p.cargo("check")
|
|
||||||
.with_status(101)
|
|
||||||
.with_stderr(
|
|
||||||
"\
|
|
||||||
error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
|
|
||||||
|
|
||||||
Caused by:
|
|
||||||
optional dependency features with `?` syntax are only allowed on the nightly \
|
|
||||||
channel and requires the `-Z weak-dep-features` flag on the command line
|
|
||||||
Feature `f1` had feature value `bar?/feat`.
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cargo_test]
|
|
||||||
fn dependency_gate_ignored() {
|
|
||||||
// Dependencies with ? features in the registry are ignored in the
|
|
||||||
// registry if not on nightly.
|
|
||||||
Package::new("baz", "1.0.0").feature("feat", &[]).publish();
|
|
||||||
Package::new("bar", "1.0.0")
|
|
||||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
|
||||||
.feature("feat", &["baz?/feat"])
|
|
||||||
.publish();
|
|
||||||
let p = project()
|
|
||||||
.file(
|
|
||||||
"Cargo.toml",
|
|
||||||
r#"
|
|
||||||
[package]
|
|
||||||
name = "foo"
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bar = "1.0"
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.file("src/lib.rs", "")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
p.cargo("check")
|
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
|
||||||
.with_stderr(
|
|
||||||
"\
|
|
||||||
[UPDATING] [..]
|
|
||||||
[ERROR] no matching package named `bar` found
|
|
||||||
location searched: registry `crates-io`
|
|
||||||
required by package `foo v0.1.0 ([..]/foo)`
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.run();
|
|
||||||
|
|
||||||
// Publish a version without the ? feature, it should ignore 1.0.0
|
|
||||||
// and use this instead.
|
|
||||||
Package::new("bar", "1.0.1")
|
|
||||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
|
||||||
.feature("feat", &["baz"])
|
|
||||||
.publish();
|
|
||||||
p.cargo("check")
|
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
|
||||||
"\
|
|
||||||
[UPDATING] [..]
|
|
||||||
[DOWNLOADING] crates ...
|
|
||||||
[DOWNLOADED] bar [..]
|
|
||||||
[CHECKING] bar v1.0.1
|
|
||||||
[CHECKING] foo v0.1.0 [..]
|
|
||||||
[FINISHED] [..]
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn simple() {
|
fn simple() {
|
||||||
Package::new("bar", "1.0.0")
|
Package::new("bar", "1.0.0")
|
||||||
|
@ -140,8 +46,7 @@ fn simple() {
|
||||||
|
|
||||||
// It's a bit unfortunate that this has to download `bar`, but avoiding
|
// It's a bit unfortunate that this has to download `bar`, but avoiding
|
||||||
// that is extremely difficult.
|
// that is extremely difficult.
|
||||||
p.cargo("check -Z weak-dep-features --features f1")
|
p.cargo("check --features f1")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -153,8 +58,7 @@ fn simple() {
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("check -Z weak-dep-features --features f1,bar")
|
p.cargo("check --features f1,bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[CHECKING] bar v1.0.0
|
[CHECKING] bar v1.0.0
|
||||||
|
@ -196,8 +100,7 @@ fn deferred() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z weak-dep-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -238,8 +141,7 @@ fn not_optional_dep() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z weak-dep-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr("\
|
.with_stderr("\
|
||||||
error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
|
error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
|
||||||
|
@ -275,8 +177,7 @@ fn optional_cli_syntax() {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Does not build bar.
|
// Does not build bar.
|
||||||
p.cargo("check --features bar?/feat -Z weak-dep-features")
|
p.cargo("check --features bar?/feat")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -289,8 +190,7 @@ fn optional_cli_syntax() {
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
// Builds bar.
|
// Builds bar.
|
||||||
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
p.cargo("check --features bar?/feat,bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[CHECKING] bar v1.0.0
|
[CHECKING] bar v1.0.0
|
||||||
|
@ -304,8 +204,7 @@ fn optional_cli_syntax() {
|
||||||
switch_to_resolver_2(&p);
|
switch_to_resolver_2(&p);
|
||||||
p.build_dir().rm_rf();
|
p.build_dir().rm_rf();
|
||||||
// Does not build bar.
|
// Does not build bar.
|
||||||
p.cargo("check --features bar?/feat -Z weak-dep-features")
|
p.cargo("check --features bar?/feat")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[CHECKING] foo v0.1.0 [..]
|
[CHECKING] foo v0.1.0 [..]
|
||||||
|
@ -315,8 +214,7 @@ fn optional_cli_syntax() {
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
// Builds bar.
|
// Builds bar.
|
||||||
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
p.cargo("check --features bar?/feat,bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[CHECKING] bar v1.0.0
|
[CHECKING] bar v1.0.0
|
||||||
|
@ -351,8 +249,7 @@ fn required_features() {
|
||||||
.file("src/main.rs", "fn main() {}")
|
.file("src/main.rs", "fn main() {}")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z weak-dep-features")
|
p.cargo("check")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
|
@ -366,7 +263,7 @@ optional dependency with `?` is not allowed in required-features
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn weak_with_host_decouple() {
|
fn weak_with_host_decouple() {
|
||||||
// -Z weak-opt-features with new resolver
|
// weak-dep-features with new resolver
|
||||||
//
|
//
|
||||||
// foo v0.1.0
|
// foo v0.1.0
|
||||||
// └── common v1.0.0
|
// └── common v1.0.0
|
||||||
|
@ -447,8 +344,7 @@ fn weak_with_host_decouple() {
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("run -Z weak-dep-features")
|
p.cargo("run")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -493,8 +389,7 @@ fn weak_namespaced() {
|
||||||
.file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
|
.file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("check -Z weak-dep-features -Z namespaced-features --features f1")
|
p.cargo("check --features f1")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
@ -506,21 +401,18 @@ fn weak_namespaced() {
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features -Z namespaced-features -f")
|
p.cargo("tree -f")
|
||||||
.arg("{p} feats:{f}")
|
.arg("{p} feats:{f}")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("foo v0.1.0 ([ROOT]/foo) feats:")
|
.with_stdout("foo v0.1.0 ([ROOT]/foo) feats:")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features -Z namespaced-features --features f1 -f")
|
p.cargo("tree --features f1 -f")
|
||||||
.arg("{p} feats:{f}")
|
.arg("{p} feats:{f}")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("foo v0.1.0 ([ROOT]/foo) feats:f1")
|
.with_stdout("foo v0.1.0 ([ROOT]/foo) feats:f1")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features -Z namespaced-features --features f1,f2 -f")
|
p.cargo("tree --features f1,f2 -f")
|
||||||
.arg("{p} feats:{f}")
|
.arg("{p} feats:{f}")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
foo v0.1.0 ([ROOT]/foo) feats:f1,f2
|
foo v0.1.0 ([ROOT]/foo) feats:f1,f2
|
||||||
|
@ -532,8 +424,7 @@ foo v0.1.0 ([ROOT]/foo) feats:f1,f2
|
||||||
// "bar" remains not-a-feature
|
// "bar" remains not-a-feature
|
||||||
p.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
|
p.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
|
||||||
|
|
||||||
p.cargo("check -Z weak-dep-features -Z namespaced-features --features f1,f2")
|
p.cargo("check --features f1,f2")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[CHECKING] bar v1.0.0
|
[CHECKING] bar v1.0.0
|
||||||
|
@ -568,13 +459,11 @@ fn tree() {
|
||||||
.file("src/lib.rs", &require(&["f1"], &[]))
|
.file("src/lib.rs", &require(&["f1"], &[]))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features --features f1")
|
p.cargo("tree --features f1")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features --features f1,bar")
|
p.cargo("tree --features f1,bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
foo v0.1.0 ([ROOT]/foo)
|
foo v0.1.0 ([ROOT]/foo)
|
||||||
|
@ -583,8 +472,7 @@ foo v0.1.0 ([ROOT]/foo)
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features --features f1,bar -e features")
|
p.cargo("tree --features f1,bar -e features")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
foo v0.1.0 ([ROOT]/foo)
|
foo v0.1.0 ([ROOT]/foo)
|
||||||
|
@ -594,8 +482,7 @@ foo v0.1.0 ([ROOT]/foo)
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features --features f1,bar -e features -i bar")
|
p.cargo("tree --features f1,bar -e features -i bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
bar v1.0.0
|
bar v1.0.0
|
||||||
|
@ -610,20 +497,17 @@ bar v1.0.0
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features -e features --features bar?/feat")
|
p.cargo("tree -e features --features bar?/feat")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
// This is a little strange in that it produces no output.
|
// This is a little strange in that it produces no output.
|
||||||
// Maybe `cargo tree` should print a note about why?
|
// Maybe `cargo tree` should print a note about why?
|
||||||
p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat")
|
p.cargo("tree -e features -i bar --features bar?/feat")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout("")
|
.with_stdout("")
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat,bar")
|
p.cargo("tree -e features -i bar --features bar?/feat,bar")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stdout(
|
.with_stdout(
|
||||||
"\
|
"\
|
||||||
bar v1.0.0
|
bar v1.0.0
|
||||||
|
@ -663,8 +547,7 @@ fn publish() {
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
p.cargo("publish --token sekrit -Z weak-dep-features")
|
p.cargo("publish --token sekrit")
|
||||||
.masquerade_as_nightly_cargo()
|
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[UPDATING] [..]
|
||||||
|
|
Loading…
Reference in a new issue