Auto merge of #14591 - epage:autolib, r=weihanglo

feat(toml): Add `autolib`

### What does this PR try to resolve?

PR #5335 added `autobins`, etc for #5330.  Nowhere in there is
discussion of `autolib`.

Cargo script disables support for additional build-targets by disabling
discovery.
Except we don't have a way to disable discovery of `autolib`, leading to #14476.
By adding `autolib`, we can continue in that direction.

This also allows us to bypass inferring of libs on published packages,
like all other build-targets which were handled in #13849.

Fixes #14476

### How should we test and review this PR?

### Additional information

As this seems fairly low controversy, this insta-stabilizes the field.
In prior versions of Cargo, users will get an "unused manifest key"
warning.
For packages where this is set by `cargo publish`, the warning will be suppressed and things will work as normal.
For `cargo vendor`, the same except there will be some churn in the
vendored source as this field will now be set.
For local development, it should be rare to set `autolib` so the lack of
error by discovering a file when this is set shouldn't be a problem.
This commit is contained in:
bors 2024-09-27 12:25:16 +00:00
commit b396f2c3aa
19 changed files with 160 additions and 47 deletions

2
Cargo.lock generated
View File

@ -462,7 +462,7 @@ dependencies = [
[[package]]
name = "cargo-util-schemas"
version = "0.6.1"
version = "0.7.0"
dependencies = [
"semver",
"serde",

View File

@ -33,7 +33,7 @@ cargo-platform = { path = "crates/cargo-platform", version = "0.1.5" }
cargo-test-macro = { version = "0.3.0", path = "crates/cargo-test-macro" }
cargo-test-support = { version = "0.5.0", path = "crates/cargo-test-support" }
cargo-util = { version = "0.2.14", path = "crates/cargo-util" }
cargo-util-schemas = { version = "0.6.0", path = "crates/cargo-util-schemas" }
cargo-util-schemas = { version = "0.7.0", path = "crates/cargo-util-schemas" }
cargo_metadata = "0.18.1"
clap = "4.5.18"
clap_complete = { version = "4.5.29", features = ["unstable-dynamic"] }

View File

@ -1,6 +1,6 @@
[package]
name = "cargo-util-schemas"
version = "0.6.1"
version = "0.7.0"
rust-version = "1.81" # MSRV:1
edition.workspace = true
license.workspace = true

View File

@ -173,6 +173,7 @@ pub struct TomlPackage {
pub publish: Option<InheritableVecStringOrBool>,
pub workspace: Option<String>,
pub im_a_teapot: Option<bool>,
pub autolib: Option<bool>,
pub autobins: Option<bool>,
pub autoexamples: Option<bool>,
pub autotests: Option<bool>,
@ -217,6 +218,7 @@ impl TomlPackage {
publish: None,
workspace: None,
im_a_teapot: None,
autolib: None,
autobins: None,
autoexamples: None,
autotests: None,

View File

@ -8,7 +8,13 @@ use crate::GlobalContext;
const DEFAULT_EDITION: crate::core::features::Edition =
crate::core::features::Edition::LATEST_STABLE;
const AUTO_FIELDS: &[&str] = &["autobins", "autoexamples", "autotests", "autobenches"];
const AUTO_FIELDS: &[&str] = &[
"autolib",
"autobins",
"autoexamples",
"autotests",
"autobenches",
];
pub(super) fn expand_manifest(
content: &str,
@ -289,6 +295,7 @@ path = "/home/me/test.rs"
autobenches = false
autobins = false
autoexamples = false
autolib = false
autotests = false
build = false
edition = "2021"
@ -324,6 +331,7 @@ time = "0.1.25"
autobenches = false
autobins = false
autoexamples = false
autolib = false
autotests = false
build = false
edition = "2021"
@ -359,6 +367,7 @@ time = "0.1.25"
autobenches = false
autobins = false
autoexamples = false
autolib = false
autotests = false
build = false
edition = "2021"

View File

@ -334,6 +334,7 @@ fn normalize_toml(
package_root,
&original_package.name,
edition,
original_package.autolib,
warnings,
)?;
normalized_toml.bin = Some(targets::normalize_bins(
@ -624,6 +625,7 @@ fn normalize_package_toml<'a>(
.map(manifest::InheritableField::Value),
workspace: original_package.workspace.clone(),
im_a_teapot: original_package.im_a_teapot.clone(),
autolib: Some(false),
autobins: Some(false),
autoexamples: Some(false),
autotests: Some(false),

View File

@ -129,48 +129,63 @@ pub fn normalize_lib(
package_root: &Path,
package_name: &str,
edition: Edition,
autodiscover: Option<bool>,
warnings: &mut Vec<String>,
) -> CargoResult<Option<TomlLibTarget>> {
let inferred = inferred_lib(package_root);
let lib = original_lib.cloned().or_else(|| {
inferred.as_ref().map(|lib| TomlTarget {
path: Some(PathValue(lib.clone())),
..TomlTarget::new()
})
});
let Some(mut lib) = lib else { return Ok(None) };
lib.name
.get_or_insert_with(|| package_name.replace("-", "_"));
if is_normalized(original_lib, autodiscover) {
let Some(lib) = original_lib.cloned() else {
return Ok(None);
};
// Check early to improve error messages
validate_lib_name(&lib, warnings)?;
// Check early to improve error messages
validate_lib_name(&lib, warnings)?;
validate_proc_macro(&lib, "library", edition, warnings)?;
validate_crate_types(&lib, "library", edition, warnings)?;
validate_proc_macro(&lib, "library", edition, warnings)?;
validate_crate_types(&lib, "library", edition, warnings)?;
if lib.path.is_none() {
if let Some(inferred) = inferred {
lib.path = Some(PathValue(inferred));
} else {
let name = name_or_panic(&lib);
let legacy_path = Path::new("src").join(format!("{name}.rs"));
if edition == Edition::Edition2015 && package_root.join(&legacy_path).exists() {
warnings.push(format!(
"path `{}` was erroneously implicitly accepted for library `{name}`,\n\
please rename the file to `src/lib.rs` or set lib.path in Cargo.toml",
legacy_path.display(),
));
lib.path = Some(PathValue(legacy_path));
Ok(Some(lib))
} else {
let inferred = inferred_lib(package_root);
let lib = original_lib.cloned().or_else(|| {
inferred.as_ref().map(|lib| TomlTarget {
path: Some(PathValue(lib.clone())),
..TomlTarget::new()
})
});
let Some(mut lib) = lib else { return Ok(None) };
lib.name
.get_or_insert_with(|| package_name.replace("-", "_"));
// Check early to improve error messages
validate_lib_name(&lib, warnings)?;
validate_proc_macro(&lib, "library", edition, warnings)?;
validate_crate_types(&lib, "library", edition, warnings)?;
if lib.path.is_none() {
if let Some(inferred) = inferred {
lib.path = Some(PathValue(inferred));
} else {
anyhow::bail!(
"can't find library `{name}`, \
let name = name_or_panic(&lib);
let legacy_path = Path::new("src").join(format!("{name}.rs"));
if edition == Edition::Edition2015 && package_root.join(&legacy_path).exists() {
warnings.push(format!(
"path `{}` was erroneously implicitly accepted for library `{name}`,\n\
please rename the file to `src/lib.rs` or set lib.path in Cargo.toml",
legacy_path.display(),
));
lib.path = Some(PathValue(legacy_path));
} else {
anyhow::bail!(
"can't find library `{name}`, \
rename file to `src/lib.rs` or specify lib.path",
)
)
}
}
}
}
Ok(Some(lib))
Ok(Some(lib))
}
}
#[tracing::instrument(skip_all)]
@ -239,7 +254,7 @@ pub fn normalize_bins(
errors: &mut Vec<String>,
has_lib: bool,
) -> CargoResult<Vec<TomlBinTarget>> {
if is_normalized(toml_bins, autodiscover) {
if are_normalized(toml_bins, autodiscover) {
let toml_bins = toml_bins.cloned().unwrap_or_default();
for bin in &toml_bins {
validate_bin_name(bin, warnings)?;
@ -526,7 +541,15 @@ fn to_bench_targets(
Ok(result)
}
fn is_normalized(toml_targets: Option<&Vec<TomlTarget>>, autodiscover: Option<bool>) -> bool {
fn is_normalized(toml_target: Option<&TomlTarget>, autodiscover: Option<bool>) -> bool {
are_normalized_(toml_target.map(std::slice::from_ref), autodiscover)
}
fn are_normalized(toml_targets: Option<&Vec<TomlTarget>>, autodiscover: Option<bool>) -> bool {
are_normalized_(toml_targets.map(|v| v.as_slice()), autodiscover)
}
fn are_normalized_(toml_targets: Option<&[TomlTarget]>, autodiscover: Option<bool>) -> bool {
if autodiscover != Some(false) {
return false;
}
@ -579,7 +602,7 @@ fn normalize_targets_with_legacy_path(
legacy_path: &mut dyn FnMut(&TomlTarget) -> Option<PathBuf>,
autodiscover_flag_name: &str,
) -> CargoResult<Vec<TomlTarget>> {
if is_normalized(toml_targets, autodiscover) {
if are_normalized(toml_targets, autodiscover) {
let toml_targets = toml_targets.cloned().unwrap_or_default();
for target in &toml_targets {
// Check early to improve error messages

View File

@ -323,13 +323,14 @@ configuration tables, such as `[lib]`, `[[bin]]`, `[[test]]`, `[[bench]]`, or
standard directory layout.
The automatic target discovery can be disabled so that only manually
configured targets will be built. Setting the keys `autobins`, `autoexamples`,
configured targets will be built. Setting the keys `autolib`, `autobins`, `autoexamples`,
`autotests`, or `autobenches` to `false` in the `[package]` section will
disable auto-discovery of the corresponding target type.
```toml
[package]
# ...
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -363,6 +364,9 @@ autobins = false
> is `false` if at least one target is manually defined in `Cargo.toml`.
> Beginning with the 2018 edition, the default is always `true`.
> **MSRV:** Respected as of 1.27 for `autobins`, `autoexamples`, `autotests`, and `autobenches`
> **MSRV:** Respected as of 1.83 for `autolib`
[Build cache]: ../guide/build-cache.md
[Rust Edition]: ../../edition-guide/index.html

View File

@ -30,6 +30,7 @@ Every manifest file consists of the following sections:
* [`publish`](#the-publish-field) --- Can be used to prevent publishing the package.
* [`metadata`](#the-metadata-table) --- Extra settings for external tools.
* [`default-run`](#the-default-run-field) --- The default binary to run by [`cargo run`].
* [`autolib`](cargo-targets.md#target-auto-discovery) --- Disables library auto discovery.
* [`autobins`](cargo-targets.md#target-auto-discovery) --- Disables binary auto discovery.
* [`autoexamples`](cargo-targets.md#target-auto-discovery) --- Disables example auto discovery.
* [`autotests`](cargo-targets.md#target-auto-discovery) --- Disables test auto discovery.

View File

@ -1314,7 +1314,7 @@ Inferred / defaulted manifest fields:
Disallowed manifest fields:
- `[workspace]`, `[lib]`, `[[bin]]`, `[[example]]`, `[[test]]`, `[[bench]]`
- `package.workspace`, `package.build`, `package.links`, `package.autobins`, `package.autoexamples`, `package.autotests`, `package.autobenches`
- `package.workspace`, `package.build`, `package.links`, `package.autolib`, `package.autobins`, `package.autoexamples`, `package.autotests`, `package.autobenches`
The default `CARGO_TARGET_DIR` for single-file packages is at `$CARGO_HOME/target/<hash>`:
- Avoid conflicts from multiple single-file packages being in the same directory

View File

@ -2272,6 +2272,7 @@ name = "foo"
version = "0.1.0"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false

View File

@ -1800,6 +1800,7 @@ name = "a"
version = "0.1.0"
authors = ["Zzz"]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false

View File

@ -985,6 +985,7 @@ edition = "2015"
name = "foo"
version = "0.1.0"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -1112,6 +1113,7 @@ edition = "2015"
name = "foo"
version = "0.1.0"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false

View File

@ -224,6 +224,7 @@ include = [
"Cargo.toml",
]
publish = true
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -394,6 +395,7 @@ name = "bar"
version = "0.2.0"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -533,6 +535,7 @@ name = "bar"
version = "0.2.0"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -793,6 +796,7 @@ include = [
"README.md",
]
publish = true
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -966,6 +970,7 @@ name = "bar"
version = "0.2.0"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false

View File

@ -1334,6 +1334,7 @@ version = "0.0.1"
authors = []
build = false
exclude = ["*.txt"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -1419,6 +1420,7 @@ name = "bar"
version = "0.1.0"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -1496,6 +1498,7 @@ edition = "2015"
name = "foo"
version = "0.0.1"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -1524,6 +1527,7 @@ edition = "2015"
name = "foo"
version = "0.0.1"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -2986,6 +2990,7 @@ edition = "2021"
name = "bar"
version = "0.1.0"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3015,6 +3020,7 @@ edition = "2015"
name = "baz"
version = "0.1.0"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3087,6 +3093,7 @@ version = "0.0.1"
authors = []
build = false
exclude = ["*.txt"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3189,6 +3196,7 @@ name = "foo"
version = "0.0.1"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3304,6 +3312,7 @@ name = "foo"
version = "0.0.1"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3496,6 +3505,7 @@ version = "0.0.1"
authors = []
build = false
exclude = ["*.txt"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3902,6 +3912,7 @@ name = "foo"
version = "0.0.1"
authors = []
build = "src/build.rs"
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -3996,6 +4007,7 @@ include = [
"src/lib.rs",
"build.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4072,6 +4084,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/lib.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4151,6 +4164,7 @@ include = [
"src/lib.rs",
"build.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4228,6 +4242,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/lib.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4312,6 +4327,7 @@ include = [
"src/main.rs",
"src/lib.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4392,6 +4408,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/main.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4479,6 +4496,7 @@ include = [
"src/main.rs",
"src/lib.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4562,6 +4580,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/main.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4655,6 +4674,7 @@ include = [
"tests/test_foo.rs",
"benches/bench_foo.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4753,6 +4773,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/lib.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4858,6 +4879,7 @@ include = [
"tests/test_foo.rs",
"benches/bench_foo.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -4968,6 +4990,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/lib.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -5066,6 +5089,7 @@ name = "foo"
version = "0.0.1"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -5275,6 +5299,7 @@ name = "level1"
version = "0.0.1"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false

View File

@ -1583,6 +1583,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly.
version = \"0.1.0\"\n\
authors = []\n\
build = false\n\
autolib = false\n\
autobins = false\n\
autoexamples = false\n\
autotests = false\n\
@ -1963,6 +1964,7 @@ name = "foo"
version = "0.1.0"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false

View File

@ -813,6 +813,34 @@ Hello world!
.run();
}
#[cargo_test]
fn test_no_autolib() {
let script = r#"#!/usr/bin/env cargo
fn main() {
println!("Hello world!");
}"#;
let p = cargo_test_support::project()
.file("script.rs", script)
.file("src/lib.rs", r#"compile_error!{"must not be built"}"#)
.build();
p.cargo("-Zscript -v script.rs --help")
.masquerade_as_nightly_cargo(&["script"])
.with_stdout_data(str![[r#"
Hello world!
"#]])
.with_stderr_data(str![[r#"
[WARNING] `package.edition` is unspecified, defaulting to `2021`
[COMPILING] script v0.0.0 ([ROOT]/foo)
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
[RUNNING] `[ROOT]/home/.cargo/target/[HASH]/debug/script[EXE] --help`
"#]])
.run();
}
#[cargo_test]
fn implicit_target_dir() {
let script = ECHO_SCRIPT;

View File

@ -294,6 +294,7 @@ include = [
"src/lib.rs",
"build.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -379,6 +380,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/lib.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -467,6 +469,7 @@ include = [
"src/main.rs",
"src/lib.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -556,6 +559,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/main.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -650,6 +654,7 @@ include = [
"tests/test_foo.rs",
"benches/bench_foo.rs",
]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -754,6 +759,7 @@ version = "0.0.1"
authors = []
build = false
include = ["src/lib.rs"]
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -1527,6 +1533,7 @@ name = "git_dep"
version = "0.0.1"
authors = []
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
@ -1542,27 +1549,27 @@ path = "src/lib.rs"
[[example]]
name = "a"
path = [..]
path = "examples/a.rs"
[[example]]
name = "b"
path = [..]
path = "examples/b.rs"
[[example]]
name = "c"
path = [..]
path = "examples/c.rs"
[[example]]
name = "x"
path = [..]
path = "examples/x.rs"
[[example]]
name = "y"
path = [..]
path = "examples/y.rs"
[[example]]
name = "z"
path = [..]
path = "examples/z.rs"
"##]],
);

View File

@ -630,6 +630,7 @@ edition = "2015"
name = "foo"
version = "0.1.0"
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false