Add multiple build scripts to unit deps

This commit is contained in:
Naman Garg 2025-06-27 03:23:33 +05:30
parent 72290ad03a
commit a24abd6fc2
No known key found for this signature in database
2 changed files with 97 additions and 68 deletions

View File

@ -343,7 +343,11 @@ fn compute_deps(
if unit.target.is_custom_build() {
return Ok(ret);
}
ret.extend(dep_build_script(unit, unit_for, state)?);
ret.extend(
dep_build_script(unit, unit_for, state)?
.into_iter()
.flatten(),
);
// If this target is a binary, test, example, etc, then it depends on
// the library of the same package. The call to `resolve.deps` above
@ -645,7 +649,11 @@ fn compute_deps_doc(
}
// Be sure to build/run the build script for documented libraries.
ret.extend(dep_build_script(unit, unit_for, state)?);
ret.extend(
dep_build_script(unit, unit_for, state)?
.into_iter()
.flatten(),
);
// If we document a binary/example, we need the library available.
if unit.target.is_bin() || unit.target.is_example() {
@ -731,54 +739,57 @@ fn dep_build_script(
unit: &Unit,
unit_for: UnitFor,
state: &State<'_, '_>,
) -> CargoResult<Option<UnitDep>> {
unit.pkg
.targets()
.iter()
.find(|t| t.is_custom_build())
.map(|t| {
// The profile stored in the Unit is the profile for the thing
// the custom build script is running for.
let profile = state.profiles.get_profile_run_custom_build(&unit.profile);
// UnitFor::for_custom_build is used because we want the `host` flag set
// for all of our build dependencies (so they all get
// build-override profiles), including compiling the build.rs
// script itself.
//
// If `is_for_host_features` here is `false`, that means we are a
// build.rs script for a normal dependency and we want to set the
// CARGO_FEATURE_* environment variables to the features as a
// normal dep.
//
// If `is_for_host_features` here is `true`, that means that this
// package is being used as a build dependency or proc-macro, and
// so we only want to set CARGO_FEATURE_* variables for the host
// side of the graph.
//
// Keep in mind that the RunCustomBuild unit and the Compile
// build.rs unit use the same features. This is because some
// people use `cfg!` and `#[cfg]` expressions to check for enabled
// features instead of just checking `CARGO_FEATURE_*` at runtime.
// In the case with the new feature resolver (decoupled host
// deps), and a shared dependency has different features enabled
// for normal vs. build, then the build.rs script will get
// compiled twice. I believe it is not feasible to only build it
// once because it would break a large number of scripts (they
// would think they have the wrong set of features enabled).
let script_unit_for = unit_for.for_custom_build();
new_unit_dep_with_profile(
state,
unit,
&unit.pkg,
t,
script_unit_for,
unit.kind,
CompileMode::RunCustomBuild,
profile,
IS_NO_ARTIFACT_DEP,
)
})
.transpose()
) -> CargoResult<Option<Vec<UnitDep>>> {
Some(
unit.pkg
.targets()
.iter()
.filter(|t| t.is_custom_build())
.map(|t| {
// The profile stored in the Unit is the profile for the thing
// the custom build script is running for.
let profile = state.profiles.get_profile_run_custom_build(&unit.profile);
// UnitFor::for_custom_build is used because we want the `host` flag set
// for all of our build dependencies (so they all get
// build-override profiles), including compiling the build.rs
// script itself.
//
// If `is_for_host_features` here is `false`, that means we are a
// build.rs script for a normal dependency and we want to set the
// CARGO_FEATURE_* environment variables to the features as a
// normal dep.
//
// If `is_for_host_features` here is `true`, that means that this
// package is being used as a build dependency or proc-macro, and
// so we only want to set CARGO_FEATURE_* variables for the host
// side of the graph.
//
// Keep in mind that the RunCustomBuild unit and the Compile
// build.rs unit use the same features. This is because some
// people use `cfg!` and `#[cfg]` expressions to check for enabled
// features instead of just checking `CARGO_FEATURE_*` at runtime.
// In the case with the new feature resolver (decoupled host
// deps), and a shared dependency has different features enabled
// for normal vs. build, then the build.rs script will get
// compiled twice. I believe it is not feasible to only build it
// once because it would break a large number of scripts (they
// would think they have the wrong set of features enabled).
let script_unit_for = unit_for.for_custom_build();
new_unit_dep_with_profile(
state,
unit,
&unit.pkg,
t,
script_unit_for,
unit.kind,
CompileMode::RunCustomBuild,
profile,
IS_NO_ARTIFACT_DEP,
)
})
.collect(),
)
.transpose()
}
/// Choose the correct mode for dependencies.

View File

@ -436,13 +436,12 @@ fn custom_build_script_first_index_script_failed() {
.with_status(101)
.with_stderr_data(str![[r#"
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[RUNNING] `rustc --crate-name build_script_build1 --edition=2024 build1.rs [..]--crate-type bin [..]`
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1`
...
[ERROR] failed to run custom build command for `foo v0.1.0 ([ROOT]/foo)`
Caused by:
process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1` ([EXIT_STATUS]: 101)
...
"#]])
.run();
}
@ -472,14 +471,15 @@ fn custom_build_script_second_index_script_failed() {
p.cargo("check -v")
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
.with_status(0)
.with_status(101)
.with_stderr_data(str![[r#"
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[RUNNING] `rustc --crate-name build_script_build1 --edition=2024 build1.rs [..]--crate-type bin [..]`
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1`
[RUNNING] `rustc --crate-name foo --edition=2024 src/main.rs [..] --crate-type bin [..]`
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
...
[ERROR] failed to run custom build command for `foo v0.1.0 ([ROOT]/foo)`
Caused by:
process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build2` ([EXIT_STATUS]: 101)
...
"#]])
.run();
}
@ -602,7 +602,7 @@ fn build_script_with_conflicting_out_dirs() {
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
.with_status(0)
.with_stdout_data(str![[r#"
Hello, from Build Script 1!
Hello, from Build Script 2!
"#]])
.run();
@ -614,23 +614,34 @@ fn rerun_untracks_other_files() {
.file(
"Cargo.toml",
r#"
cargo-features = ["multiple-build-scripts"]
[package]
name = "foo"
version = "0.1.0"
edition = "2024"
build = ["build1.rs", "build2.rs"]
"#,
)
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
"build1.rs",
r#"
fn main() {
foo();
bar();
}
fn foo() {
let _path = "assets/foo.txt";
}
"#,
)
.file(
"build2.rs",
r#"
fn main() {
bar();
}
fn bar() {
let path = "assets/bar.txt";
println!("cargo::rerun-if-changed={path}");
@ -639,27 +650,34 @@ fn bar() {
.file("assets/foo.txt", "foo")
.file("assets/bar.txt", "bar")
.build();
p.cargo("check").run();
// Editing foo.txt won't recompile, leading to unnoticed changes
p.cargo("check")
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
.run();
// Editing foo.txt will also recompile now since they are separate build scripts
p.change_file("assets/foo.txt", "foo updated");
p.cargo("check -v")
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
.with_stderr_data(str![[r#"
[FRESH] foo v0.1.0 ([ROOT]/foo)
[DIRTY] foo v0.1.0 ([ROOT]/foo): the [..]
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1`
[RUNNING] `rustc --crate-name foo --edition=2024 src/main.rs [..] --crate-type bin [..]
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
"#]])
.run();
// Editing bar.txt will recompile
// Editing bar.txt will also recompile now since they are separate build scripts
p.change_file("assets/bar.txt", "bar updated");
p.cargo("check -v")
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
.with_stderr_data(str![[r#"
[DIRTY] foo v0.1.0 ([ROOT]/foo): the file `assets/bar.txt` has changed ([TIME_DIFF_AFTER_LAST_BUILD])
[DIRTY] foo v0.1.0 ([ROOT]/foo): the [..]
[COMPILING] foo v0.1.0 ([ROOT]/foo)
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build`
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build[..]`
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build[..]`
[RUNNING] `rustc --crate-name foo --edition=2024 src/main.rs [..] --crate-type bin [..]
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s