about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-08-19 14:18:28 +1000
committerGitHub <noreply@github.com>2025-08-19 14:18:28 +1000
commit3ced940a31240700514d127670a050991383d2d5 (patch)
treea45e1d7f2bdfa80508e6d815a62e19860982efd1 /src
parentf44f963b03ce177a2037386244b344234048074e (diff)
parenta1f5bbeed88134cb0978ad85e5e64bc3589318d2 (diff)
downloadrust-3ced940a31240700514d127670a050991383d2d5.tar.gz
rust-3ced940a31240700514d127670a050991383d2d5.zip
Rollup merge of #145565 - Kobzol:bootstrap-ci-print-error, r=jieyouxu
Improve context of bootstrap errors in CI

Inspired by https://rust-lang.zulipchat.com/#narrow/channel/326414-t-infra.2Fbootstrap/topic/printing.20test.20suite.20name.20by.20default/with/534920583, this PR attempts to improve the context displayed when a bootstrap invocation fails in CI.

Since https://github.com/rust-lang/rust/pull/145261, we now see the latest started step when a failure occurs. However, we can go further.

1) The first commit prints the actual executed bootstrap invocation command arguments when bootstrap ends. Since CI jobs often run multiple bootstrap commands, this makes it easier to figure out which one of them failed (before it was annoying having to search for that in CI logs). Because bootstrap doesn't really use `Result`s much, and most of them time it ends with the `detail_exit` function, which YOLOs `std::process::exit(...)`, I added the print there.
2) Adds `#[track_caller]` to a few bootstrap Cargo builder functions. This makes the log that we print when a command fails more accurate:
```
2025-08-16T18:18:51.6998201Z Command ... failed ...
2025-08-16T18:18:51.7003653Z Created at: src/bootstrap/src/core/builder/cargo.rs:423:33
2025-08-16T18:18:51.7004032Z Executed at: src/bootstrap/src/core/build_steps/doc.rs:933:26
```
Before, the `cargo.rs:XYZ` location wasn't very useful.
3) Is the most wild thing (I'll revert if you find it too magical). We store the step stack of the currently active `Builder` instance in a global variable, and when bootstrap exits with a failure, we print the stack, to make it easier to find out what was happening when a failure occurred. We could print an actual captured `Backtrace`, but I think that would be too much information in the common case. We now pass `RUST_BACKTRACE=1` on CI, so if bootstrap actually crashes unexpectedly, we would see the stacktrace.

The end of the bootsrap failure log in CI now looks like this now:

```
Bootstrap failed while executing `x build library`

---BOOTSTRAP step stack start---

Assemble { target_compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu, forced_compiler: false } }
Rustc { target: x86_64-unknown-linux-gnu, build_compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu, forced_compiler: false }, crates: [] }

---BOOTSTRAP step stack end---
```

r? `@jieyouxu`
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs4
-rw-r--r--src/build_helper/src/util.rs11
2 files changed, 15 insertions, 0 deletions
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 52733a434a3..69a744a86cb 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -101,6 +101,7 @@ pub struct Cargo {
 impl Cargo {
     /// Calls [`Builder::cargo`] and [`Cargo::configure_linker`] to prepare an invocation of `cargo`
     /// to be run.
+    #[track_caller]
     pub fn new(
         builder: &Builder<'_>,
         compiler: Compiler,
@@ -139,6 +140,7 @@ impl Cargo {
 
     /// Same as [`Cargo::new`] except this one doesn't configure the linker with
     /// [`Cargo::configure_linker`].
+    #[track_caller]
     pub fn new_for_mir_opt_tests(
         builder: &Builder<'_>,
         compiler: Compiler,
@@ -422,6 +424,7 @@ impl From<Cargo> for BootstrapCommand {
 
 impl Builder<'_> {
     /// Like [`Builder::cargo`], but only passes flags that are valid for all commands.
+    #[track_caller]
     pub fn bare_cargo(
         &self,
         compiler: Compiler,
@@ -506,6 +509,7 @@ impl Builder<'_> {
     /// scoped by `mode`'s output directory, it will pass the `--target` flag for the specified
     /// `target`, and will be executing the Cargo command `cmd`. `cmd` can be `miri-cmd` for
     /// commands to be run with Miri.
+    #[track_caller]
     fn cargo(
         &self,
         compiler: Compiler,
diff --git a/src/build_helper/src/util.rs b/src/build_helper/src/util.rs
index a8355f774e9..1bdbb7515e2 100644
--- a/src/build_helper/src/util.rs
+++ b/src/build_helper/src/util.rs
@@ -3,6 +3,8 @@ use std::io::{BufRead, BufReader};
 use std::path::Path;
 use std::process::Command;
 
+use crate::ci::CiEnv;
+
 /// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
 ///
 /// This is a macro instead of a function so that it uses `cfg(test)` in the *calling* crate, not in build helper.
@@ -20,6 +22,15 @@ pub fn detail_exit(code: i32, is_test: bool) -> ! {
     if is_test {
         panic!("status code: {code}");
     } else {
+        // If we're in CI, print the current bootstrap invocation command, to make it easier to
+        // figure out what exactly has failed.
+        if CiEnv::is_ci() {
+            // Skip the first argument, as it will be some absolute path to the bootstrap binary.
+            let bootstrap_args =
+                std::env::args().skip(1).map(|a| a.to_string()).collect::<Vec<_>>().join(" ");
+            eprintln!("Bootstrap failed while executing `{bootstrap_args}`");
+        }
+
         // otherwise, exit with provided status code
         std::process::exit(code);
     }