]> git.lizzy.rs Git - rust.git/blobdiff - src/bootstrap/builder.rs
Check RLS tests
[rust.git] / src / bootstrap / builder.rs
index 5d7400ab9ae8ac4f0d4af0ac52f42e0c0d195766..dd24e8705beb38c7f7865c5976884dd5559bc1f0 100644 (file)
@@ -8,20 +8,22 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use serde::{Serialize, Deserialize};
-
+use std::fmt::Debug;
+use std::hash::Hash;
 use std::cell::RefCell;
 use std::path::{Path, PathBuf};
 use std::process::Command;
 use std::fs;
 use std::ops::Deref;
+use std::any::Any;
+use std::collections::BTreeSet;
 
 use compile;
 use install;
 use dist;
 use util::{exe, libdir, add_lib_path};
 use {Build, Mode};
-use cache::{Cache, Key};
+use cache::{INTERNER, Interned, Cache};
 use check;
 use flags::Subcommand;
 use doc;
@@ -34,7 +36,7 @@ pub struct Builder<'a> {
     pub top_stage: u32,
     pub kind: Kind,
     cache: Cache,
-    stack: RefCell<Vec<Key>>,
+    stack: RefCell<Vec<Box<Any>>>,
 }
 
 impl<'a> Deref for Builder<'a> {
@@ -45,16 +47,10 @@ fn deref(&self) -> &Self::Target {
     }
 }
 
-pub trait Step<'a>: Serialize + Sized {
-    /// The output type of this step. This is used in a few places to return a
+pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash {
     /// `PathBuf` when directories are created or to return a `Compiler` once
     /// it's been assembled.
-    ///
-    /// When possible, this should be used instead of implicitly creating files
-    /// in a prearranged directory that will later be used by the build system.
-    /// It's not always practical, however, since it makes avoiding rebuilds
-    /// somewhat harder.
-    type Output: Serialize + Deserialize<'a> + 'a;
+    type Output: Clone;
 
     const DEFAULT: bool = false;
 
@@ -69,13 +65,13 @@ pub trait Step<'a>: Serialize + Sized {
 
     /// Primary function to execute this rule. Can call `builder.ensure(...)`
     /// with other steps to run those.
-    fn run(self, builder: &'a Builder) -> Self::Output;
+    fn run(self, builder: &Builder) -> Self::Output;
 
     /// When bootstrap is passed a set of paths, this controls whether this rule
     /// will execute. However, it does not get called in a "default" context
     /// when we are not passed any paths; in that case, make_run is called
     /// directly.
-    fn should_run(_builder: &'a Builder, _path: &Path) -> bool { false }
+    fn should_run(run: ShouldRun) -> ShouldRun;
 
     /// Build up a "root" rule, either as a default rule or from a path passed
     /// to us.
@@ -84,45 +80,209 @@ fn should_run(_builder: &'a Builder, _path: &Path) -> bool { false }
     /// passed. When `./x.py build` is run, for example, this rule could get
     /// called if it is in the correct list below with a path of `None`.
     fn make_run(
-        _builder: &'a Builder,
+        _builder: &Builder,
         _path: Option<&Path>,
-        _host: &'a str,
-        _target: &'a str,
-    ) { unimplemented!() }
+        _host: Interned<String>,
+        _target: Interned<String>,
+    ) {
+        // It is reasonable to not have an implementation of make_run for rules
+        // who do not want to get called from the root context. This means that
+        // they are likely dependencies (e.g., sysroot creation) or similar, and
+        // as such calling them from ./x.py isn't logical.
+        unimplemented!()
+    }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub enum Kind {
-    Build,
-    Test,
-    Bench,
-    Dist,
-    Doc,
-    Install,
+struct StepDescription {
+    default: bool,
+    only_hosts: bool,
+    only_build_targets: bool,
+    only_build: bool,
+    should_run: fn(ShouldRun) -> ShouldRun,
+    make_run: fn(&Builder, Option<&Path>, Interned<String>, Interned<String>),
 }
 
-macro_rules! check {
-    ($self:ident, $paths:ident, $($rule:ty),+ $(,)*) => {{
-        let paths = $paths;
+impl StepDescription {
+    fn from<S: Step>() -> StepDescription {
+        StepDescription {
+            default: S::DEFAULT,
+            only_hosts: S::ONLY_HOSTS,
+            only_build_targets: S::ONLY_BUILD_TARGETS,
+            only_build: S::ONLY_BUILD,
+            should_run: S::should_run,
+            make_run: S::make_run,
+        }
+    }
+
+    fn maybe_run(&self, builder: &Builder, path: Option<&Path>) {
+        let build = builder.build;
+        let hosts = if self.only_build_targets || self.only_build {
+            &build.config.host[..1]
+        } else {
+            &build.hosts
+        };
+
+        // Determine the actual targets participating in this rule.
+        // NOTE: We should keep the full projection from build triple to
+        // the hosts for the dist steps, now that the hosts array above is
+        // truncated to avoid duplication of work in that case. Therefore
+        // the original non-shadowed hosts array is used below.
+        let targets = if self.only_hosts {
+            // If --target was specified but --host wasn't specified,
+            // don't run any host-only tests. Also, respect any `--host`
+            // overrides as done for `hosts`.
+            if build.flags.host.len() > 0 {
+                &build.flags.host[..]
+            } else if build.flags.target.len() > 0 {
+                &[]
+            } else if self.only_build {
+                &build.config.host[..1]
+            } else {
+                &build.config.host[..]
+            }
+        } else {
+            &build.targets
+        };
+
+        for host in hosts {
+            for target in targets {
+                (self.make_run)(builder, path, *host, *target);
+            }
+        }
+    }
+
+    fn run(v: &[StepDescription], builder: &Builder, paths: &[PathBuf]) {
         if paths.is_empty() {
-            $({
-                if <$rule>::DEFAULT {
-                    $self.maybe_run::<$rule>(None);
+            for desc in v {
+                if desc.default {
+                    desc.maybe_run(builder, None);
                 }
-            })+
+            }
         } else {
             for path in paths {
-                $({
-                    if <$rule>::should_run($self, path) {
-                        $self.maybe_run::<$rule>(Some(path));
+                let mut attempted_run = false;
+                for desc in v {
+                    if (desc.should_run)(ShouldRun::new(builder)).run(path) {
+                        attempted_run = true;
+                        desc.maybe_run(builder, Some(path));
                     }
-                })+
+                }
+
+                if !attempted_run {
+                    eprintln!("Warning: no rules matched {}.", path.display());
+                }
             }
         }
-    }};
+    }
+}
+
+#[derive(Clone)]
+pub struct ShouldRun<'a> {
+    builder: &'a Builder<'a>,
+    // use a BTreeSet to maintain sort order
+    paths: BTreeSet<PathBuf>,
+}
+
+impl<'a> ShouldRun<'a> {
+    fn new(builder: &'a Builder) -> ShouldRun<'a> {
+        ShouldRun {
+            builder: builder,
+            paths: BTreeSet::new(),
+        }
+    }
+
+    pub fn krate(mut self, name: &str) -> Self {
+        for (_, krate_path) in self.builder.crates(name) {
+            self.paths.insert(PathBuf::from(krate_path));
+        }
+        self
+    }
+
+    pub fn path(mut self, path: &str) -> Self {
+        self.paths.insert(PathBuf::from(path));
+        self
+    }
+
+    // allows being more explicit about why should_run in Step returns the value passed to it
+    pub fn never(self) -> ShouldRun<'a> {
+        self
+    }
+
+    fn run(&self, path: &Path) -> bool {
+        self.paths.iter().any(|p| path.ends_with(p))
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub enum Kind {
+    Build,
+    Test,
+    Bench,
+    Dist,
+    Doc,
+    Install,
 }
 
 impl<'a> Builder<'a> {
+    fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
+        macro_rules! describe {
+            ($($rule:ty),+ $(,)*) => {{
+                vec![$(StepDescription::from::<$rule>()),+]
+            }};
+        }
+        match kind {
+            Kind::Build => describe!(compile::Std, compile::Test, compile::Rustc,
+                compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex,
+                tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
+                tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
+                tool::RustInstaller, tool::Cargo, tool::Rls),
+            Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest,
+                check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Linkcheck,
+                check::Cargotest, check::Cargo, check::Rls, check::Docs, check::ErrorIndex,
+                check::Distcheck),
+            Kind::Bench => describe!(check::Crate, check::CrateLibrustc),
+            Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
+                doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
+                doc::Reference),
+            Kind::Dist => describe!(dist::Docs, dist::Mingw, dist::Rustc, dist::DebuggerScripts,
+                dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo,
+                dist::Rls, dist::Extended, dist::HashSign),
+            Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls,
+                install::Analysis, install::Src, install::Rustc),
+        }
+    }
+
+    pub fn get_help(build: &Build, subcommand: &str) -> Option<String> {
+        let kind = match subcommand {
+            "build" => Kind::Build,
+            "doc" => Kind::Doc,
+            "test" => Kind::Test,
+            "bench" => Kind::Bench,
+            "dist" => Kind::Dist,
+            "install" => Kind::Install,
+            _ => return None,
+        };
+
+        let builder = Builder {
+            build: build,
+            top_stage: build.flags.stage.unwrap_or(2),
+            kind: kind,
+            cache: Cache::new(),
+            stack: RefCell::new(Vec::new()),
+        };
+
+        let builder = &builder;
+        let mut should_run = ShouldRun::new(builder);
+        for desc in Builder::get_step_descriptions(builder.kind) {
+            should_run = (desc.should_run)(should_run);
+        }
+        let mut help = String::from("Available paths:\n");
+        for path in should_run.paths {
+            help.push_str(format!("    ./x.py {} {}\n", subcommand, path.display()).as_str());
+        }
+        Some(help)
+    }
+
     pub fn run(build: &Build) {
         let (kind, paths) = match build.flags.cmd {
             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
@@ -142,56 +302,44 @@ pub fn run(build: &Build) {
             stack: RefCell::new(Vec::new()),
         };
 
-        let builder = &builder;
-        match builder.kind {
-            Kind::Build => check!(builder, paths, compile::Std, compile::Test, compile::Rustc,
-                compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex,
-                tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest,
-                tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
-                tool::RustInstaller, tool::Cargo, tool::Rls),
-            Kind::Test => check!(builder, paths, check::Tidy, check::Bootstrap, check::Compiletest,
-                check::Krate, check::KrateLibrustc, check::Linkcheck, check::Cargotest,
-                check::Cargo, check::Docs, check::ErrorIndex, check::Distcheck),
-            Kind::Bench => check!(builder, paths, check::Krate, check::KrateLibrustc),
-            Kind::Doc => builder.default_doc(Some(paths)),
-            Kind::Dist => check!(builder, paths, dist::Docs, dist::Mingw, dist::Rustc,
-                dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src,
-                dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Extended, dist::HashSign),
-            Kind::Install => check!(builder, paths, install::Docs, install::Std, install::Cargo,
-                install::Rls, install::Analysis, install::Src, install::Rustc),
-        }
+        StepDescription::run(&Builder::get_step_descriptions(builder.kind), &builder, paths);
     }
 
     pub fn default_doc(&self, paths: Option<&[PathBuf]>) {
         let paths = paths.unwrap_or(&[]);
-        check!(self, paths, doc::UnstableBook, doc::UnstableBookGen, doc::Rustbook, doc::TheBook,
-            doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex,
-            doc::Nomicon, doc::Reference);
+        StepDescription::run(&Builder::get_step_descriptions(Kind::Doc), self, paths);
     }
 
     /// Obtain a compiler at a given stage and for a given host. Explictly does
     /// not take `Compiler` since all `Compiler` instances are meant to be
     /// obtained through this function, since it ensures that they are valid
     /// (i.e., built and assembled).
-    pub fn compiler(&'a self, stage: u32, host: &'a str) -> Compiler<'a> {
+    pub fn compiler(&self, stage: u32, host: Interned<String>) -> Compiler {
         self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } })
     }
 
-    pub fn sysroot(&self, compiler: Compiler<'a>) -> PathBuf {
+    pub fn sysroot(&self, compiler: Compiler) -> Interned<PathBuf> {
         self.ensure(compile::Sysroot { compiler })
     }
 
     /// Returns the libdir where the standard library and other artifacts are
     /// found for a compiler's sysroot.
-    pub fn sysroot_libdir(&self, compiler: Compiler<'a>, target: &'a str) -> PathBuf {
-        #[derive(Serialize)]
-        struct Libdir<'a> {
-            compiler: Compiler<'a>,
-            target: &'a str,
+    pub fn sysroot_libdir(
+        &self, compiler: Compiler, target: Interned<String>
+    ) -> Interned<PathBuf> {
+        #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+        struct Libdir {
+            compiler: Compiler,
+            target: Interned<String>,
         }
-        impl<'a> Step<'a> for Libdir<'a> {
-            type Output = PathBuf;
-            fn run(self, builder: &Builder) -> PathBuf {
+        impl Step for Libdir {
+            type Output = Interned<PathBuf>;
+
+            fn should_run(run: ShouldRun) -> ShouldRun {
+                run.never()
+            }
+
+            fn run(self, builder: &Builder) -> Interned<PathBuf> {
                 let compiler = self.compiler;
                 let lib = if compiler.stage >= 2 && builder.build.config.libdir_relative.is_some() {
                     builder.build.config.libdir_relative.clone().unwrap()
@@ -202,7 +350,7 @@ fn run(self, builder: &Builder) -> PathBuf {
                     .join("rustlib").join(self.target).join("lib");
                 let _ = fs::remove_dir_all(&sysroot);
                 t!(fs::create_dir_all(&sysroot));
-                sysroot
+                INTERNER.intern_path(sysroot)
             }
         }
         self.ensure(Libdir { compiler, target })
@@ -217,7 +365,7 @@ pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
         if compiler.is_snapshot(self) {
             self.build.rustc_snapshot_libdir()
         } else {
-            self.sysroot(compiler).join(libdir(compiler.host))
+            self.sysroot(compiler).join(libdir(&compiler.host))
         }
     }
 
@@ -239,7 +387,7 @@ pub fn rustc(&self, compiler: Compiler) -> PathBuf {
         if compiler.is_snapshot(self) {
             self.initial_rustc.clone()
         } else {
-            self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
+            self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host))
         }
     }
 
@@ -247,7 +395,7 @@ pub fn rustc(&self, compiler: Compiler) -> PathBuf {
     pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
         let mut rustdoc = self.rustc(compiler);
         rustdoc.pop();
-        rustdoc.push(exe("rustdoc", compiler.host));
+        rustdoc.push(exe("rustdoc", &compiler.host));
         rustdoc
     }
 
@@ -261,7 +409,7 @@ pub fn rustdoc(&self, compiler: Compiler) -> PathBuf {
     pub fn cargo(&self,
              compiler: Compiler,
              mode: Mode,
-             target: &str,
+             target: Interned<String>,
              cmd: &str) -> Command {
         let mut cargo = Command::new(&self.initial_cargo);
         let out_dir = self.stage_out(compiler, mode);
@@ -386,19 +534,6 @@ pub fn cargo(&self,
             cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
         }
 
-        // When being built Cargo will at some point call `nmake.exe` on Windows
-        // MSVC. Unfortunately `nmake` will read these two environment variables
-        // below and try to intepret them. We're likely being run, however, from
-        // MSYS `make` which uses the same variables.
-        //
-        // As a result, to prevent confusion and errors, we remove these
-        // variables from our environment to prevent passing MSYS make flags to
-        // nmake, causing it to blow up.
-        if cfg!(target_env = "msvc") {
-            cargo.env_remove("MAKE");
-            cargo.env_remove("MAKEFLAGS");
-        }
-
         // Environment variables *required* throughout the build
         //
         // FIXME: should update code to not require this env var
@@ -423,73 +558,40 @@ pub fn cargo(&self,
         cargo
     }
 
-    fn maybe_run<S: Step<'a>>(&'a self, path: Option<&Path>) {
-        let build = self.build;
-        let hosts = if S::ONLY_BUILD_TARGETS || S::ONLY_BUILD {
-            &build.config.host[..1]
-        } else {
-            &build.hosts
-        };
-
-        // Determine the actual targets participating in this rule.
-        // NOTE: We should keep the full projection from build triple to
-        // the hosts for the dist steps, now that the hosts array above is
-        // truncated to avoid duplication of work in that case. Therefore
-        // the original non-shadowed hosts array is used below.
-        let targets = if S::ONLY_HOSTS {
-            // If --target was specified but --host wasn't specified,
-            // don't run any host-only tests. Also, respect any `--host`
-            // overrides as done for `hosts`.
-            if build.flags.host.len() > 0 {
-                &build.flags.host[..]
-            } else if build.flags.target.len() > 0 {
-                &[]
-            } else if S::ONLY_BUILD {
-                &build.config.host[..1]
-            } else {
-                &build.config.host[..]
-            }
-        } else {
-            &build.targets
-        };
-
-        for host in hosts {
-            for target in targets {
-                S::make_run(self, path, host, target);
-            }
-        }
-    }
-
     /// Ensure that a given step is built, returning it's output. This will
     /// cache the step, so it is safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are built.
-    pub fn ensure<S: Step<'a>>(&'a self, step: S) -> S::Output {
-        let key = Cache::to_key(&step);
+    pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
         {
             let mut stack = self.stack.borrow_mut();
-            if stack.contains(&key) {
+            for stack_step in stack.iter() {
+                // should skip
+                if stack_step.downcast_ref::<S>().map_or(true, |stack_step| *stack_step != step) {
+                    continue;
+                }
                 let mut out = String::new();
-                out += &format!("\n\nCycle in build detected when adding {:?}\n", key);
+                out += &format!("\n\nCycle in build detected when adding {:?}\n", step);
                 for el in stack.iter().rev() {
                     out += &format!("\t{:?}\n", el);
                 }
                 panic!(out);
             }
-            if let Some(out) = self.cache.get::<S::Output>(&key) {
-                self.build.verbose(&format!("{}c {:?}", "  ".repeat(stack.len()), key));
+            if let Some(out) = self.cache.get(&step) {
+                self.build.verbose(&format!("{}c {:?}", "  ".repeat(stack.len()), step));
 
                 return out;
             }
-            self.build.verbose(&format!("{}> {:?}", "  ".repeat(stack.len()), key));
-            stack.push(key.clone());
+            self.build.verbose(&format!("{}> {:?}", "  ".repeat(stack.len()), step));
+            stack.push(Box::new(step.clone()));
         }
-        let out = step.run(self);
+        let out = step.clone().run(self);
         {
             let mut stack = self.stack.borrow_mut();
-            assert_eq!(stack.pop().as_ref(), Some(&key));
+            let cur_step = stack.pop().expect("step stack empty");
+            assert_eq!(cur_step.downcast_ref(), Some(&step));
         }
-        self.build.verbose(&format!("{}< {:?}", "  ".repeat(self.stack.borrow().len()), key));
-        self.cache.put(key.clone(), &out);
-        self.cache.get::<S::Output>(&key).unwrap()
+        self.build.verbose(&format!("{}< {:?}", "  ".repeat(self.stack.borrow().len()), step));
+        self.cache.put(step, out.clone());
+        out
     }
 }