diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index da5d36eb5129..0400e89a1e46 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -416,7 +416,7 @@ features! { (unstable, profile_rustflags, "", "reference/unstable.html#profile-rustflags-option"), // Allow specifying rustflags directly in a profile - (unstable, workspace_inheritance, "", "reference/unstable.html#workspace-inheritance"), + (stable, workspace_inheritance, "1.64", "reference/unstable.html#workspace-inheritance"), } pub struct Feature { diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index ab63420ab241..e71ca757941a 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -1017,19 +1017,16 @@ pub enum MaybeWorkspace { impl MaybeWorkspace { fn resolve<'a>( self, - cargo_features: &Features, label: &str, get_ws_field: impl FnOnce() -> CargoResult, ) -> CargoResult { match self { MaybeWorkspace::Defined(value) => Ok(value), - MaybeWorkspace::Workspace(TomlWorkspaceField { workspace: true }) => { - cargo_features.require(Feature::workspace_inheritance())?; - get_ws_field().context(format!( + MaybeWorkspace::Workspace(TomlWorkspaceField { workspace: true }) => get_ws_field() + .context(format!( "error inheriting `{}` from workspace root manifest's `workspace.package.{}`", label, label - )) - } + )), MaybeWorkspace::Workspace(TomlWorkspaceField { workspace: false }) => Err(anyhow!( "`workspace=false` is unsupported for `package.{}`", label, @@ -1592,7 +1589,7 @@ impl TomlManifest { let version = project .version .clone() - .resolve(&features, "version", || inherit()?.version())?; + .resolve("version", || inherit()?.version())?; project.version = MaybeWorkspace::Defined(version.clone()); @@ -1600,7 +1597,7 @@ impl TomlManifest { let edition = if let Some(edition) = project.edition.clone() { let edition: Edition = edition - .resolve(&features, "edition", || inherit()?.edition())? + .resolve("edition", || inherit()?.edition())? .parse() .with_context(|| "failed to parse the `edition` key")?; project.edition = Some(MaybeWorkspace::Defined(edition.to_string())); @@ -1625,7 +1622,7 @@ impl TomlManifest { let rust_version = if let Some(rust_version) = &project.rust_version { let rust_version = rust_version .clone() - .resolve(&features, "rust_version", || inherit()?.rust_version())?; + .resolve("rust_version", || inherit()?.rust_version())?; let req = match semver::VersionReq::parse(&rust_version) { // Exclude semver operators like `^` and pre-release identifiers Ok(req) if rust_version.chars().all(|c| c.is_ascii_digit() || c == '.') => req, @@ -1716,7 +1713,6 @@ impl TomlManifest { }; fn process_dependencies( - features: &Features, cx: &mut Context<'_, '_>, new_deps: Option<&BTreeMap>, kind: Option, @@ -1736,7 +1732,7 @@ impl TomlManifest { let mut deps: BTreeMap = BTreeMap::new(); for (n, v) in dependencies.iter() { - let resolved = v.clone().resolve(features, n, cx, || inherit())?; + let resolved = v.clone().resolve(n, cx, || inherit())?; let dep = resolved.to_dependency(n, cx, kind)?; validate_package_name(dep.name_in_toml().as_str(), "dependency name", "")?; cx.deps.push(dep); @@ -1747,7 +1743,6 @@ impl TomlManifest { // Collect the dependencies. let dependencies = process_dependencies( - &features, &mut cx, me.dependencies.as_ref(), None, @@ -1762,7 +1757,6 @@ impl TomlManifest { .as_ref() .or_else(|| me.dev_dependencies2.as_ref()); let dev_deps = process_dependencies( - &features, &mut cx, dev_deps, Some(DepKind::Development), @@ -1777,7 +1771,6 @@ impl TomlManifest { .as_ref() .or_else(|| me.build_dependencies2.as_ref()); let build_deps = process_dependencies( - &features, &mut cx, build_deps, Some(DepKind::Build), @@ -1793,7 +1786,6 @@ impl TomlManifest { Some(platform) }; let deps = process_dependencies( - &features, &mut cx, platform.dependencies.as_ref(), None, @@ -1809,7 +1801,6 @@ impl TomlManifest { .as_ref() .or_else(|| platform.build_dependencies2.as_ref()); let build_deps = process_dependencies( - &features, &mut cx, build_deps, Some(DepKind::Build), @@ -1825,7 +1816,6 @@ impl TomlManifest { .as_ref() .or_else(|| platform.dev_dependencies2.as_ref()); let dev_deps = process_dependencies( - &features, &mut cx, dev_deps, Some(DepKind::Development), @@ -1872,13 +1862,13 @@ impl TomlManifest { let exclude = project .exclude .clone() - .map(|mw| mw.resolve(&features, "exclude", || inherit()?.exclude())) + .map(|mw| mw.resolve("exclude", || inherit()?.exclude())) .transpose()? .unwrap_or_default(); let include = project .include .clone() - .map(|mw| mw.resolve(&features, "include", || inherit()?.include())) + .map(|mw| mw.resolve("include", || inherit()?.include())) .transpose()? .unwrap_or_default(); let empty_features = BTreeMap::new(); @@ -1895,67 +1885,63 @@ impl TomlManifest { description: project .description .clone() - .map(|mw| mw.resolve(&features, "description", || inherit()?.description())) + .map(|mw| mw.resolve("description", || inherit()?.description())) .transpose()?, homepage: project .homepage .clone() - .map(|mw| mw.resolve(&features, "homepage", || inherit()?.homepage())) + .map(|mw| mw.resolve("homepage", || inherit()?.homepage())) .transpose()?, documentation: project .documentation .clone() - .map(|mw| mw.resolve(&features, "documentation", || inherit()?.documentation())) + .map(|mw| mw.resolve("documentation", || inherit()?.documentation())) .transpose()?, readme: readme_for_project( package_root, project .readme .clone() - .map(|mw| mw.resolve(&features, "readme", || inherit()?.readme(package_root))) + .map(|mw| mw.resolve("readme", || inherit()?.readme(package_root))) .transpose()?, ), authors: project .authors .clone() - .map(|mw| mw.resolve(&features, "authors", || inherit()?.authors())) + .map(|mw| mw.resolve("authors", || inherit()?.authors())) .transpose()? .unwrap_or_default(), license: project .license .clone() - .map(|mw| mw.resolve(&features, "license", || inherit()?.license())) + .map(|mw| mw.resolve("license", || inherit()?.license())) .transpose()?, license_file: project .license_file .clone() - .map(|mw| { - mw.resolve(&features, "license", || { - inherit()?.license_file(package_root) - }) - }) + .map(|mw| mw.resolve("license", || inherit()?.license_file(package_root))) .transpose()?, repository: project .repository .clone() - .map(|mw| mw.resolve(&features, "repository", || inherit()?.repository())) + .map(|mw| mw.resolve("repository", || inherit()?.repository())) .transpose()?, keywords: project .keywords .clone() - .map(|mw| mw.resolve(&features, "keywords", || inherit()?.keywords())) + .map(|mw| mw.resolve("keywords", || inherit()?.keywords())) .transpose()? .unwrap_or_default(), categories: project .categories .clone() - .map(|mw| mw.resolve(&features, "categories", || inherit()?.categories())) + .map(|mw| mw.resolve("categories", || inherit()?.categories())) .transpose()? .unwrap_or_default(), badges: me .badges .clone() - .map(|mw| mw.resolve(&features, "badges", || inherit()?.badges())) + .map(|mw| mw.resolve("badges", || inherit()?.badges())) .transpose()? .unwrap_or_default(), links: project.links.clone(), @@ -2015,11 +2001,10 @@ impl TomlManifest { profiles.validate(&features, &mut warnings)?; } - let publish = project.publish.clone().map(|publish| { - publish - .resolve(&features, "publish", || inherit()?.publish()) - .unwrap() - }); + let publish = project + .publish + .clone() + .map(|publish| publish.resolve("publish", || inherit()?.publish()).unwrap()); project.publish = publish.clone().map(|p| MaybeWorkspace::Defined(p)); @@ -2479,7 +2464,6 @@ impl TomlDependency

{ impl TomlDependency { fn resolve<'a>( self, - cargo_features: &Features, label: &str, cx: &mut Context<'_, '_>, get_inheritable: impl FnOnce() -> CargoResult<&'a InheritableFields>, @@ -2492,7 +2476,6 @@ impl TomlDependency { features, optional, }) => { - cargo_features.require(Feature::workspace_inheritance())?; let inheritable = get_inheritable()?; inheritable.get_dependency(label).context(format!( "error reading `dependencies.{}` from workspace root manifest's `workspace.dependencies.{}`", diff --git a/src/doc/src/reference/specifying-dependencies.md b/src/doc/src/reference/specifying-dependencies.md index f1188f6d6fb6..3cd4ae473123 100644 --- a/src/doc/src/reference/specifying-dependencies.md +++ b/src/doc/src/reference/specifying-dependencies.md @@ -454,8 +454,51 @@ following to the above manifest: log-debug = ['bar/log-debug'] # using 'foo/log-debug' would be an error! ``` +### Inheriting a dependency from a workspace + +Dependencies can be inherited from a workspace by specifying the +dependency in the workspace's [`[workspace.dependencies]`][workspace.dependencies] table. +After that add it to the `[dependencies]` table with `dep.workspace = true`. + +The `workspace` key can be defined with: +- [`optional`][optional]: Note that the`[workspace.dependencies]` table is not allowed to specify `optional`. +- [`features`][features]: These are additive with the features declared in the `[workspace.dependencies]` + +The `workspace` key cannot be defined with: + +| | | +|------------------|--------------------| +| `branch` | `default-features` | +| `git` | `package` | +| `path` | `registry` | +| `registry-index` | `rev` | +| `tag` | `version` | + + +Dependencies in the `[dependencies]`, `[dev-dependencies]`, `[build-dependencies]`, and +`[target."...".dependencies]` sections support the ability to reference the +`[workspace.dependencies]` definition of dependencies. + +Example: +```toml +[dependencies] +dep.workspace = true +dep2 = { workspace = true, features = ["fancy"] } +dep3 = { workspace = true, optional = true } +dep4 = { workspace = true, optional = true, features = ["fancy"] } + +[build-dependencies] +dep-build.workspace = true + +[dev-dependencies] +dep-dev.workspace = true +``` + [crates.io]: https://crates.io/ [dev-dependencies]: #development-dependencies +[workspace.dependencies]: workspaces.md#the-workspacedependencies-table +[optional]: features.md#optional-dependencies +[features]: features.md