Skip to content

Commit 175bf94

Browse files
authored
Add support for experimental_output_paths (#4011)
For details on path mapping see bazelbuild/bazel#22658 Changes: - The process wrapper now explicitly handles `out_dir` to avoid location expanded environment variables. - `construct_arguments` is updated to support `rustc_flags` as an `Args` object. `List` is still supported though
1 parent 72c67cd commit 175bf94

12 files changed

Lines changed: 766 additions & 329 deletions

File tree

.bazelci/presubmit.yml

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -377,43 +377,100 @@ tasks:
377377
platform: ubuntu2204
378378
run_targets:
379379
- "//test/rustfmt:rustfmt_failure_tester"
380-
rust_analyzer_tests_linux:
381-
name: Rust-Analyzer Linux Tests
380+
ide_integration_tests_linux:
381+
name: IDE VSCode Tests
382382
platform: ubuntu2204
383383
run_targets:
384+
- "//tools/vscode:gen_launch_json"
385+
- "//test/vscode:vscode_test"
384386
- "//tools/rust_analyzer:gen_rust_project"
385387
- "//tools/rust_analyzer:discover_bazel_rust_project"
386388
- "//test/rust_analyzer:rust_analyzer_test"
387-
rust_analyzer_tests_macos:
388-
name: Rust-Analyzer Macos Tests
389+
ide_integration_tests_macos:
390+
name: IDE VSCode Tests
389391
platform: macos_arm64
390392
run_targets:
393+
- "//tools/vscode:gen_launch_json"
394+
- "//test/vscode:vscode_test"
391395
- "//tools/rust_analyzer:gen_rust_project"
392396
- "//tools/rust_analyzer:discover_bazel_rust_project"
393397
- "//test/rust_analyzer:rust_analyzer_test"
394-
rust_analyzer_tests_windows:
395-
name: Rust-Analyzer Windows Tests
398+
ide_integration_tests_windows:
399+
name: IDE VSCode Tests
396400
platform: windows
397401
run_targets:
402+
- "//tools/vscode:gen_launch_json"
398403
- "//tools/rust_analyzer:gen_rust_project"
399404
- "//tools/rust_analyzer:discover_bazel_rust_project"
400-
ide_integration_vscode_tests_linux:
401-
name: IDE VSCode Tests
405+
# TODO: Enable rust-analyzer tests on windows.
406+
# - "//test/rust_analyzer:rust_analyzer_test"
407+
408+
path_mapping_ubuntu2204:
409+
name: Path Mapping Linux
402410
platform: ubuntu2204
403-
run_targets:
404-
- "//tools/vscode:gen_launch_json"
405-
- "//test/vscode:vscode_test"
406-
ide_integration_vscode_tests_macos:
407-
name: IDE VSCode Tests
411+
build_flags:
412+
- --config=clippy
413+
- --config=rustfmt
414+
- --experimental_output_paths=strip
415+
test_flags:
416+
- --config=clippy
417+
- --config=rustfmt
418+
- --experimental_output_paths=strip
419+
build_targets: *default_linux_targets
420+
test_targets: *default_linux_targets
421+
coverage_targets: *default_linux_targets
422+
post_shell_commands: *coverage_validation_post_shell_commands
423+
path_mapping_rbe_ubuntu2204:
424+
name: Path Mapping RBE
425+
platform: rbe_ubuntu2204
426+
shell_commands:
427+
- sed -i 's/^# load("@bazel_ci_rules/load("@bazel_ci_rules/' WORKSPACE.bazel
428+
- sed -i 's/^# rbe_preconfig/rbe_preconfig/' WORKSPACE.bazel
429+
build_flags:
430+
- --config=clippy
431+
- --config=rustfmt
432+
- --experimental_output_paths=strip
433+
test_flags:
434+
- --config=clippy
435+
- --config=rustfmt
436+
- --experimental_output_paths=strip
437+
build_targets: *default_rbe_targets
438+
test_targets: *default_rbe_targets
439+
coverage_targets: *default_rbe_targets
440+
coverage_flags: *rbe_coverage_flags
441+
post_shell_commands: *coverage_validation_post_shell_commands
442+
path_mapping_macos:
443+
name: Path Mapping MacOS
408444
platform: macos_arm64
409-
run_targets:
410-
- "//tools/vscode:gen_launch_json"
411-
- "//test/vscode:vscode_test"
412-
ide_integration_vscode_tests_windows:
413-
name: IDE VSCode Tests
414-
platform: windows
415-
run_targets:
416-
- "//tools/vscode:gen_launch_json"
445+
build_flags:
446+
- --config=clippy
447+
- --config=rustfmt
448+
- --experimental_output_paths=strip
449+
test_flags:
450+
- --config=clippy
451+
- --config=rustfmt
452+
- --experimental_output_paths=strip
453+
build_targets: *default_macos_targets
454+
test_targets: *default_macos_targets
455+
coverage_targets: *default_macos_targets
456+
post_shell_commands: *coverage_validation_post_shell_commands
457+
# TODO: path_mapping requires sandboxing
458+
# https://github.com/bazelbuild/bazel/issues/7480
459+
#
460+
# path_mapping_windows:
461+
# name: Path Mapping Windows
462+
# platform: windows
463+
# build_flags:
464+
# - --config=clippy
465+
# - --config=rustfmt
466+
# - --experimental_output_paths=strip
467+
# test_flags:
468+
# - --config=clippy
469+
# - --config=rustfmt
470+
# - --experimental_output_paths=strip
471+
# build_targets: *default_windows_targets
472+
# test_targets: *default_windows_targets
473+
417474
###########################################################################
418475
# C R A T E U N I V E R S E I N T E G R A T I O N T E S T S
419476
###########################################################################

cargo/private/cargo_build_script_runner/bin.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn run_buildrs() -> Result<(), String> {
5353

5454
cargo_manifest_maker.create_runfiles_dir().unwrap();
5555

56-
let out_dir_abs = exec_root.join(out_dir);
56+
let out_dir_abs = exec_root.join(&out_dir);
5757
// For some reason Google's RBE does not create the output directory, force create it.
5858
create_dir_all(&out_dir_abs)
5959
.unwrap_or_else(|_| panic!("Failed to make output directory: {:?}", out_dir_abs));
@@ -176,7 +176,7 @@ fn run_buildrs() -> Result<(), String> {
176176

177177
write(
178178
&env_file,
179-
BuildScriptOutput::outputs_to_env(&buildrs_outputs, &exec_root.to_string_lossy())
179+
BuildScriptOutput::outputs_to_env(&buildrs_outputs, &exec_root.to_string_lossy(), &out_dir)
180180
.as_bytes(),
181181
)
182182
.unwrap_or_else(|e| panic!("Unable to write file {:?}: {:#?}", env_file, e));
@@ -186,6 +186,7 @@ fn run_buildrs() -> Result<(), String> {
186186
&buildrs_outputs,
187187
&crate_links,
188188
&exec_root.to_string_lossy(),
189+
&out_dir,
189190
)
190191
.as_bytes(),
191192
)
@@ -204,7 +205,11 @@ fn run_buildrs() -> Result<(), String> {
204205
compile_flags,
205206
link_flags,
206207
link_search_paths,
207-
} = BuildScriptOutput::outputs_to_flags(&buildrs_outputs, &exec_root.to_string_lossy());
208+
} = BuildScriptOutput::outputs_to_flags(
209+
&buildrs_outputs,
210+
&exec_root.to_string_lossy(),
211+
&out_dir,
212+
);
208213

209214
write(&compile_flags_file, compile_flags.as_bytes())
210215
.unwrap_or_else(|e| panic!("Unable to write file {:?}: {:#?}", compile_flags_file, e));

cargo/private/cargo_build_script_runner/lib.rs

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ impl BuildScriptOutput {
158158
}
159159

160160
/// Convert a vector of [BuildScriptOutput] into a list of environment variables.
161-
pub fn outputs_to_env(outputs: &[BuildScriptOutput], exec_root: &str) -> String {
161+
pub fn outputs_to_env(outputs: &[BuildScriptOutput], exec_root: &str, out_dir: &str) -> String {
162162
outputs
163163
.iter()
164164
.filter_map(|x| {
165165
if let BuildScriptOutput::Env(env) = x {
166-
Some(Self::escape_for_serializing(Self::redact_exec_root(
167-
env, exec_root,
166+
Some(Self::escape_for_serializing(Self::redact_paths(
167+
env, exec_root, out_dir,
168168
)))
169169
} else {
170170
None
@@ -179,6 +179,7 @@ impl BuildScriptOutput {
179179
outputs: &[BuildScriptOutput],
180180
crate_links: &str,
181181
exec_root: &str,
182+
out_dir: &str,
182183
) -> String {
183184
let prefix = format!("DEP_{}_", crate_links.replace('-', "_").to_uppercase());
184185
outputs
@@ -188,7 +189,7 @@ impl BuildScriptOutput {
188189
Some(format!(
189190
"{}{}",
190191
prefix,
191-
Self::escape_for_serializing(Self::redact_exec_root(env, exec_root))
192+
Self::escape_for_serializing(Self::redact_paths(env, exec_root, out_dir))
192193
))
193194
} else {
194195
None
@@ -199,7 +200,11 @@ impl BuildScriptOutput {
199200
}
200201

201202
/// Convert a vector of [BuildScriptOutput] into a flagfile.
202-
pub fn outputs_to_flags(outputs: &[BuildScriptOutput], exec_root: &str) -> CompileAndLinkFlags {
203+
pub fn outputs_to_flags(
204+
outputs: &[BuildScriptOutput],
205+
exec_root: &str,
206+
out_dir: &str,
207+
) -> CompileAndLinkFlags {
203208
let mut compile_flags = Vec::new();
204209
let mut link_flags = Vec::new();
205210
let mut link_search_paths = Vec::new();
@@ -217,13 +222,38 @@ impl BuildScriptOutput {
217222

218223
CompileAndLinkFlags {
219224
compile_flags: compile_flags.join("\n"),
220-
link_flags: Self::redact_exec_root(&link_flags.join("\n"), exec_root),
221-
link_search_paths: Self::redact_exec_root(&link_search_paths.join("\n"), exec_root),
225+
link_flags: Self::redact_paths(&link_flags.join("\n"), exec_root, out_dir),
226+
link_search_paths: Self::redact_paths(
227+
&link_search_paths.join("\n"),
228+
exec_root,
229+
out_dir,
230+
),
222231
}
223232
}
224233

225-
fn redact_exec_root(value: &str, exec_root: &str) -> String {
226-
value.replace(exec_root, "${pwd}")
234+
/// Replace the absolute exec-root with `${pwd}` and the relative
235+
/// configuration-dependent `out_dir` path (e.g.
236+
/// `bazel-out/<config>/bin/.../_bs.out_dir`) with `${out_dir}`.
237+
///
238+
/// Both tokens are substituted by `process_wrapper` at action
239+
/// execution time. Routing the `out_dir` portion through
240+
/// `${out_dir}` lets Bazel's path mapping
241+
/// (`--experimental_output_paths=strip`) rewrite it: the consumer
242+
/// `Rustc` action passes the directory to `process_wrapper` via
243+
/// `--out-dir <File>` from a `File`-typed `Args` entry, so the value
244+
/// is the mapped `bazel-out/cfg/bin/...` path under path mapping and
245+
/// the un-mapped path otherwise. Without this redaction,
246+
/// build-script-emitted env vars (e.g. `cargo::rustc-env=FOO=$OUT_DIR/bar`)
247+
/// would carry the un-mapped path through the `_bs.env` file and
248+
/// cause the path-mapped Rustc action to look in the wrong location
249+
/// at runtime.
250+
fn redact_paths(value: &str, exec_root: &str, out_dir: &str) -> String {
251+
let with_pwd = value.replace(exec_root, "${pwd}");
252+
if out_dir.is_empty() {
253+
with_pwd
254+
} else {
255+
with_pwd.replace(out_dir, "${out_dir}")
256+
}
227257
}
228258

229259
// The process-wrapper treats trailing backslashes as escapes for following newlines.
@@ -283,15 +313,15 @@ mod tests {
283313
BuildScriptOutput::Env("no_trailing_newline=true".to_owned())
284314
);
285315
assert_eq!(
286-
BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path"),
316+
BuildScriptOutput::outputs_to_dep_env(&result, "ssh2", "/some/absolute/path", ""),
287317
"DEP_SSH2_VERSION=123\nDEP_SSH2_VERSION_NUMBER=1010107f\nDEP_SSH2_INCLUDE_PATH=${pwd}/include".to_owned()
288318
);
289319
assert_eq!(
290-
BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path"),
320+
BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path", ""),
291321
"FOO=BAR\nBAR=FOO\nSOME_PATH=${pwd}/beep\nno_trailing_newline=true".to_owned()
292322
);
293323
assert_eq!(
294-
BuildScriptOutput::outputs_to_flags(&result, "/some/absolute/path"),
324+
BuildScriptOutput::outputs_to_flags(&result, "/some/absolute/path", ""),
295325
CompileAndLinkFlags {
296326
// -Lblah was output as a rustc-flags, so even though it probably _should_ be a link
297327
// flag, we don't treat it like one.
@@ -366,7 +396,7 @@ cargo::rustc-env=valid2=2
366396
let result = BuildScriptOutput::outputs_from_reader(reader);
367397
assert_eq!(result.len(), 2);
368398
assert_eq!(
369-
&BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path"),
399+
&BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path", ""),
370400
"valid1=1\nvalid2=2"
371401
);
372402
}
@@ -385,7 +415,7 @@ cargo:rustc-env=valid2=2
385415
let result = BuildScriptOutput::outputs_from_reader(reader);
386416
assert_eq!(result.len(), 2);
387417
assert_eq!(
388-
&BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path"),
418+
&BuildScriptOutput::outputs_to_env(&result, "/some/absolute/path", ""),
389419
"valid1=1\nvalid2=2"
390420
);
391421
}
@@ -399,4 +429,32 @@ cargo:rustc-env=valid2=2
399429
vec![BuildScriptOutput::DepEnv("VERSION_1_10_0=1".to_owned())]
400430
);
401431
}
432+
433+
/// Verify that a build-script-emitted env var that references the
434+
/// `out_dir` (e.g. `cargo::rustc-env=FOO=$OUT_DIR/bar`) is rewritten
435+
/// to use the `${out_dir}` substitution token. `process_wrapper`
436+
/// substitutes the token at action execution time using the value
437+
/// from its `--out-dir` arg, which is sourced from a `File`-typed
438+
/// `Args` entry on the rules_rust side and therefore picks up Bazel
439+
/// path mapping (`--experimental_output_paths=strip`) when the
440+
/// consumer Rustc action advertises `supports-path-mapping`.
441+
#[test]
442+
fn out_dir_in_env_value_is_redacted_to_substitution_token() {
443+
let buff = Cursor::new(
444+
"
445+
cargo::rustc-env=FOO=/abs/exec_root/bazel-out/cfg/bin/_bs.out_dir/op.rs
446+
cargo::rustc-env=BAR=/abs/exec_root/elsewhere/file.rs
447+
",
448+
);
449+
let reader = BufReader::new(buff);
450+
let result = BuildScriptOutput::outputs_from_reader(reader);
451+
assert_eq!(
452+
BuildScriptOutput::outputs_to_env(
453+
&result,
454+
"/abs/exec_root",
455+
"bazel-out/cfg/bin/_bs.out_dir",
456+
),
457+
"FOO=${pwd}/${out_dir}/op.rs\nBAR=${pwd}/elsewhere/file.rs"
458+
);
459+
}
402460
}

0 commit comments

Comments
 (0)