about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/bootstrap.py8
-rw-r--r--src/bootstrap/builder/tests.rs2
-rw-r--r--src/bootstrap/check.rs4
-rw-r--r--src/bootstrap/download.rs33
-rw-r--r--src/bootstrap/flags.rs10
-rw-r--r--src/bootstrap/format.rs58
-rw-r--r--src/bootstrap/lib.rs11
-rw-r--r--src/bootstrap/native.rs6
-rw-r--r--src/bootstrap/test.rs4
9 files changed, 100 insertions, 36 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index c298817895c..013d1ab525b 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -784,6 +784,8 @@ class RustBuild(object):
         if self.get_toml("metrics", "build"):
             args.append("--features")
             args.append("build-metrics")
+        if self.json_output:
+            args.append("--message-format=json")
         if color == "always":
             args.append("--color=always")
         elif color == "never":
@@ -841,6 +843,7 @@ def parse_args():
     parser.add_argument('--build')
     parser.add_argument('--color', choices=['always', 'never', 'auto'])
     parser.add_argument('--clean', action='store_true')
+    parser.add_argument('--json-output', action='store_true')
     parser.add_argument('-v', '--verbose', action='count', default=0)
 
     return parser.parse_known_args(sys.argv)[0]
@@ -852,6 +855,7 @@ def bootstrap(args):
     build.rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
     build.verbose = args.verbose != 0
     build.clean = args.clean
+    build.json_output = args.json_output
 
     # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`,
     # then `config.toml` in the root directory.
@@ -937,6 +941,7 @@ def main():
         )
 
     exit_code = 0
+    success_word = "successfully"
     try:
         bootstrap(args)
     except (SystemExit, KeyboardInterrupt) as error:
@@ -945,9 +950,10 @@ def main():
         else:
             exit_code = 1
             print(error)
+        success_word = "unsuccessfully"
 
     if not help_triggered:
-        print("Build completed successfully in", format_build_time(time() - start_time))
+        print("Build completed", success_word, "in", format_build_time(time() - start_time))
     sys.exit(exit_code)
 
 
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index d5fcd107502..3574f11189e 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -557,6 +557,7 @@ mod dist {
             rustfix_coverage: false,
             pass: None,
             run: None,
+            only_modified: false,
         };
 
         let build = Build::new(config);
@@ -627,6 +628,7 @@ mod dist {
             rustfix_coverage: false,
             pass: None,
             run: None,
+            only_modified: false,
         };
         // Make sure rustfmt binary not being found isn't an error.
         config.channel = "beta".to_string();
diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs
index 4b8a58e87b6..1675ed158c9 100644
--- a/src/bootstrap/check.rs
+++ b/src/bootstrap/check.rs
@@ -99,6 +99,10 @@ impl Step for Std {
             cargo_subcommand(builder.kind),
         );
         std_cargo(builder, target, compiler.stage, &mut cargo);
+        if matches!(builder.config.cmd, Subcommand::Fix { .. }) {
+            // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot.
+            cargo.arg("--lib");
+        }
 
         builder.info(&format!(
             "Checking stage{} library artifacts ({} -> {})",
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index bd67978a766..d6592d2d771 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -2,7 +2,7 @@ use std::{
     env,
     ffi::{OsStr, OsString},
     fs::{self, File},
-    io::{BufRead, BufReader, ErrorKind},
+    io::{self, BufRead, BufReader, ErrorKind},
     path::{Path, PathBuf},
     process::{Command, Stdio},
 };
@@ -26,6 +26,14 @@ impl Config {
         self.verbose > 0
     }
 
+    pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::Result<()> {
+        #[cfg(unix)]
+        use std::os::unix::fs::symlink as symlink_file;
+        #[cfg(windows)]
+        use std::os::windows::fs::symlink_file;
+        if !self.dry_run() { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
+    }
+
     pub(crate) fn create(&self, path: &Path, s: &str) {
         if self.dry_run() {
             return;
@@ -173,8 +181,7 @@ impl Config {
             // appear to have this (even when `../lib` is redundant).
             // NOTE: there are only two paths here, delimited by a `:`
             let mut entries = OsString::from("$ORIGIN/../lib:");
-            entries.push(t!(fs::canonicalize(nix_deps_dir)));
-            entries.push("/lib");
+            entries.push(t!(fs::canonicalize(nix_deps_dir)).join("lib"));
             entries
         };
         patchelf.args(&[OsString::from("--set-rpath"), rpath_entries]);
@@ -221,10 +228,10 @@ impl Config {
             "--retry",
             "3",
             "-Sf",
-            "-o",
         ]);
-        curl.arg(tempfile);
         curl.arg(url);
+        let f = File::create(tempfile).unwrap();
+        curl.stdout(Stdio::from(f));
         if !self.check_run(&mut curl) {
             if self.build.contains("windows-msvc") {
                 println!("Fallback to PowerShell");
@@ -331,6 +338,15 @@ impl Config {
         let bin_root = self.out.join(host.triple).join("rustfmt");
         let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
         let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
+
+        #[cfg(not(windows))]
+        {
+            let legacy_rustfmt = self.initial_rustc.with_file_name(exe("rustfmt", host));
+            if !legacy_rustfmt.exists() {
+                t!(self.symlink_file(&rustfmt_path, &legacy_rustfmt));
+            }
+        }
+
         if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
             return Some(rustfmt_path);
         }
@@ -353,6 +369,13 @@ impl Config {
         if self.should_fix_bins_and_dylibs() {
             self.fix_bin_or_dylib(&bin_root.join("bin").join("rustfmt"));
             self.fix_bin_or_dylib(&bin_root.join("bin").join("cargo-fmt"));
+            let lib_dir = bin_root.join("lib");
+            for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
+                let lib = t!(lib);
+                if lib.path().extension() == Some(OsStr::new("so")) {
+                    self.fix_bin_or_dylib(&lib.path());
+                }
+            }
         }
 
         self.create(&rustfmt_stamp, &channel);
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index 52c3dc0bf75..ff927ed561b 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -124,6 +124,7 @@ pub enum Subcommand {
         fail_fast: bool,
         doc_tests: DocTests,
         rustfix_coverage: bool,
+        only_modified: bool,
     },
     Bench {
         paths: Vec<PathBuf>,
@@ -301,6 +302,7 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
                 opts.optflag("", "doc", "only run doc tests");
                 opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests");
                 opts.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged");
+                opts.optflag("", "only-modified", "only run tests that result has been changed");
                 opts.optopt(
                     "",
                     "compare-mode",
@@ -598,6 +600,7 @@ Arguments:
                 rustc_args: matches.opt_strs("rustc-args"),
                 fail_fast: !matches.opt_present("no-fail-fast"),
                 rustfix_coverage: matches.opt_present("rustfix-coverage"),
+                only_modified: matches.opt_present("only-modified"),
                 doc_tests: if matches.opt_present("doc") {
                     DocTests::Only
                 } else if matches.opt_present("no-doc") {
@@ -777,6 +780,13 @@ impl Subcommand {
         }
     }
 
+    pub fn only_modified(&self) -> bool {
+        match *self {
+            Subcommand::Test { only_modified, .. } => only_modified,
+            _ => false,
+        }
+    }
+
     pub fn force_rerun(&self) -> bool {
         match *self {
             Subcommand::Test { force_rerun, .. } => force_rerun,
diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs
index bfc57a85cdb..615794958d0 100644
--- a/src/bootstrap/format.rs
+++ b/src/bootstrap/format.rs
@@ -1,8 +1,8 @@
 //! Runs rustfmt on the repository.
 
 use crate::builder::Builder;
-use crate::util::{output, output_result, program_out_of_date, t};
-use build_helper::git::updated_master_branch;
+use crate::util::{output, program_out_of_date, t};
+use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
 use std::collections::VecDeque;
 use std::path::{Path, PathBuf};
@@ -80,23 +80,11 @@ fn update_rustfmt_version(build: &Builder<'_>) {
 ///
 /// Returns `None` if all files should be formatted.
 fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
-    let Ok(updated_master) = updated_master_branch(Some(&build.config.src)) else { return Ok(None); };
-
     if !verify_rustfmt_version(build) {
         return Ok(None);
     }
 
-    let merge_base =
-        output_result(build.config.git().arg("merge-base").arg(&updated_master).arg("HEAD"))?;
-    Ok(Some(
-        output_result(
-            build.config.git().arg("diff-index").arg("--name-only").arg(merge_base.trim()),
-        )?
-        .lines()
-        .map(|s| s.trim().to_owned())
-        .filter(|f| Path::new(f).extension().map_or(false, |ext| ext == "rs"))
-        .collect(),
-    ))
+    get_git_modified_files(Some(&build.config.src), &vec!["rs"])
 }
 
 #[derive(serde::Deserialize)]
@@ -205,10 +193,46 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
     let (tx, rx): (SyncSender<PathBuf>, _) = std::sync::mpsc::sync_channel(128);
     let walker = match paths.get(0) {
         Some(first) => {
-            let mut walker = WalkBuilder::new(first);
+            let find_shortcut_candidates = |p: &PathBuf| {
+                let mut candidates = Vec::new();
+                for candidate in WalkBuilder::new(src.clone()).max_depth(Some(3)).build() {
+                    if let Ok(entry) = candidate {
+                        if let Some(dir_name) = p.file_name() {
+                            if entry.path().is_dir() && entry.file_name() == dir_name {
+                                candidates.push(entry.into_path());
+                            }
+                        }
+                    }
+                }
+                candidates
+            };
+
+            // Only try to look for shortcut candidates for single component paths like
+            // `std` and not for e.g. relative paths like `../library/std`.
+            let should_look_for_shortcut_dir = |p: &PathBuf| p.components().count() == 1;
+
+            let mut walker = if should_look_for_shortcut_dir(first) {
+                if let [single_candidate] = &find_shortcut_candidates(first)[..] {
+                    WalkBuilder::new(single_candidate)
+                } else {
+                    WalkBuilder::new(first)
+                }
+            } else {
+                WalkBuilder::new(first)
+            };
+
             for path in &paths[1..] {
-                walker.add(path);
+                if should_look_for_shortcut_dir(path) {
+                    if let [single_candidate] = &find_shortcut_candidates(path)[..] {
+                        walker.add(single_candidate);
+                    } else {
+                        walker.add(path);
+                    }
+                } else {
+                    walker.add(path);
+                }
             }
+
             walker
         }
         None => WalkBuilder::new(src.clone()),
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index f4abdf1cc57..f753720b353 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -20,7 +20,6 @@ use std::cell::{Cell, RefCell};
 use std::collections::{HashMap, HashSet};
 use std::env;
 use std::fs::{self, File};
-use std::io;
 use std::io::ErrorKind;
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
@@ -1407,7 +1406,7 @@ impl Build {
                 src = t!(fs::canonicalize(src));
             } else {
                 let link = t!(fs::read_link(src));
-                t!(self.symlink_file(link, dst));
+                t!(self.config.symlink_file(link, dst));
                 return;
             }
         }
@@ -1525,14 +1524,6 @@ impl Build {
         iter.map(|e| t!(e)).collect::<Vec<_>>().into_iter()
     }
 
-    fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(&self, src: P, link: Q) -> io::Result<()> {
-        #[cfg(unix)]
-        use std::os::unix::fs::symlink as symlink_file;
-        #[cfg(windows)]
-        use std::os::windows::fs::symlink_file;
-        if !self.config.dry_run() { symlink_file(src.as_ref(), link.as_ref()) } else { Ok(()) }
-    }
-
     /// Returns if config.ninja is enabled, and checks for ninja existence,
     /// exiting with a nicer error message if not.
     fn ninja(&self) -> bool {
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 3acc2d4b5c4..9235de75ec6 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -516,7 +516,7 @@ impl Step for Llvm {
 
             let lib_llvm = out_dir.join("build").join("lib").join(lib_name);
             if !lib_llvm.exists() {
-                t!(builder.symlink_file("libLLVM.dylib", &lib_llvm));
+                t!(builder.build.config.symlink_file("libLLVM.dylib", &lib_llvm));
             }
         }
 
@@ -561,11 +561,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     let version = output(cmd.arg("--version"));
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 13 {
+        if major >= 14 {
             return;
         }
     }
-    panic!("\n\nbad LLVM version: {}, need >=13.0\n\n", version)
+    panic!("\n\nbad LLVM version: {}, need >=14.0\n\n", version)
 }
 
 fn configure_cmake(
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 8a0c532cfb0..f8835fe11a8 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1510,6 +1510,10 @@ note: if you're sure you want to do this, please open an issue as to why. In the
         if builder.config.rust_optimize_tests {
             cmd.arg("--optimize-tests");
         }
+        if builder.config.cmd.only_modified() {
+            cmd.arg("--only-modified");
+        }
+
         let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
         flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
         flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));