-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Accessing each build script's OUT_DIR
#15891
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1704,12 +1704,22 @@ fn build_deps_args( | |
|
||
let mut unstable_opts = false; | ||
|
||
// Add `OUT_DIR` environment variables for build scripts | ||
let first_custom_build_dep = deps.iter().find(|dep| dep.unit.mode.is_run_custom_build()); | ||
if let Some(dep) = first_custom_build_dep { | ||
let out_dir = &build_runner.files().build_script_out_dir(&dep.unit); | ||
cmd.env("OUT_DIR", &out_dir); | ||
} | ||
|
||
for dep in deps { | ||
if dep.unit.mode.is_run_custom_build() { | ||
cmd.env( | ||
"OUT_DIR", | ||
&build_runner.files().build_script_out_dir(&dep.unit), | ||
); | ||
let out_dir = &build_runner.files().build_script_out_dir(&dep.unit); | ||
let target_name = dep.unit.target.name(); | ||
let out_dir_prefix = target_name | ||
.strip_prefix("build-script-") | ||
.unwrap_or(target_name); | ||
let out_dir_name = format!("{out_dir_prefix}_OUT_DIR"); | ||
cmd.env(&out_dir_name, &out_dir); | ||
Comment on lines
+1716
to
+1722
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't is need a feature gate? |
||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -10,7 +10,7 @@ | |||||||||||||
//! It is a bit tricky because we need match explicit information from `Cargo.toml` | ||||||||||||||
//! with implicit info in directory layout. | ||||||||||||||
|
||||||||||||||
use std::collections::HashSet; | ||||||||||||||
use std::collections::{HashMap, HashSet}; | ||||||||||||||
use std::fs::{self, DirEntry}; | ||||||||||||||
use std::path::{Path, PathBuf}; | ||||||||||||||
|
||||||||||||||
|
@@ -104,6 +104,7 @@ pub(super) fn to_targets( | |||||||||||||
if metabuild.is_some() { | ||||||||||||||
anyhow::bail!("cannot specify both `metabuild` and `build`"); | ||||||||||||||
} | ||||||||||||||
validate_unique_build_scripts(custom_build)?; | ||||||||||||||
for script in custom_build { | ||||||||||||||
let script_path = Path::new(script); | ||||||||||||||
let name = format!( | ||||||||||||||
|
@@ -901,6 +902,35 @@ fn validate_unique_names(targets: &[TomlTarget], target_kind: &str) -> CargoResu | |||||||||||||
Ok(()) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/// Will check a list of build scripts, and make sure script file stems are unique within a vector. | ||||||||||||||
fn validate_unique_build_scripts(scripts: &[String]) -> CargoResult<()> { | ||||||||||||||
let mut seen = HashMap::new(); | ||||||||||||||
for script in scripts { | ||||||||||||||
let stem = Path::new(script).file_stem().unwrap().to_str().unwrap(); | ||||||||||||||
seen.entry(stem) | ||||||||||||||
.or_insert_with(Vec::new) | ||||||||||||||
.push(script.as_str()); | ||||||||||||||
} | ||||||||||||||
let mut conflict_file_stem = false; | ||||||||||||||
let mut err_msg = String::from( | ||||||||||||||
"found build scripts with duplicate file stems, but all build scripts must have a unique file stem", | ||||||||||||||
); | ||||||||||||||
for (stem, paths) in seen { | ||||||||||||||
if paths.len() > 1 { | ||||||||||||||
conflict_file_stem = true; | ||||||||||||||
err_msg += &format!( | ||||||||||||||
"\nBuild Scripts : {} have the same file stem, that is {}", | ||||||||||||||
paths.join(", "), | ||||||||||||||
stem | ||||||||||||||
); | ||||||||||||||
Comment on lines
+921
to
+925
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
if conflict_file_stem { | ||||||||||||||
anyhow::bail!(err_msg); | ||||||||||||||
} | ||||||||||||||
Ok(()) | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
fn configure( | ||||||||||||||
toml: &TomlTarget, | ||||||||||||||
target: &mut Target, | ||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -256,6 +256,9 @@ corresponding environment variable is set to the empty string, `""`. | |
* `OUT_DIR` --- If the package has a build script, this is set to the folder | ||
where the build script should place its output. See below for more information. | ||
(Only set during compilation.) | ||
* `<script-name>_OUT_DIR` --- If the package has build script(s), this is set to the folder where the | ||
build script should place its output. The `<script-name>` is the file-stem of the build script, exactly as-is. | ||
For example, `bar_OUT_DIR` for script at `foo/bar.rs`. (Only set during compilation.) | ||
Comment on lines
+259
to
+261
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably be on |
||
* `CARGO_BIN_EXE_<name>` --- The absolute path to a binary target's executable. | ||
This is only set when building an [integration test] or benchmark. This may | ||
be used with the [`env` macro] to find the executable to run for testing | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -549,7 +549,7 @@ fn build_script_with_conflicting_out_dirs() { | |
build = ["build1.rs", "build2.rs"] | ||
"#, | ||
) | ||
// OUT_DIR is set to the lexicographically largest build script's OUT_DIR by default | ||
// By default, OUT_DIR is set to that of the first build script in the array | ||
.file( | ||
"src/main.rs", | ||
r#" | ||
|
@@ -603,7 +603,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 2! | ||
Hello, from Build Script 1! | ||
|
||
"#]]) | ||
.run(); | ||
|
@@ -628,7 +628,7 @@ fn build_script_with_conflicts_reverse_sorted() { | |
build = ["build2.rs", "build1.rs"] | ||
"#, | ||
) | ||
// OUT_DIR is set to the lexicographically largest build script's OUT_DIR by default | ||
// By default, OUT_DIR is set to that of the first build script in the array | ||
.file( | ||
"src/main.rs", | ||
r#" | ||
|
@@ -682,7 +682,7 @@ fn build_script_with_conflicts_reverse_sorted() { | |
.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(); | ||
|
@@ -764,3 +764,118 @@ fn bar() { | |
"#]]) | ||
.run(); | ||
} | ||
|
||
#[cargo_test] | ||
fn multiple_out_dirs() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this test be added before the validation? |
||
// Test to verify access to the `OUT_DIR` of the respective build scripts. | ||
|
||
let p = project() | ||
.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", | ||
r#" | ||
include!(concat!(env!("build1_OUT_DIR"), "/foo.rs")); | ||
include!(concat!(env!("build2_OUT_DIR"), "/foo.rs")); | ||
fn main() { | ||
println!("{}", message1()); | ||
println!("{}", message2()); | ||
} | ||
"#, | ||
) | ||
.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 message1() -> &'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 message2() -> &'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! | ||
Hello, from Build Script 2! | ||
|
||
"#]]) | ||
.run(); | ||
} | ||
|
||
#[cargo_test] | ||
fn duplicate_build_script_stems() { | ||
// Test to verify that duplicate build script file stems throws error. | ||
|
||
let p = project() | ||
.file( | ||
"Cargo.toml", | ||
r#" | ||
cargo-features = ["multiple-build-scripts"] | ||
|
||
[package] | ||
name = "foo" | ||
version = "0.1.0" | ||
edition = "2024" | ||
build = ["build1.rs", "foo/build1.rs"] | ||
"#, | ||
) | ||
.file("src/main.rs", "fn main() {}") | ||
.file("build1.rs", "fn main() {}") | ||
.file("foo/build1.rs", "fn main() {}") | ||
.build(); | ||
|
||
p.cargo("check -v") | ||
.masquerade_as_nightly_cargo(&["multiple-build-scripts"]) | ||
.with_status(101) | ||
.with_stderr_data(str![[r#" | ||
[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` | ||
|
||
Caused by: | ||
found build scripts with duplicate file stems, but all build scripts must have a unique file stem | ||
Build Scripts : build1.rs, foo/build1.rs have the same file stem, that is build1 | ||
|
||
"#]]) | ||
.run(); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.