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
1 change: 0 additions & 1 deletion cargo/private/cargo_build_script_runner/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,6 @@ fn run_buildrs() -> Result<(), String> {
&buildrs_outputs,
&crate_links,
&exec_root.to_string_lossy(),
&out_dir,
)
.as_bytes(),
)
Expand Down
33 changes: 30 additions & 3 deletions cargo/private/cargo_build_script_runner/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ impl BuildScriptOutput {
outputs: &[BuildScriptOutput],
crate_links: &str,
exec_root: &str,
out_dir: &str,
) -> String {
let prefix = format!("DEP_{}_", crate_links.replace('-', "_").to_uppercase());
outputs
Expand All @@ -191,7 +190,14 @@ impl BuildScriptOutput {
Some(format!(
"{}{}",
prefix,
Self::escape_for_serializing(Self::redact_paths(env, exec_root, out_dir))
// Do NOT redact the producer's out_dir to the generic
// `${out_dir}` token here: DEP_* env vars are consumed
// by *downstream* crates' build scripts, whose runner
// only substitutes `${pwd}` and whose own out_dir
// points to a different directory, so the token would
// resolve incorrectly (or not at all). Only the exec
// root is safe to substitute.
Self::escape_for_serializing(Self::redact_exec_root(env, exec_root))
))
} else {
None
Expand Down Expand Up @@ -321,7 +327,7 @@ mod tests {
BuildScriptOutput::Env("no_trailing_newline=true".to_owned())
);
assert_eq!(
BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path", ""),
BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path"),
"DEP_SSH2_VERSION=123\nDEP_SSH2_VERSION_NUMBER=1010107f\nDEP_SSH2_INCLUDE_PATH=${pwd}/include".to_owned()
);
assert_eq!(
Expand Down Expand Up @@ -478,6 +484,27 @@ cargo::rustc-env=BAR=/abs/exec_root/elsewhere/file.rs
);
}

/// Verify that `DEP_*` values referencing the producer's `out_dir` keep
/// the real path (with only the exec root substituted). Dep env files are
/// consumed by *downstream* crates' build scripts, whose runner only
/// substitutes `${pwd}` and whose own `out_dir` points to a different
/// directory, so a `${out_dir}` token would be left unresolved (e.g.
/// libssh2-sys failing to find `zlib.h` from libz-sys's `DEP_Z_INCLUDE`).
#[test]
fn out_dir_in_dep_env_value_is_not_redacted_to_substitution_token() {
let buff = Cursor::new(
"
cargo::include=/abs/exec_root/bazel-out/cfg/bin/pkg/_bs.out_dir/include
",
);
let reader = BufReader::new(buff);
let result = BuildScriptOutput::outputs_from_reader(reader, true);
assert_eq!(
BuildScriptOutput::outputs_to_dep_env(&result, "z", "/abs/exec_root"),
"DEP_Z_INCLUDE=${pwd}/bazel-out/cfg/bin/pkg/_bs.out_dir/include"
);
}

/// Link search paths use the full `out_dir` path as the substitution
/// key so each build script gets a unique token. This avoids
/// collisions when the flag file is consumed transitively by a target
Expand Down
28 changes: 28 additions & 0 deletions cargo/tests/dep_env/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ cargo_build_script(
links = "Y",
)

cargo_build_script(
name = "set_out_dir_build",
srcs = ["set_out_dir.rs"],
edition = "2018",
links = "Z",
)

rust_library(
name = "set_a",
srcs = ["empty.rs"],
Expand Down Expand Up @@ -52,6 +59,13 @@ rust_library(
],
)

rust_library(
name = "set_out_dir",
srcs = ["empty.rs"],
edition = "2018",
deps = [":set_out_dir_build"],
)

cargo_build_script(
name = "read_a",
srcs = ["read_a.rs"],
Expand Down Expand Up @@ -89,6 +103,13 @@ cargo_build_script(
link_deps = [":set_dep_dir"],
)

cargo_build_script(
name = "read_out_dir",
srcs = ["read_out_dir.rs"],
edition = "2018",
link_deps = [":set_out_dir"],
)

rust_test(
name = "build_read_a",
srcs = ["read_a.rs"],
Expand Down Expand Up @@ -117,6 +138,13 @@ rust_test(
deps = [":read_dep_dir"],
)

rust_test(
name = "build_read_out_dir",
srcs = ["read_out_dir.rs"],
edition = "2018",
deps = [":read_out_dir"],
)

create_dep_dir(
name = "dep_dir",
)
Expand Down
22 changes: 22 additions & 0 deletions cargo/tests/dep_env/read_out_dir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::env::var;
use std::path::PathBuf;

fn main() {
// Mirrors sys-crates like libssh2-sys consuming libz-sys: the producer's
// build script advertised `$OUT_DIR/include` via `cargo:include=`, which
// must arrive here as a resolvable path. A `${out_dir}` substitution
// token would be left unresolved because only `${pwd}` is substituted in
// dep env files, and the consumer's own OUT_DIR is a different directory.
let include = var("DEP_Z_INCLUDE").expect("DEP_Z_INCLUDE should be set");
assert!(
!include.contains("${out_dir}"),
"DEP_Z_INCLUDE contains an unresolved ${{out_dir}} token: {}",
include
);
let header = PathBuf::from(&include).join("header.h");
assert!(
header.is_file(),
"DEP_Z_INCLUDE does not point at the producer's OUT_DIR: {}",
header.display()
);
}
14 changes: 14 additions & 0 deletions cargo/tests/dep_env/set_out_dir.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use std::env::var;
use std::fs;
use std::path::PathBuf;

fn main() {
// Mirrors sys-crates like libz-sys: generate a header into OUT_DIR and
// advertise its location to dependents via a `cargo:include=` metadata
// key, which downstream build scripts receive as `DEP_Z_INCLUDE`.
let out_dir = PathBuf::from(var("OUT_DIR").expect("OUT_DIR should be set"));
let include_dir = out_dir.join("include");
fs::create_dir_all(&include_dir).expect("Failed to create include dir");
fs::write(include_dir.join("header.h"), "// generated\n").expect("Failed to write header");
println!("cargo:include={}", include_dir.display());
}
Loading