Skip to content

fix(cargo_build_script): keep real OUT_DIR path in cross-crate dep-env#4104

Open
esnunes wants to merge 1 commit into
bazelbuild:mainfrom
esnunes:fix/cross-crate-dep-env-out-dir
Open

fix(cargo_build_script): keep real OUT_DIR path in cross-crate dep-env#4104
esnunes wants to merge 1 commit into
bazelbuild:mainfrom
esnunes:fix/cross-crate-dep-env-out-dir

Conversation

@esnunes

@esnunes esnunes commented Jun 25, 2026

Copy link
Copy Markdown

Summary

Fixes #4103.

A links (-sys) crate whose build script exposes an OUT_DIR-relative path through the metadata convention (cargo:include=$OUT_DIR/include) propagated DEP_<LINKS>_INCLUDE to a dependent build script with the producing crate's OUT_DIR rewritten to the literal, unresolved ${out_dir} token — e.g. the dependent saw DEP_LZ4_INCLUDE=<execroot>/${out_dir}/include, which does not exist, so librocksdb-sys could not find lz4.h.

This is a regression from #4011 (experimental_output_paths, refined by #4050), which introduced the ${out_dir} tokenization of build-script outputs. It is on main only — the latest release 0.70.0 predates #4011 and is unaffected.

Root cause

outputs_to_dep_env redacted values with redact_paths, rewriting the producing crate's out_dir to the generic ${out_dir} token. That token is only resolved by process_wrapper's --out-dir for the crate that directly owns the build script. A .depenv file is instead consumed by a dependent crate's build-script runner (bin.rs), which only substitutes ${pwd} and has no ${out_dir} binding for another crate's out_dir — so the token survives unresolved.

This is the same transitive-consumption scenario redact_flags was written for (per-build-script tokens plus matching --subst entries added on the Starlark side). The dep-env path was left on the generic-token codepath, which has no resolution mechanism on the consuming side.

Fix

outputs_to_dep_env now redacts only the exec root (${pwd}) and keeps the producing crate's real out_dir-relative path. Safe because:

  • the consumer (bin.rs) already resolves ${pwd};
  • the producing crate's out_dir tree is already a declared input of the dependent build-script action at that same exec-root-relative path;
  • build-script actions do not advertise supports-path-mapping, so --experimental_output_paths=strip never rewrites the literal path;
  • the producing crate's own .env file (outputs_to_env) still uses ${out_dir}, so path-mapping cache-shareability for the owning target is unchanged.

Tests

  • Unit (cargo/private/cargo_build_script_runner): dep_env_out_dir_is_preserved_not_tokenized and a Windows variant assert the dep-env keeps the real path with only ${pwd} tokenized.
  • End-to-end (test/cargo_build_script/metadata_dep_env): the producer now exposes an OUT_DIR-relative include/ via cargo:include=, and include_test.rs asserts the dependent build script receives a resolved, existing path (red before the fix, green after).

Reported downstream as hermeticbuild/rules_rs#163.

🤖 Generated with Claude Code

@google-cla

google-cla Bot commented Jun 25, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

A `links` crate whose build script exposes an OUT_DIR-relative path via the
metadata convention (e.g. `cargo:include=$OUT_DIR/include`) propagated
`DEP_<LINKS>_INCLUDE` to a dependent build script with the producing crate's
OUT_DIR rewritten to a literal `${out_dir}` token. That token is only resolved
by process_wrapper's `--out-dir` for the crate that directly owns the build
script; a cross-crate `.depenv` is consumed by a *dependent* crate's
build-script runner (`bin.rs`), which resolves only `${pwd}`. The token
survived unresolved, so e.g. librocksdb-sys could not find `lz4.h`.

`outputs_to_dep_env` now redacts only the exec root and keeps the producing
crate's real out_dir-relative path. This is the same transitive-consumption
case `redact_flags` handles with per-build-script tokens; the dep-env path has
no such resolution on the consuming side, so emit the real path. It is safe
because build-script actions do not advertise `supports-path-mapping`, and the
producing crate's out_dir tree is already a declared input of the dependent
action at that path. The producing crate's own `.env` file still uses
`${out_dir}`, so path-mapping cache-shareability is unchanged.

Adds unit tests (unix + windows) and an end-to-end regression test.

Fixes bazelbuild#4103.
@esnunes esnunes force-pushed the fix/cross-crate-dep-env-out-dir branch from ecc3509 to c5510c9 Compare June 25, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cargo_build_script: DEP_<links>_<KEY> values pointing into OUT_DIR reach dependent build scripts with an unresolved ${out_dir} token

1 participant