Skip to content

Commit a24abd6

Browse files
committed
Add multiple build scripts to unit deps
1 parent 72290ad commit a24abd6

File tree

2 files changed

+97
-68
lines changed

2 files changed

+97
-68
lines changed

src/cargo/core/compiler/unit_dependencies.rs

Lines changed: 61 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,11 @@ fn compute_deps(
343343
if unit.target.is_custom_build() {
344344
return Ok(ret);
345345
}
346-
ret.extend(dep_build_script(unit, unit_for, state)?);
346+
ret.extend(
347+
dep_build_script(unit, unit_for, state)?
348+
.into_iter()
349+
.flatten(),
350+
);
347351

348352
// If this target is a binary, test, example, etc, then it depends on
349353
// the library of the same package. The call to `resolve.deps` above
@@ -645,7 +649,11 @@ fn compute_deps_doc(
645649
}
646650

647651
// Be sure to build/run the build script for documented libraries.
648-
ret.extend(dep_build_script(unit, unit_for, state)?);
652+
ret.extend(
653+
dep_build_script(unit, unit_for, state)?
654+
.into_iter()
655+
.flatten(),
656+
);
649657

650658
// If we document a binary/example, we need the library available.
651659
if unit.target.is_bin() || unit.target.is_example() {
@@ -731,54 +739,57 @@ fn dep_build_script(
731739
unit: &Unit,
732740
unit_for: UnitFor,
733741
state: &State<'_, '_>,
734-
) -> CargoResult<Option<UnitDep>> {
735-
unit.pkg
736-
.targets()
737-
.iter()
738-
.find(|t| t.is_custom_build())
739-
.map(|t| {
740-
// The profile stored in the Unit is the profile for the thing
741-
// the custom build script is running for.
742-
let profile = state.profiles.get_profile_run_custom_build(&unit.profile);
743-
// UnitFor::for_custom_build is used because we want the `host` flag set
744-
// for all of our build dependencies (so they all get
745-
// build-override profiles), including compiling the build.rs
746-
// script itself.
747-
//
748-
// If `is_for_host_features` here is `false`, that means we are a
749-
// build.rs script for a normal dependency and we want to set the
750-
// CARGO_FEATURE_* environment variables to the features as a
751-
// normal dep.
752-
//
753-
// If `is_for_host_features` here is `true`, that means that this
754-
// package is being used as a build dependency or proc-macro, and
755-
// so we only want to set CARGO_FEATURE_* variables for the host
756-
// side of the graph.
757-
//
758-
// Keep in mind that the RunCustomBuild unit and the Compile
759-
// build.rs unit use the same features. This is because some
760-
// people use `cfg!` and `#[cfg]` expressions to check for enabled
761-
// features instead of just checking `CARGO_FEATURE_*` at runtime.
762-
// In the case with the new feature resolver (decoupled host
763-
// deps), and a shared dependency has different features enabled
764-
// for normal vs. build, then the build.rs script will get
765-
// compiled twice. I believe it is not feasible to only build it
766-
// once because it would break a large number of scripts (they
767-
// would think they have the wrong set of features enabled).
768-
let script_unit_for = unit_for.for_custom_build();
769-
new_unit_dep_with_profile(
770-
state,
771-
unit,
772-
&unit.pkg,
773-
t,
774-
script_unit_for,
775-
unit.kind,
776-
CompileMode::RunCustomBuild,
777-
profile,
778-
IS_NO_ARTIFACT_DEP,
779-
)
780-
})
781-
.transpose()
742+
) -> CargoResult<Option<Vec<UnitDep>>> {
743+
Some(
744+
unit.pkg
745+
.targets()
746+
.iter()
747+
.filter(|t| t.is_custom_build())
748+
.map(|t| {
749+
// The profile stored in the Unit is the profile for the thing
750+
// the custom build script is running for.
751+
let profile = state.profiles.get_profile_run_custom_build(&unit.profile);
752+
// UnitFor::for_custom_build is used because we want the `host` flag set
753+
// for all of our build dependencies (so they all get
754+
// build-override profiles), including compiling the build.rs
755+
// script itself.
756+
//
757+
// If `is_for_host_features` here is `false`, that means we are a
758+
// build.rs script for a normal dependency and we want to set the
759+
// CARGO_FEATURE_* environment variables to the features as a
760+
// normal dep.
761+
//
762+
// If `is_for_host_features` here is `true`, that means that this
763+
// package is being used as a build dependency or proc-macro, and
764+
// so we only want to set CARGO_FEATURE_* variables for the host
765+
// side of the graph.
766+
//
767+
// Keep in mind that the RunCustomBuild unit and the Compile
768+
// build.rs unit use the same features. This is because some
769+
// people use `cfg!` and `#[cfg]` expressions to check for enabled
770+
// features instead of just checking `CARGO_FEATURE_*` at runtime.
771+
// In the case with the new feature resolver (decoupled host
772+
// deps), and a shared dependency has different features enabled
773+
// for normal vs. build, then the build.rs script will get
774+
// compiled twice. I believe it is not feasible to only build it
775+
// once because it would break a large number of scripts (they
776+
// would think they have the wrong set of features enabled).
777+
let script_unit_for = unit_for.for_custom_build();
778+
new_unit_dep_with_profile(
779+
state,
780+
unit,
781+
&unit.pkg,
782+
t,
783+
script_unit_for,
784+
unit.kind,
785+
CompileMode::RunCustomBuild,
786+
profile,
787+
IS_NO_ARTIFACT_DEP,
788+
)
789+
})
790+
.collect(),
791+
)
792+
.transpose()
782793
}
783794

784795
/// Choose the correct mode for dependencies.

tests/testsuite/build_scripts_multiple.rs

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -436,13 +436,12 @@ fn custom_build_script_first_index_script_failed() {
436436
.with_status(101)
437437
.with_stderr_data(str![[r#"
438438
[COMPILING] foo v0.1.0 ([ROOT]/foo)
439-
[RUNNING] `rustc --crate-name build_script_build1 --edition=2024 build1.rs [..]--crate-type bin [..]`
440-
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1`
439+
...
441440
[ERROR] failed to run custom build command for `foo v0.1.0 ([ROOT]/foo)`
442441
443442
Caused by:
444443
process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1` ([EXIT_STATUS]: 101)
445-
444+
...
446445
"#]])
447446
.run();
448447
}
@@ -472,14 +471,15 @@ fn custom_build_script_second_index_script_failed() {
472471

473472
p.cargo("check -v")
474473
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
475-
.with_status(0)
474+
.with_status(101)
476475
.with_stderr_data(str![[r#"
477476
[COMPILING] foo v0.1.0 ([ROOT]/foo)
478-
[RUNNING] `rustc --crate-name build_script_build1 --edition=2024 build1.rs [..]--crate-type bin [..]`
479-
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1`
480-
[RUNNING] `rustc --crate-name foo --edition=2024 src/main.rs [..] --crate-type bin [..]`
481-
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
477+
...
478+
[ERROR] failed to run custom build command for `foo v0.1.0 ([ROOT]/foo)`
482479
480+
Caused by:
481+
process didn't exit successfully: `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build2` ([EXIT_STATUS]: 101)
482+
...
483483
"#]])
484484
.run();
485485
}
@@ -602,7 +602,7 @@ fn build_script_with_conflicting_out_dirs() {
602602
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
603603
.with_status(0)
604604
.with_stdout_data(str![[r#"
605-
Hello, from Build Script 1!
605+
Hello, from Build Script 2!
606606
607607
"#]])
608608
.run();
@@ -614,23 +614,34 @@ fn rerun_untracks_other_files() {
614614
.file(
615615
"Cargo.toml",
616616
r#"
617+
cargo-features = ["multiple-build-scripts"]
618+
617619
[package]
618620
name = "foo"
619621
version = "0.1.0"
620622
edition = "2024"
623+
build = ["build1.rs", "build2.rs"]
621624
"#,
622625
)
623626
.file("src/main.rs", "fn main() {}")
624627
.file(
625-
"build.rs",
628+
"build1.rs",
626629
r#"
627630
fn main() {
628631
foo();
629-
bar();
630632
}
631633
fn foo() {
632634
let _path = "assets/foo.txt";
633635
}
636+
"#,
637+
)
638+
.file(
639+
"build2.rs",
640+
r#"
641+
fn main() {
642+
bar();
643+
}
644+
634645
fn bar() {
635646
let path = "assets/bar.txt";
636647
println!("cargo::rerun-if-changed={path}");
@@ -639,27 +650,34 @@ fn bar() {
639650
.file("assets/foo.txt", "foo")
640651
.file("assets/bar.txt", "bar")
641652
.build();
642-
p.cargo("check").run();
643-
644-
// Editing foo.txt won't recompile, leading to unnoticed changes
653+
p.cargo("check")
654+
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
655+
.run();
645656

657+
// Editing foo.txt will also recompile now since they are separate build scripts
646658
p.change_file("assets/foo.txt", "foo updated");
647659
p.cargo("check -v")
660+
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
648661
.with_stderr_data(str![[r#"
649-
[FRESH] foo v0.1.0 ([ROOT]/foo)
662+
[DIRTY] foo v0.1.0 ([ROOT]/foo): the [..]
663+
[COMPILING] foo v0.1.0 ([ROOT]/foo)
664+
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build1`
665+
[RUNNING] `rustc --crate-name foo --edition=2024 src/main.rs [..] --crate-type bin [..]
650666
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
651667
652668
"#]])
653669
.run();
654670

655-
// Editing bar.txt will recompile
671+
// Editing bar.txt will also recompile now since they are separate build scripts
656672

657673
p.change_file("assets/bar.txt", "bar updated");
658674
p.cargo("check -v")
675+
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
659676
.with_stderr_data(str![[r#"
660-
[DIRTY] foo v0.1.0 ([ROOT]/foo): the file `assets/bar.txt` has changed ([TIME_DIFF_AFTER_LAST_BUILD])
677+
[DIRTY] foo v0.1.0 ([ROOT]/foo): the [..]
661678
[COMPILING] foo v0.1.0 ([ROOT]/foo)
662-
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build`
679+
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build[..]`
680+
[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build[..]`
663681
[RUNNING] `rustc --crate-name foo --edition=2024 src/main.rs [..] --crate-type bin [..]
664682
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
665683

0 commit comments

Comments
 (0)