Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/cargo/core/compiler/unit_dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ use crate::core::dependency::{Artifact, ArtifactKind, ArtifactTarget, DepKind};
use crate::core::profiles::{Profile, Profiles, UnitFor};
use crate::core::resolver::Resolve;
use crate::core::resolver::features::{FeaturesFor, ResolvedFeatures};
use crate::core::{Dependency, Package, PackageId, PackageSet, Target, TargetKind, Workspace};
use crate::core::{
Dependency, Feature, Package, PackageId, PackageSet, Target, TargetKind, Workspace,
};
use crate::ops::resolve_all_features;
use crate::util::GlobalContext;
use crate::util::interning::InternedString;
Expand Down Expand Up @@ -142,8 +144,27 @@ pub fn build_unit_dependencies<'a, 'gctx>(
// which affect the determinism of the build itself. As a result be sure
// that dependency lists are always sorted to ensure we've always got a
// deterministic output.
for list in state.unit_dependencies.values_mut() {
list.sort();
for (unit, list) in &mut state.unit_dependencies {
let is_multiple_build_scripts_enabled = unit
.pkg
.manifest()
.unstable_features()
.require(Feature::multiple_build_scripts())
.is_ok();

if is_multiple_build_scripts_enabled {
list.sort_by_key(|unit_dep| {
if unit_dep.unit.target.is_custom_build() {
// We do not sort build scripts to preserve the user-defined order.
// In terms of determinism, we are assuming nothing interferes with order from when the user set it in `Cargo.toml` to here
(0, None)
} else {
(1, Some(unit_dep.clone()))
}
});
} else {
list.sort();
}
}
trace!("ALL UNIT DEPENDENCIES {:#?}", state.unit_dependencies);

Expand Down
79 changes: 79 additions & 0 deletions tests/testsuite/build_scripts_multiple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,85 @@ Hello, from Build Script 2!
.run();
}

#[cargo_test]
fn build_script_with_conflicts_reverse_sorted() {
// In this, multiple scripts create file with same name in their respective OUT_DIR.
// It is different from above because `package.build` is not sorted in this.

let p = project()
.file(
"Cargo.toml",
r#"
cargo-features = ["multiple-build-scripts"]

[package]
name = "foo"
version = "0.1.0"
edition = "2024"

build = ["build2.rs", "build1.rs"]
"#,
)
// OUT_DIR is set to the lexicographically largest build script's OUT_DIR by default
.file(
"src/main.rs",
r#"
include!(concat!(env!("OUT_DIR"), "/foo.rs"));
fn main() {
println!("{}", message());
}
"#,
)
.file(
"build1.rs",
r#"
use std::env;
use std::fs;
use std::path::Path;

fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("foo.rs");
fs::write(
&dest_path,
"pub fn message() -> &'static str {
\"Hello, from Build Script 1!\"
}
"
).unwrap();
}"#,
)
.file(
"build2.rs",
r#"
use std::env;
use std::fs;
use std::path::Path;

fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("foo.rs");
fs::write(
&dest_path,
"pub fn message() -> &'static str {
\"Hello, from Build Script 2!\"
}
"
).unwrap();
}"#,
)
.build();

p.cargo("run -v")
.masquerade_as_nightly_cargo(&["multiple-build-scripts"])
.with_status(0)
.with_stdout_data(str![[r#"
Hello, from Build Script 1!

"#]])
.run();
}

#[cargo_test]
fn rerun_untracks_other_files() {
let p = project()
Expand Down
Loading