diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl index 6f375defb7..484e35d34e 100644 --- a/rust/private/rust.bzl +++ b/rust/private/rust.bzl @@ -1060,6 +1060,13 @@ def _common_attrs_for_binary_without_process_wrapper(attrs): cfg = "exec", ) + new_attr["_bootstrap_process_wrapper"] = attr.label( + default = Label("//util/process_wrapper:bootstrap_process_wrapper"), + executable = True, + allow_single_file = True, + cfg = "exec", + ) + # fix stamp = 0 new_attr["stamp"] = attr.int( doc = dedent("""\ diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 9ba3115e76..1da062d923 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -1300,16 +1300,16 @@ def rustc_compile_action( ), toolchain = "@rules_rust//rust:toolchain_type", ) - else: + elif hasattr(ctx.executable, "_bootstrap_process_wrapper"): # Run without process_wrapper if build_env_files or build_flags_files or stamp or build_metadata: fail("build_env_files, build_flags_files, stamp, build_metadata are not supported when building without process_wrapper") ctx.actions.run( - executable = toolchain.rustc, + executable = ctx.executable._bootstrap_process_wrapper, inputs = compile_inputs, outputs = action_outputs, env = env, - arguments = [args.rustc_flags], + arguments = [args.rustc_path, args.rustc_flags], mnemonic = "Rustc", progress_message = "Compiling Rust (without process_wrapper) {} {}{} ({} files)".format( crate_info.type, @@ -1319,6 +1319,8 @@ def rustc_compile_action( ), toolchain = "@rules_rust//rust:toolchain_type", ) + else: + fail("No process wrapper was defined for {}".format(ctx.label)) if experimental_use_cc_common_link: # Wrap the main `.o` file into a compilation output suitable for diff --git a/util/process_wrapper/BUILD.bazel b/util/process_wrapper/BUILD.bazel index c5276dd9cb..80fbbaabb7 100644 --- a/util/process_wrapper/BUILD.bazel +++ b/util/process_wrapper/BUILD.bazel @@ -1,12 +1,45 @@ +load("@bazel_skylib//lib:selects.bzl", "selects") +load("@bazel_skylib//rules:native_binary.bzl", "native_binary") load("//rust:defs.bzl", "rust_test") # buildifier: disable=bzl-visibility load("//rust/private:rust.bzl", "rust_binary_without_process_wrapper") +config_setting( + name = "compilation_mode_opt", + values = {"compilation_mode": "opt"}, +) + +selects.config_setting_group( + name = "opt_linux", + match_all = [ + ":compilation_mode_opt", + "@platforms//os:linux", + ], + visibility = ["@rules_rust_tinyjson//:__pkg__"], +) + +selects.config_setting_group( + name = "opt_macos", + match_all = [ + ":compilation_mode_opt", + "@platforms//os:macos", + ], + visibility = ["@rules_rust_tinyjson//:__pkg__"], +) + rust_binary_without_process_wrapper( name = "process_wrapper", srcs = glob(["*.rs"]), edition = "2018", + # To ensure the process wrapper is produced deterministically + # debug info, which is known to sometimes have host specific + # paths embedded in this section, is stripped out. + rustc_flags = select({ + ":opt_linux": ["-Cstrip=debuginfo"], + ":opt_macos": ["-Cstrip=debuginfo"], + "//conditions:default": [], + }), visibility = ["//visibility:public"], deps = [ "@rules_rust_tinyjson//:tinyjson", @@ -18,3 +51,16 @@ rust_test( crate = ":process_wrapper", edition = "2018", ) + +native_binary( + name = "bootstrap_process_wrapper", + src = select({ + "@platforms//os:windows": "process_wrapper.bat", + "//conditions:default": "process_wrapper.sh", + }), + out = select({ + "@platforms//os:windows": "process_wrapper.bat", + "//conditions:default": "process_wrapper.sh", + }), + visibility = ["//visibility:public"], +) diff --git a/util/process_wrapper/BUILD.tinyjson.bazel b/util/process_wrapper/BUILD.tinyjson.bazel index 31f9da24f3..f8013f6efd 100644 --- a/util/process_wrapper/BUILD.tinyjson.bazel +++ b/util/process_wrapper/BUILD.tinyjson.bazel @@ -5,5 +5,13 @@ rust_library_without_process_wrapper( name = "tinyjson", srcs = glob(["src/*.rs"]), edition = "2018", + # To ensure the process wrapper is produced deterministically + # debug info, which is known to sometimes have host specific + # paths embedded in this section, is stripped out. + rustc_flags = select({ + "@rules_rust//util/process_wrapper:opt_linux": ["-Cstrip=debuginfo"], + "@rules_rust//util/process_wrapper:opt_macos": ["-Cstrip=debuginfo"], + "//conditions:default": [], + }), visibility = ["@rules_rust//util/process_wrapper:__pkg__"], ) diff --git a/util/process_wrapper/process_wrapper.bat b/util/process_wrapper/process_wrapper.bat new file mode 100644 index 0000000000..36fff8699a --- /dev/null +++ b/util/process_wrapper/process_wrapper.bat @@ -0,0 +1,31 @@ +@ECHO OFF +SETLOCAL enabledelayedexpansion + +SET command=%* + +:: Resolve the `${pwd}` placeholders +SET command=!command:${pwd}=%CD%! + +:: Strip out the leading `--` argument. +SET command=!command:~3! + +:: Find the rustc.exe argument and sanitize it's path +for %%A in (%*) do ( + SET arg=%%~A + if "!arg:~-9!"=="rustc.exe" ( + SET sanitized=!arg:/=\! + + SET command=!sanitized! !command:%%~A=! + goto :break + ) +) + +:break + +%command% + +:: Capture the exit code of rustc.exe +SET exit_code=!errorlevel! + +:: Exit with the same exit code +EXIT /b %exit_code% diff --git a/util/process_wrapper/process_wrapper.sh b/util/process_wrapper/process_wrapper.sh new file mode 100755 index 0000000000..97b3478c9f --- /dev/null +++ b/util/process_wrapper/process_wrapper.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Skip the first argument which is expected to be `--` +shift + +args=() + +for arg in "$@"; do + # Check if the argument contains "${PWD}" and replace it with the actual value of PWD + if [[ "${arg}" == *'${pwd}'* ]]; then + arg="${arg//\$\{pwd\}/$PWD}" + fi + args+=("${arg}") +done + +exec "${args[@]}"