]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #41170 - Nashenas88:master, r=alexcrichton
authorbors <bors@rust-lang.org>
Wed, 19 Apr 2017 05:54:23 +0000 (05:54 +0000)
committerbors <bors@rust-lang.org>
Wed, 19 Apr 2017 05:54:23 +0000 (05:54 +0000)
Use the existing path when removing the prefix fails

This allows the use of out-of-tree paths to be specified. I found this while trying to build with a modified version of `rls-data`, which is currently pointing to a version on crates.io.

cc @alexcrichton

Also, it wasn't clear if I needed to add a test for this (or how). I didn't see any tests that took paths into consideration.

1  2 
src/bootstrap/step.rs

diff --combined src/bootstrap/step.rs
index 34705040e8a5e116bd33f31ab7f469b256a592d6,74c9ae983737327c66a14f3786c4e9cc28ba926c..17902a39df1e82b4b76fa45034131fb67f630239
@@@ -26,7 -26,7 +26,7 @@@
  //! along with the actual implementation elsewhere. You can find more comments
  //! about how to define rules themselves below.
  
 -use std::collections::{BTreeMap, HashSet};
 +use std::collections::{BTreeMap, HashSet, HashMap};
  use std::mem;
  
  use check::{self, TestKind};
@@@ -137,7 -137,9 +137,9 @@@ pub fn build_rules<'a>(build: &'a Build
          while let Some(krate) = list.pop() {
              let default = krate == name;
              let krate = &build.crates[krate];
-             let path = krate.path.strip_prefix(&build.src).unwrap();
+             let path = krate.path.strip_prefix(&build.src)
+                 // This handles out of tree paths
+                 .unwrap_or(&krate.path);
              ret.push((krate, path.to_str().unwrap(), default));
              for dep in krate.deps.iter() {
                  if visited.insert(dep) && dep != "build_helper" {
      //
      // Tools used during the build system but not shipped
      rules.build("tool-rustbook", "src/tools/rustbook")
 -         .dep(|s| s.name("librustc"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("librustc-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
      rules.build("tool-error-index", "src/tools/error_index_generator")
 -         .dep(|s| s.name("librustc"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("librustc-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
      rules.build("tool-tidy", "src/tools/tidy")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
      rules.build("tool-linkchecker", "src/tools/linkchecker")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
      rules.build("tool-cargotest", "src/tools/cargotest")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
      rules.build("tool-compiletest", "src/tools/compiletest")
 -         .dep(|s| s.name("libtest"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libtest-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
      rules.build("tool-build-manifest", "src/tools/build-manifest")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
      rules.build("tool-qemu-test-server", "src/tools/qemu-test-server")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-server"));
      rules.build("tool-qemu-test-client", "src/tools/qemu-test-client")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client"));
      rules.build("tool-cargo", "cargo")
 -         .dep(|s| s.name("libstd"))
 +         .dep(|s| s.name("maybe-clean-tools"))
 +         .dep(|s| s.name("libstd-tool"))
           .dep(|s| s.stage(0).host(s.target).name("openssl"))
           .dep(move |s| {
               // Cargo depends on procedural macros, which requires a full host
                .host(&build.config.build)
           })
           .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
 +    rules.build("tool-rls", "rls")
 +         .host(true)
 +         .dep(|s| s.name("librustc-tool"))
 +         .dep(|s| s.stage(0).host(s.target).name("openssl"))
 +         .dep(move |s| {
 +             // rls, like cargo, uses procedural macros
 +             s.name("librustc-link")
 +              .target(&build.config.build)
 +              .host(&build.config.build)
 +         })
 +         .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
 +
 +    // "pseudo rule" which represents completely cleaning out the tools dir in
 +    // one stage. This needs to happen whenever a dependency changes (e.g.
 +    // libstd, libtest, librustc) and all of the tool compilations above will
 +    // be sequenced after this rule.
 +    rules.build("maybe-clean-tools", "path/to/nowhere")
 +         .after("librustc-tool")
 +         .after("libtest-tool")
 +         .after("libstd-tool");
 +
 +    rules.build("librustc-tool", "path/to/nowhere")
 +         .dep(|s| s.name("librustc"))
 +         .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Librustc));
 +    rules.build("libtest-tool", "path/to/nowhere")
 +         .dep(|s| s.name("libtest"))
 +         .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libtest));
 +    rules.build("libstd-tool", "path/to/nowhere")
 +         .dep(|s| s.name("libstd"))
 +         .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libstd));
  
      // ========================================================================
      // Documentation targets
           .dep(|s| s.name("default:doc"))
           .run(move |s| dist::docs(build, s.stage, s.target));
      rules.dist("dist-analysis", "analysis")
 +         .default(build.config.extended)
           .dep(|s| s.name("dist-std"))
 -         .default(true)
           .only_host_build(true)
           .run(move |s| dist::analysis(build, &s.compiler(), s.target));
 +    rules.dist("dist-rls", "rls")
 +         .host(true)
 +         .only_host_build(true)
 +         .dep(|s| s.name("tool-rls"))
 +         .run(move |s| dist::rls(build, s.stage, s.target));
      rules.dist("install", "path/to/nowhere")
           .dep(|s| s.name("default:dist"))
           .run(move |s| install::install(build, s.stage, s.target));
           .dep(|d| d.name("dist-mingw"))
           .dep(|d| d.name("dist-docs"))
           .dep(|d| d.name("dist-cargo"))
 +         .dep(|d| d.name("dist-rls"))
 +         .dep(|d| d.name("dist-analysis"))
           .run(move |s| dist::extended(build, s.stage, s.target));
  
      rules.dist("dist-sign", "hash-and-sign")
@@@ -858,11 -813,6 +860,11 @@@ struct Rule<'a> 
      /// Whether this rule is only for the build triple, not anything in hosts or
      /// targets.
      only_build: bool,
 +
 +    /// A list of "order only" dependencies. This rules does not actually
 +    /// depend on these rules, but if they show up in the dependency graph then
 +    /// this rule must be executed after all these rules.
 +    after: Vec<&'a str>,
  }
  
  #[derive(PartialEq)]
@@@ -886,7 -836,6 +888,7 @@@ impl<'a> Rule<'a> 
              host: false,
              only_host_build: false,
              only_build: false,
 +            after: Vec::new(),
          }
      }
  }
@@@ -906,11 -855,6 +908,11 @@@ impl<'a, 'b> RuleBuilder<'a, 'b> 
          self
      }
  
 +    fn after(&mut self, step: &'a str) -> &mut Self {
 +        self.rule.after.push(step);
 +        self
 +    }
 +
      fn run<F>(&mut self, f: F) -> &mut Self
          where F: Fn(&Step<'a>) + 'a,
      {
@@@ -1194,52 -1138,31 +1196,52 @@@ invalid rule dependency graph detected
      /// From the top level targets `steps` generate a topological ordering of
      /// all steps needed to run those steps.
      fn expand(&self, steps: &[Step<'a>]) -> Vec<Step<'a>> {
 +        // First up build a graph of steps and their dependencies. The `nodes`
 +        // map is a map from step to a unique number. The `edges` map is a
 +        // map from these unique numbers to a list of other numbers,
 +        // representing dependencies.
 +        let mut nodes = HashMap::new();
 +        nodes.insert(Step::noop(), 0);
 +        let mut edges = HashMap::new();
 +        edges.insert(0, HashSet::new());
 +        for step in steps {
 +            self.build_graph(step.clone(), &mut nodes, &mut edges);
 +        }
 +
 +        // Now that we've built up the actual dependency graph, draw more
 +        // dependency edges to satisfy the `after` dependencies field for each
 +        // rule.
 +        self.satisfy_after_deps(&nodes, &mut edges);
 +
 +        // And finally, perform a topological sort to return a list of steps to
 +        // execute.
          let mut order = Vec::new();
 -        let mut added = HashSet::new();
 -        added.insert(Step::noop());
 -        for step in steps.iter().cloned() {
 -            self.fill(step, &mut order, &mut added);
 +        let mut visited = HashSet::new();
 +        visited.insert(0);
 +        let idx_to_node = nodes.iter().map(|p| (*p.1, p.0)).collect::<HashMap<_, _>>();
 +        for idx in 0..nodes.len() {
 +            self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order);
          }
          return order
      }
  
 -    /// Performs topological sort of dependencies rooted at the `step`
 -    /// specified, pushing all results onto the `order` vector provided.
 +    /// Builds the dependency graph rooted at `step`.
      ///
 -    /// In other words, when this method returns, the `order` vector will
 -    /// contain a list of steps which if executed in order will eventually
 -    /// complete the `step` specified as well.
 -    ///
 -    /// The `added` set specified here is the set of steps that are already
 -    /// present in `order` (and hence don't need to be added again).
 -    fn fill(&self,
 -            step: Step<'a>,
 -            order: &mut Vec<Step<'a>>,
 -            added: &mut HashSet<Step<'a>>) {
 -        if !added.insert(step.clone()) {
 -            return
 +    /// The `nodes` and `edges` maps are filled out according to the rule
 +    /// described by `step.name`.
 +    fn build_graph(&self,
 +                   step: Step<'a>,
 +                   nodes: &mut HashMap<Step<'a>, usize>,
 +                   edges: &mut HashMap<usize, HashSet<usize>>) -> usize {
 +        use std::collections::hash_map::Entry;
 +
 +        let idx = nodes.len();
 +        match nodes.entry(step.clone()) {
 +            Entry::Vacant(e) => { e.insert(idx); }
 +            Entry::Occupied(e) => return *e.get(),
          }
 +
 +        let mut deps = Vec::new();
          for dep in self.rules[step.name].deps.iter() {
              let dep = dep(&step);
              if dep.name.starts_with("default:") {
                  let host = self.build.config.host.iter().any(|h| h == dep.target);
                  let rules = self.rules.values().filter(|r| r.default);
                  for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) {
 -                    self.fill(dep.name(rule.name), order, added);
 +                    deps.push(self.build_graph(dep.name(rule.name), nodes, edges));
                  }
              } else {
 -                self.fill(dep, order, added);
 +                deps.push(self.build_graph(dep, nodes, edges));
              }
          }
 -        order.push(step);
 +
 +        edges.entry(idx).or_insert(HashSet::new()).extend(deps);
 +        return idx
 +    }
 +
 +    /// Given a dependency graph with a finished list of `nodes`, fill out more
 +    /// dependency `edges`.
 +    ///
 +    /// This is the step which satisfies all `after` listed dependencies in
 +    /// `Rule` above.
 +    fn satisfy_after_deps(&self,
 +                          nodes: &HashMap<Step<'a>, usize>,
 +                          edges: &mut HashMap<usize, HashSet<usize>>) {
 +        // Reverse map from the name of a step to the node indices that it
 +        // appears at.
 +        let mut name_to_idx = HashMap::new();
 +        for (step, &idx) in nodes {
 +            name_to_idx.entry(step.name).or_insert(Vec::new()).push(idx);
 +        }
 +
 +        for (step, idx) in nodes {
 +            if *step == Step::noop() {
 +                continue
 +            }
 +            for after in self.rules[step.name].after.iter() {
 +                // This is the critical piece of an `after` dependency. If the
 +                // dependency isn't actually in our graph then no edge is drawn,
 +                // only if it's already present do we draw the edges.
 +                if let Some(idxs) = name_to_idx.get(after) {
 +                    edges.get_mut(idx).unwrap()
 +                         .extend(idxs.iter().cloned());
 +                }
 +            }
 +        }
 +    }
 +
 +    fn topo_sort(&self,
 +                 cur: usize,
 +                 nodes: &HashMap<usize, &Step<'a>>,
 +                 edges: &HashMap<usize, HashSet<usize>>,
 +                 visited: &mut HashSet<usize>,
 +                 order: &mut Vec<Step<'a>>) {
 +        if !visited.insert(cur) {
 +            return
 +        }
 +        for dep in edges[&cur].iter() {
 +            self.topo_sort(*dep, nodes, edges, visited, order);
 +        }
 +        order.push(nodes[&cur].clone());
      }
  }