Squashed 'third_party/rules_rust/' changes from bf59038cac..078c6908fc

078c6908fc add cc_common.link support for rust_library and rust_test (#1490)
c07aef0287 Skip supplying rpaths on Fuchsia (#1511)
6ee7c80bdb Propagate rustc_env{,_files} from rust_test.crate (#1443)
1cd0788d2a Apply get_lib_name correctly to the C++ runtime libraries (#1508)
90808f0dc4 Minor cleanup to documentation (#1505)
735640f2df Enable rust-analyzer tests on windows. (#1506)
0f34573166 Updated rules_rust to version 0.9.0 (#1503)
9b61b49934 Promoted crate_universe to non-experimental (#1504)
76360dd354 Implement rules archive release artifact in github action. (#1501)
4e5fac5980 Do not pass `--Clink-arg=-l` for libstd and libtest (#1500)
6c38934636 pipelining: add the ability to disable pipelining for a single rule. (#1499)
867fc37c17 rules_rust: enable pipelined compilation. (#1275)
c97f255dfe Delete deprecated targets (#1496)
43b42884a7 Updated examples to use crate_universe (#1494)
0ffde973e8 Updated `//util/import` to use crate_universe (#1492)
83a03ab03e Updated proto rules to fetch dependencies using crate_universe (#1491)
67e204ff22 fix: `rust_doc_test` failure to find params file (#1418)
0fc834bdfa Updated all toolchain_type definitions to be named `toolchain_type`. (#1479)
3be056a7a3 toolchain files: ensure test depends on std (#1486)
228ebfa6eb Updated rules_rust to version `0.8.1`. (#1484)
685dfda497 Fixed use of rust-analyzer with rust_static_library and rust_shared_library (#1482)
2d7f94543f Fix rust-analyzer being unable to find rust sysroot sources. (#1483)
81a77acde2 Updated rules_rust to version `0.8.0`. (#1472)
caad908848 Give useful error on missing workspace manifest (#1475)
0e86b9dd30 Added `rust_analyzer_toolchain` and repository rules for creating one (#1455)
838e4ea828 Update docs on lockfiles (#1477)
fce1222628 Fix typo in function name (#1478)
1929bfbc3e Added Rust version 1.62.1 (#1476)
9a8e878d3d Fix `rust_binary_without_process_wrapper` build with `--stamp` (#1473)
25baabc205 Updated bindgen version (#1470)
8c9d5c7051 Updated rust-analyzer generator to use clap (#1471)
6d8009dbc8 Update `//bindgen` to use `crate_universe` (#1440)
67c97d44ff Updated `tools/rust_analyzer` to use `crate_universe`. (#1448)
6c285eb28e Updated `wasm_bindgen` rules dependencies. (#1464)
82a437cc17 Fixed crate_universe lockfile checks for crates_repository rule (#1468)
e83d5f3c77 Limit coverage to requested files (#1467)
daff327ea7 Stamp only binaries by default (#1452)
adc80a301d Cleanup crate_universe dependency macros (#1460)
824b121acc Updated header of crate_universe generated files to include a regen command (#1461)
d44e1d8363 feat: add `rustc_flags` attr to `rust_doc` rule (#1458)
6b54feb0ff add a way to distinguish proc-macro deps (#1420)
6070b3c9f4 Fixed missing items in distro artifact (#1450)
1e83e74159 do not add proc-macro deps to transitive_link_search_paths (#1424)
ced94dec1b Fix @libgit2 (#1457)
03d1d5e4ac Add extra_rustc_flag and extra_exec_rustc_flag (#1413)
711adc7985 crate_universe: shorten `crate_universe_crate_index` to `cui` (#1454)
8cb9247f18 Replaced small genrules with uses of bazel_skylib (#1451)
38e841aece Upgrade stardoc (#1444)
674762f66a Updated toolchain repository rules to represent one toolchain per repo (#1442)
b22a6e1416 Re-enable disabled windows jobs in CI (#1353)
2fb94c48fd docs: Update homepage to use latest version (#1441)
389c58fcb1 Updated rules_rust to version `0.7.0`. (#1436)
60f26d49d8 exclude `BUILD` and `WORKSPACE` files from generated crate_universe targets (#1437)
26344d4cd7 Have rust_test put its compilation outputs in a subdirectory (#1434)
8b0f644122 Updated crate_universe version to `0.4.0`. (#1435)
adf92b1534 update crate_universe `--repin` args to not require values. (#1433)
da75146d0a Do not attempt to instrument rust code for coverage if rust_toolchain.llvm-cov is None (#1432)
bde2c36821 Added Rust 1.62.0 (#1427)
7056f22bd0 Fixed crate_universe not finding target library names for "rlib"s (#1429)
3d65214d23 crate_universe support for individually updating packages. (#1426)
5a9d999db9 Updated `attr.label` attribute defaults to use `Label` constructor (#1422)
52fc70145a Added `TemplateVariableInfo` to `rust_toolchain`. (#1416)
7465c1aa29 Add test coverage support (#1324)
c5c3603da6 Bump the min supported bazel version (#1414)
937bdc9d05 Add a `cargo_dep_env` rule for setting build.rs environment variables (#1415)
91466fc0d1 Updated `rules_rust` version to `0.6.0`. (#1397)
97264b79d5 Update wasm_bindgen to use crate universe. (#1398)
d3197a65c5 Updated crate_universe version (to `0.3.0`) and dependencies (#1409)
a15e67d666 Deleted "extra workspace member" functionality from crate_universe (#1406)
5910a7585a Use a vec, not set for rustc_flags for crate_universe annotations (#1404)
3aa88ab067 Deleted deprecated `rust_analyzer` rule. (#1405)
7adf7210d0 cargo: Fix handling of relative sysroots (#1371)
57607239ec Enable rustfmt CI for Windows. (#1403)
30e68b49be Added more "ignore" tags to rustfmt and clippy rules. (#1400)
53ad14eead Added support for vendoring external manifests (#1381)
ff243c6ef0 Reorganized rustfmt source tree (#1399)
94e0044afe Refactored the Rustfmt tool to work cross-platform (#1375)
8fca438124 Ran clang-format on all C++ sources (#1396)
e765719e29 Added TemplateVariableInfo to rust_toolchain (#1377)
81590f4b6a Fixed Clippy bug with `--@rules_rust//:clippy_flags`. (#1392)
d77b9f7c6a Use  `target_compatible_with` to make `macos` with `Xcode` happy (#1391)
ec27dbe310 Added comments to internal function (#1378)
a9dd2f9200 Removed deprecated file (#1380)
16175c881c Renamed toolchain files targets (#1376)
c7cb5bd7a8 Support crates that have mix of generated and nongenerated inputs (#1340)
521e649ff4 Avoid using common substrings as encodings. (#1370)
28ac6b133d Use a more compact encoding in the `import` macro. (#1365)
3a099bfa97 Fix incorrect assertion in test_env_launcher test (#1368)
4661093fb1 Use target instead of rule in rust_register_toolchains edition docs (#1366)
652f2802e3 Add `env` attribute to `rust_toolchain`. (#1363)
9520f37f1e Update rules_perl in examples (#1364)
1b451c301e Add armv7-linux-androideabi tier 2 triple (#1362)
0265c293f1 Ensure crate_features to be included correctly in rust_project.json (#1356)
121d65fe6a Updated `rules_rust` version to `0.5.0` (#1360)
aca4ec1a0f crate_universe: fix typo (#1314)
69ca2611c5 Don't leak native dependencies of proc_macro (#1359)
4c7f08b8b9 Fixed missing docs (#1358)
e48bec94de feat: build script toolchains annotations (#1344)
ffb946f4b7 Ensure memchr is linked after libobject (#1349)
edca1d8042 Add developing notes for crate_universe (#1351)
120f911d2f Updated rust_bindgen dependencies API (#1354)
42c4528a5f Added Rust 1.61.0 (#1347)
c05e0c6ab1 Fixed fetch_shas script to correctly include .gz and .xz extensions (#1355)
9770b0dd75 Update apple_support (#1346)
87eb807e67 Added support for Rust 1.61.0 to crate_universe (#1348)
84c1d42128 Temporarily disable windows job in CI. (#1352)
421d30e4ff Remove unnecessary `crate_name` usage in `rust_test_suite`. (#1345)
10185339dd Build `rust_test` targets with `crate` using the same crate name as the underlying library target. (#1332)
0049ce3884 Add support for riscv32 targets (#1323)
3aa6de3c63 remove experimental_use_whole_archive_for_native_deps (#1338)
a066bfed46 Replace slashes with underscores in default crate names. (#1336)
1b91e592d5 Revert "Replace slashes with underscores in default crate names. (#1334)" (#1335)
51f8e302e9 "sandwich" rlibs between native deps in linker order (#1333)
df354904a1 Replace slashes with underscores in default crate names. (#1334)
21eed19188 Bump version to 0.4.0 (#1329)
d3d9abac4d Support . workspace member (#1326)
fccaae3055 Error calling `all_crate_deps` without `Cargo.toml` (#1327)
d7c532cb78 Updated wasm_bindgen dependencies API (#1313)
fb4d5546ea Updated wasm_bindgen rules to only require core `rules_nodejs` rules (#1311)
1590670ae1 Prevents running of clippy on bindgen targets (#1320)
73d0164a34 Add support for aarch64-apple-ios-sim (#1304)
61eee54c73 Add bazel-* directories in cargo_manifest_dir/external_crate to gitignore (#1279)
42f78f25e1 crate_universe: Improved documentation (#1305)
bddc4bd94a Silence warnings for example/test dependencies (#1312)
b04fe3b21f Use tinyjson from crates.io instead of github.com. (#1309)
1cab691d14 Remove doc about STATIC_RUST_URL env var. (#1306)
d86e06a884 Don't propagate non-shared transitive linker inputs from `rust_static|shared_library` (#1299)
5abeb93333 Don't emit `CrateInfo` from `rust_static_library` and `rust_shared_library` (#1298)
0175a1b7aa fix for using a nightly channel after https://github.com/bazelbuild/rules_rust/commit/841fc6fb82141576d91aecb1d3f2656d58b0ab71 (#1302)
e07881fa22 Updated crate_universe docs (#1301)
c63ad973f1 rustc: fix a conditional (#1300)
a6f332fcbe Use __EXEC_ROOT__ paths for genfiles in rust_analyzer aspect (#1293)
97de47df51 Remove 'triple' field from triple struct in favor of 'str' (#1297)
58627f59eb Make get_host_triple public to get a triple from Bazel's repository_ctx (#1289)
612f4362bc Updated `rules_rust` version to `0.3.1` (#1296)
26fa5a15de Fixed build issues in release artifact (#1295)
48bb32f817 crate_universe: Added tests for serialized config files. (#1291)
841fc6fb82 Enable xz archives (#1284)
f7cb22efa6 feat(#514): pass extra flags to clippy (#1264)
e9f8b48711 Updated `rules_rust` version to `0.3.0` (#1288)
c900e1c66c Revert "Add workaround for arm vs armv7 android issue (#1259)" (#1290)
01ebef2fb9 Remove DEFAULT_RUST_EDITION (#1256)
03a70796ab Outside of examples, fill in all `edition` attrs (#1257)
207ee4fbcf feat: support extra deps in rust_doc_test (#1286)
4e7d114a8e Fix typo in render config doc (#1281)
db17f291d3 Fix crate annotation anchor (#1282)
fdb6851a92 Fix target name in `rust_test` example. (#1280)
4fb6e40147 Don't leak additive build file content across crates (#1278)
965044ae2b Remove `rust_test` example which doesn't build. (#1267)
f6e7e0a93f add a stopgap experimental_use_whole_archive_for_native_deps attribute (#1269)
34fd46756a process_wrapper: add support for terminating rustc after it emits rmeta. (#1207)
b778fca0ac crate_universe: propagate build_script_tools (#1266)
f6f27a8734 Add workaround for arm vs armv7 android issue (#1259)
c3f56c2d50 Add the BUILD.bazel file to the wasm_bindgen distro filegroup target (#1246) (#1261)
1f2e6231de Set edition for process_wrapper and cargo_build_script_runner (#1254)
55790492ac Updated Rust to 1.60.0 (#1247)
b594f90f17 Workaround for issue in linux Cargo binaries (#1252)
8f0dd9042e rust_test_suite: ensure crate names are valid (#1248)
4144ddeb9c Updating `rules_rust` version to `0.2.1` (#1243)
65cad76a52 Fixed proto package in release artifact (#1241)
4d8de6e361 Updated repository pin in the docs (#1240)
e5a3970754 Updating `rules_rust` version to `0.2.0` (#1235)
d061bf640e Updated `crate_universe` version to `0.2.0` (#1239)
c0505da0d2 Replace `rust_repositories` with `rust_register_toolchains` in docs (#1237)
145ad7609f Fixed `crates_repository` deleting `.cargo/config.toml` files. (#1227)
20066b05e2 fix: distribute `//tools/rust_analyzer` (#1234)
b58ce89603 Enabled `rust_doc_test` for `crate_universe` (#1232)
d2e2470cbf Fix some unit tests to run from another workspace (#1226)
b03aee039a Fixed `crate_universe` clippy defects (#1228)
41b39f0c99 add bots using lld (and examples with clang as a drive by) (#1221)
84e98e4d2f don't emit --codegen={metadata,extra-filename} for rust_static_library and rust_shared_library (#1222)
e48c834a40 Renamed `crate_index` repository to `crate_universe_crate_index` (#1217)
99b4b2574f fix use of stamping in rust_binary_without_process_wrapper (#1218)
8df4517d37 Add NUM_JOBS env var to cargo build scripts (#1216)
628e85e70f Restrucutred `crate_universe` dependency macros (#1208)
e3d67a0a10 Updated docs to guide users to using releases (#1213)
fd912e644c Updated crate_universe docs. (#1212)
cde4c0826c Delete deprecated `rules` targets (#1210)
26e01c8386 cache the release archive in release actions (#1201)
3205c9d846 Updated crate_universe setup guide (#1202)
c078494678 Don't leak deps from rust_proc_macro (#1206)
7c865ffeb1 Build `_import_macro_dep` in `exec` mode (#1203)
635da93206 Updating `rules_rust` version to `0.1.0`. (#1198)
6c797c9070 disable advanced features of C++ rules (#1200)
86d47a1bba Tweak import macro bootstrap to trick rust analyzer aspect (#1179)
80d197205a Added release workflow (#1195)
cd44b3670a Added support for producing distribution archives (#1194)
a665447989 Traverse custom alias-like rules in the rust analyzer aspect (#1190)
4504983fa9 Add a test showing that rust_analayzer aspect traverses aliases (#1188)
297dd18215 Updated `crate_universe` to version `0.1.0`. (#1197)
0d9c7d5e1b Specify root target for rust_analyzer test (#1189)
4a0352fecd Updated `crate_universe` dependencies (#1196)
5126479254 Fixed crate_universe release tools (#1193)
e840400eb6 Remove last remains of use_process_wrapper flag. (#1192)
eb7db68d96 Fix iOS linker arguments (#1186)
de726a10c9 Create internal rust_binary rule instead of using transitions (#1187)
5e6ad9f638 Regenerated `cargo-raze` outputs with v0.15.0 (#1184)
980b662843 add static_library to get_preferred_artifact with pic (#1183)
97fd329540 Populate CFLAGS and CXXFLAGS when invoking build script. (#1081)

git-subtree-dir: third_party/rules_rust
git-subtree-split: 078c6908fc32c168b58e72cc3884dd8e30419e3a
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: Ifc218edaa852263bd76835ee7de44de07c08aec2
diff --git a/util/process_wrapper/BUILD.bazel b/util/process_wrapper/BUILD.bazel
index c26d9a6..c5276dd 100644
--- a/util/process_wrapper/BUILD.bazel
+++ b/util/process_wrapper/BUILD.bazel
@@ -1,45 +1,20 @@
-load("@rules_cc//cc:defs.bzl", "cc_binary")
-load("//rust:defs.bzl", "rust_binary", "rust_test")
+load("//rust:defs.bzl", "rust_test")
 
 # buildifier: disable=bzl-visibility
-load("//rust/private:transitions.bzl", "without_process_wrapper")
+load("//rust/private:rust.bzl", "rust_binary_without_process_wrapper")
 
-alias(
+rust_binary_without_process_wrapper(
     name = "process_wrapper",
-    actual = select({
-        # This will never get used, it's only here to break the circular dependency to allow building process_wrapper
-        ":use_fake_process_wrapper": ":process_wrapper_fake",
-        "//conditions:default": ":process_wrapper_impl",
-    }),
-    visibility = ["//visibility:public"],
-)
-
-cc_binary(
-    name = "process_wrapper_fake",
-    srcs = ["fake.cc"],
-)
-
-config_setting(
-    name = "use_fake_process_wrapper",
-    flag_values = {
-        "//rust/settings:use_process_wrapper": "False",
-    },
-)
-
-# Changing the name of this rule requires a corresponding
-# change in //rust/private/rustc.bzl:925
-without_process_wrapper(
-    name = "process_wrapper_impl",
-    target = ":process_wrapper_bin",
-    visibility = ["//visibility:public"],
-)
-
-rust_binary(
-    name = "process_wrapper_bin",
     srcs = glob(["*.rs"]),
+    edition = "2018",
+    visibility = ["//visibility:public"],
+    deps = [
+        "@rules_rust_tinyjson//:tinyjson",
+    ],
 )
 
 rust_test(
     name = "process_wrapper_test",
-    crate = ":process_wrapper_bin",
+    crate = ":process_wrapper",
+    edition = "2018",
 )
diff --git a/util/process_wrapper/BUILD.tinyjson.bazel b/util/process_wrapper/BUILD.tinyjson.bazel
new file mode 100644
index 0000000..31f9da2
--- /dev/null
+++ b/util/process_wrapper/BUILD.tinyjson.bazel
@@ -0,0 +1,9 @@
+# buildifier: disable=bzl-visibility
+load("@rules_rust//rust/private:rust.bzl", "rust_library_without_process_wrapper")
+
+rust_library_without_process_wrapper(
+    name = "tinyjson",
+    srcs = glob(["src/*.rs"]),
+    edition = "2018",
+    visibility = ["@rules_rust//util/process_wrapper:__pkg__"],
+)
diff --git a/util/process_wrapper/main.rs b/util/process_wrapper/main.rs
index 41140a3..6d985b3 100644
--- a/util/process_wrapper/main.rs
+++ b/util/process_wrapper/main.rs
@@ -14,50 +14,115 @@
 
 mod flags;
 mod options;
+mod output;
+mod rustc;
 mod util;
 
 use std::fs::{copy, OpenOptions};
-use std::process::{exit, Command, Stdio};
+use std::io;
+use std::process::{exit, Command, ExitStatus, Stdio};
 
 use crate::options::options;
+use crate::output::{process_output, LineOutput};
+
+#[cfg(windows)]
+fn status_code(status: ExitStatus, was_killed: bool) -> i32 {
+    // On windows, there's no good way to know if the process was killed by a signal.
+    // If we killed the process, we override the code to signal success.
+    if was_killed {
+        0
+    } else {
+        status.code().unwrap_or(1)
+    }
+}
+
+#[cfg(not(windows))]
+fn status_code(status: ExitStatus, was_killed: bool) -> i32 {
+    // On unix, if code is None it means that the process was killed by a signal.
+    // https://doc.rust-lang.org/std/process/struct.ExitStatus.html#method.success
+    match status.code() {
+        Some(code) => code,
+        // If we killed the process, we expect None here
+        None if was_killed => 0,
+        // Otherwise it's some unexpected signal
+        None => 1,
+    }
+}
 
 fn main() {
     let opts = match options() {
         Err(err) => panic!("process wrapper error: {}", err),
         Ok(v) => v,
     };
-    let stdout = if let Some(stdout_file) = opts.stdout_file {
-        OpenOptions::new()
-            .create(true)
-            .truncate(true)
-            .write(true)
-            .open(stdout_file)
-            .expect("process wrapper error: unable to open stdout file")
-            .into()
-    } else {
-        Stdio::inherit()
-    };
-    let stderr = if let Some(stderr_file) = opts.stderr_file {
-        OpenOptions::new()
-            .create(true)
-            .truncate(true)
-            .write(true)
-            .open(stderr_file)
-            .expect("process wrapper error: unable to open stderr file")
-            .into()
-    } else {
-        Stdio::inherit()
-    };
-    let status = Command::new(opts.executable)
+
+    let mut child = Command::new(opts.executable)
         .args(opts.child_arguments)
         .env_clear()
         .envs(opts.child_environment)
-        .stdout(stdout)
-        .stderr(stderr)
-        .status()
+        .stdout(if let Some(stdout_file) = opts.stdout_file {
+            OpenOptions::new()
+                .create(true)
+                .truncate(true)
+                .write(true)
+                .open(stdout_file)
+                .expect("process wrapper error: unable to open stdout file")
+                .into()
+        } else {
+            Stdio::inherit()
+        })
+        .stderr(Stdio::piped())
+        .spawn()
         .expect("process wrapper error: failed to spawn child process");
 
-    if status.success() {
+    let mut stderr: Box<dyn io::Write> = if let Some(stderr_file) = opts.stderr_file {
+        Box::new(
+            OpenOptions::new()
+                .create(true)
+                .truncate(true)
+                .write(true)
+                .open(stderr_file)
+                .expect("process wrapper error: unable to open stderr file"),
+        )
+    } else {
+        Box::new(io::stderr())
+    };
+
+    let mut child_stderr = child.stderr.take().unwrap();
+
+    let mut was_killed = false;
+    let result = if let Some(format) = opts.rustc_output_format {
+        let quit_on_rmeta = opts.rustc_quit_on_rmeta;
+        // Process json rustc output and kill the subprocess when we get a signal
+        // that we emitted a metadata file.
+        let mut me = false;
+        let metadata_emitted = &mut me;
+        let result = process_output(&mut child_stderr, stderr.as_mut(), move |line| {
+            if quit_on_rmeta {
+                rustc::stop_on_rmeta_completion(line, format, metadata_emitted)
+            } else {
+                rustc::process_json(line, format)
+            }
+        });
+        if me {
+            // If recv returns Ok(), a signal was sent in this channel so we should terminate the child process.
+            // We can safely ignore the Result from kill() as we don't care if the process already terminated.
+            let _ = child.kill();
+            was_killed = true;
+        }
+        result
+    } else {
+        // Process output normally by forwarding stderr
+        process_output(&mut child_stderr, stderr.as_mut(), LineOutput::Message)
+    };
+    result.expect("process wrapper error: failed to process stderr");
+
+    let status = child
+        .wait()
+        .expect("process wrapper error: failed to wait for child process");
+    // If the child process is rustc and is killed after metadata generation, that's also a success.
+    let code = status_code(status, was_killed);
+    let success = code == 0;
+    if success {
         if let Some(tf) = opts.touch_file {
             OpenOptions::new()
                 .create(true)
@@ -75,5 +140,5 @@
         }
     }
 
-    exit(status.code().unwrap())
+    exit(code)
 }
diff --git a/util/process_wrapper/options.rs b/util/process_wrapper/options.rs
index 24bba9f..869b5c3 100644
--- a/util/process_wrapper/options.rs
+++ b/util/process_wrapper/options.rs
@@ -4,6 +4,7 @@
 use std::process::exit;
 
 use crate::flags::{FlagParseError, Flags, ParseOutcome};
+use crate::rustc;
 use crate::util::*;
 
 #[derive(Debug)]
@@ -38,12 +39,19 @@
     pub(crate) stdout_file: Option<String>,
     // If set, redirects the child process stderr to this file.
     pub(crate) stderr_file: Option<String>,
+    // If set, it configures rustc to emit an rmeta file and then
+    // quit.
+    pub(crate) rustc_quit_on_rmeta: bool,
+    // If rustc_quit_on_rmeta is set to true, this controls the
+    // output format of rustc messages.
+    pub(crate) rustc_output_format: Option<rustc::ErrorFormat>,
 }
 
 pub(crate) fn options() -> Result<Options, OptionError> {
     // Process argument list until -- is encountered.
     // Everything after is sent to the child process.
     let mut subst_mapping_raw = None;
+    let mut stable_status_file_raw = None;
     let mut volatile_status_file_raw = None;
     let mut env_file_raw = None;
     let mut arg_file_raw = None;
@@ -51,8 +59,11 @@
     let mut copy_output_raw = None;
     let mut stdout_file = None;
     let mut stderr_file = None;
+    let mut rustc_quit_on_rmeta_raw = None;
+    let mut rustc_output_format_raw = None;
     let mut flags = Flags::new();
     flags.define_repeated_flag("--subst", "", &mut subst_mapping_raw);
+    flags.define_flag("--stable-status-file", "", &mut stable_status_file_raw);
     flags.define_flag("--volatile-status-file", "", &mut volatile_status_file_raw);
     flags.define_repeated_flag(
         "--env-file",
@@ -80,6 +91,19 @@
         "Redirect subprocess stderr in this file.",
         &mut stderr_file,
     );
+    flags.define_flag(
+        "--rustc-quit-on-rmeta",
+        "If enabled, this wrapper will terminate rustc after rmeta has been emitted.",
+        &mut rustc_quit_on_rmeta_raw,
+    );
+    flags.define_flag(
+        "--rustc-output-format",
+        "Controls the rustc output format if --rustc-quit-on-rmeta is set.\n\
+        'json' will cause the json output to be output, \
+        'rendered' will extract the rendered message and print that.\n\
+        Default: `rendered`",
+        &mut rustc_output_format_raw,
+    );
 
     let mut child_args = match flags
         .parse(env::args().collect())
@@ -112,9 +136,10 @@
             Ok((key.to_owned(), v))
         })
         .collect::<Result<Vec<(String, String)>, OptionError>>()?;
-    let stamp_mappings =
+    let stable_stamp_mappings =
+        stable_status_file_raw.map_or_else(Vec::new, |s| read_stamp_status_to_array(s).unwrap());
+    let volatile_stamp_mappings =
         volatile_status_file_raw.map_or_else(Vec::new, |s| read_stamp_status_to_array(s).unwrap());
-
     let environment_file_block = env_from_files(env_file_raw.unwrap_or_default())?;
     let mut file_arguments = args_from_file(arg_file_raw.unwrap_or_default())?;
     // Process --copy-output
@@ -138,9 +163,26 @@
         })
         .transpose()?;
 
+    let rustc_quit_on_rmeta = rustc_quit_on_rmeta_raw.map_or(false, |s| s == "true");
+    let rustc_output_format = rustc_output_format_raw
+        .map(|v| match v.as_str() {
+            "json" => Ok(rustc::ErrorFormat::Json),
+            "rendered" => Ok(rustc::ErrorFormat::Rendered),
+            _ => Err(OptionError::Generic(format!(
+                "invalid --rustc-output-format '{}'",
+                v
+            ))),
+        })
+        .transpose()?;
+
     // Prepare the environment variables, unifying those read from files with the ones
     // of the current process.
-    let vars = environment_block(environment_file_block, &stamp_mappings, &subst_mappings);
+    let vars = environment_block(
+        environment_file_block,
+        &stable_stamp_mappings,
+        &volatile_stamp_mappings,
+        &subst_mappings,
+    );
     // Append all the arguments fetched from files to those provided via command line.
     child_args.append(&mut file_arguments);
     let child_args = prepare_args(child_args, &subst_mappings);
@@ -159,13 +201,20 @@
         copy_output,
         stdout_file,
         stderr_file,
+        rustc_quit_on_rmeta,
+        rustc_output_format,
     })
 }
 
 fn args_from_file(paths: Vec<String>) -> Result<Vec<String>, OptionError> {
     let mut args = vec![];
-    for path in paths.into_iter() {
-        let mut lines = read_file_to_array(path).map_err(OptionError::Generic)?;
+    for path in paths.iter() {
+        let mut lines = read_file_to_array(path).map_err(|err| {
+            OptionError::Generic(format!(
+                "{} while processing args from file paths: {:?}",
+                err, &paths
+            ))
+        })?;
         args.append(&mut lines);
     }
     Ok(args)
@@ -174,7 +223,7 @@
 fn env_from_files(paths: Vec<String>) -> Result<HashMap<String, String>, OptionError> {
     let mut env_vars = HashMap::new();
     for path in paths.into_iter() {
-        let lines = read_file_to_array(path).map_err(OptionError::Generic)?;
+        let lines = read_file_to_array(&path).map_err(OptionError::Generic)?;
         for line in lines.into_iter() {
             let (k, v) = line
                 .split_once('=')
@@ -198,7 +247,8 @@
 
 fn environment_block(
     environment_file_block: HashMap<String, String>,
-    stamp_mappings: &[(String, String)],
+    stable_stamp_mappings: &[(String, String)],
+    volatile_stamp_mappings: &[(String, String)],
     subst_mappings: &[(String, String)],
 ) -> HashMap<String, String> {
     // Taking all environment variables from the current process
@@ -208,7 +258,7 @@
     // This is simpler than needing to track duplicates and explicitly override
     // them.
     environment_variables.extend(environment_file_block.into_iter());
-    for (f, replace_with) in stamp_mappings {
+    for (f, replace_with) in &[stable_stamp_mappings, volatile_stamp_mappings].concat() {
         for value in environment_variables.values_mut() {
             let from = format!("{{{}}}", f);
             let new = value.replace(from.as_str(), replace_with);
diff --git a/util/process_wrapper/output.rs b/util/process_wrapper/output.rs
new file mode 100644
index 0000000..84d61d9
--- /dev/null
+++ b/util/process_wrapper/output.rs
@@ -0,0 +1,56 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::io::{self, prelude::*};
+
+/// LineOutput tells process_output what to do when a line is processed.
+/// If a Message is returned, it will be written to write_end, if
+/// Skip is returned nothing will be printed and execution continues,
+/// if Terminate is returned, process_output returns immediately.
+/// Terminate is used to stop processing when we see an emit metadata
+/// message.
+#[derive(Debug)]
+pub(crate) enum LineOutput {
+    Message(String),
+    Skip,
+    Terminate,
+}
+
+/// process_output reads lines from read_end and invokes process_line on each.
+/// Depending on the result of process_line, the modified message may be written
+/// to write_end.
+pub(crate) fn process_output<F>(
+    read_end: &mut dyn Read,
+    write_end: &mut dyn Write,
+    mut process_line: F,
+) -> io::Result<()>
+where
+    F: FnMut(String) -> LineOutput,
+{
+    let mut reader = io::BufReader::new(read_end);
+    let mut writer = io::LineWriter::new(write_end);
+    loop {
+        let mut line = String::new();
+        let read_bytes = reader.read_line(&mut line)?;
+        if read_bytes == 0 {
+            break;
+        }
+        match process_line(line) {
+            LineOutput::Message(to_write) => writer.write_all(to_write.as_bytes())?,
+            LineOutput::Skip => {}
+            LineOutput::Terminate => return Ok(()),
+        };
+    }
+    Ok(())
+}
diff --git a/util/process_wrapper/rustc.rs b/util/process_wrapper/rustc.rs
new file mode 100644
index 0000000..ca79680
--- /dev/null
+++ b/util/process_wrapper/rustc.rs
@@ -0,0 +1,112 @@
+// Copyright 2020 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::convert::{TryFrom, TryInto};
+
+use tinyjson::JsonValue;
+
+use crate::output::LineOutput;
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum ErrorFormat {
+    Json,
+    Rendered,
+}
+
+impl Default for ErrorFormat {
+    fn default() -> Self {
+        Self::Rendered
+    }
+}
+
+fn get_key(value: &JsonValue, key: &str) -> Option<String> {
+    if let JsonValue::Object(map) = value {
+        if let JsonValue::String(s) = map.get(key)? {
+            Some(s.clone())
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+
+#[derive(Debug)]
+enum RustcMessage {
+    Emit(String),
+    Message(String),
+}
+
+impl TryFrom<JsonValue> for RustcMessage {
+    type Error = ();
+    fn try_from(val: JsonValue) -> Result<Self, Self::Error> {
+        if let Some(emit) = get_key(&val, "emit") {
+            return Ok(Self::Emit(emit));
+        }
+        if let Some(rendered) = get_key(&val, "rendered") {
+            return Ok(Self::Message(rendered));
+        }
+        Err(())
+    }
+}
+
+/// process_rustc_json takes an output line from rustc configured with
+/// --error-format=json, parses the json and returns the appropriate output
+/// according to the original --error-format supplied.
+/// Only messages are returned, emits are ignored.
+pub(crate) fn process_json(line: String, error_format: ErrorFormat) -> LineOutput {
+    let parsed: JsonValue = line
+        .parse()
+        .expect("process wrapper error: expected json messages in pipeline mode");
+    match parsed.try_into() {
+        Ok(RustcMessage::Message(msg)) => match error_format {
+            // If the output should be json, we just forward the messages as-is
+            // using `line`.
+            ErrorFormat::Json => LineOutput::Message(line),
+            // Otherwise we return the rendered field.
+            _ => LineOutput::Message(msg),
+        },
+        _ => LineOutput::Skip,
+    }
+}
+
+/// stop_on_rmeta_completion parses the json output of rustc in the same way process_rustc_json does.
+/// In addition, it will signal to stop when metadata is emitted
+/// so the compiler can be terminated.
+/// This is used to implement pipelining in rules_rust, please see
+/// https://internals.rust-lang.org/t/evaluating-pipelined-rustc-compilation/10199
+pub(crate) fn stop_on_rmeta_completion(
+    line: String,
+    error_format: ErrorFormat,
+    kill: &mut bool,
+) -> LineOutput {
+    let parsed: JsonValue = line
+        .parse()
+        .expect("process wrapper error: expected json messages in pipeline mode");
+
+    match parsed.try_into() {
+        Ok(RustcMessage::Emit(emit)) if emit == "metadata" => {
+            *kill = true;
+            LineOutput::Terminate
+        }
+        Ok(RustcMessage::Message(msg)) => match error_format {
+            // If the output should be json, we just forward the messages as-is
+            // using `line`.
+            ErrorFormat::Json => LineOutput::Message(line),
+            // Otherwise we return the rendered field.
+            _ => LineOutput::Message(msg),
+        },
+        _ => LineOutput::Skip,
+    }
+}
diff --git a/util/process_wrapper/util.rs b/util/process_wrapper/util.rs
index 4b3d6bb..89f2ded 100644
--- a/util/process_wrapper/util.rs
+++ b/util/process_wrapper/util.rs
@@ -15,8 +15,16 @@
 use std::fs::File;
 use std::io::{BufRead, BufReader, Read};
 
-pub(crate) fn read_file_to_array(path: String) -> Result<Vec<String>, String> {
-    let file = File::open(path).map_err(|e| e.to_string())?;
+pub(crate) fn read_file_to_array(path: &str) -> Result<Vec<String>, String> {
+    let file = File::open(path).map_err(|e| e.to_string()).map_err(|err| {
+        format!(
+            "{} reading path: {:?}, current directory: {:?}",
+            err,
+            path,
+            std::env::current_dir()
+        )
+    })?;
+
     read_to_array(file)
 }