]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/tool.rs
Require should_run to be implemented.
[rust.git] / src / bootstrap / tool.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::env;
12 use std::path::{Path, PathBuf};
13 use std::process::Command;
14
15 use Mode;
16 use Compiler;
17 use builder::{Step, Builder};
18 use util::{exe, add_lib_path};
19 use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp, Rustc};
20 use native;
21 use channel::GitInfo;
22 use cache::Interned;
23
24 //// ========================================================================
25 //// Build tools
26 ////
27 //// Tools used during the build system but not shipped
28 //// "pseudo rule" which represents completely cleaning out the tools dir in
29 //// one stage. This needs to happen whenever a dependency changes (e.g.
30 //// libstd, libtest, librustc) and all of the tool compilations above will
31 //// be sequenced after this rule.
32 //rules.build("maybe-clean-tools", "path/to/nowhere")
33 //     .after("librustc-tool")
34 //     .after("libtest-tool")
35 //     .after("libstd-tool");
36 //
37 //rules.build("librustc-tool", "path/to/nowhere")
38 //     .dep(|s| s.name("librustc"))
39 //     .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Librustc));
40 //rules.build("libtest-tool", "path/to/nowhere")
41 //     .dep(|s| s.name("libtest"))
42 //     .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libtest));
43 //rules.build("libstd-tool", "path/to/nowhere")
44 //     .dep(|s| s.name("libstd"))
45 //     .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libstd));
46 //
47
48 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
49 pub struct CleanTools {
50     pub stage: u32,
51     pub target: Interned<String>,
52     pub mode: Mode,
53 }
54
55 impl Step for CleanTools {
56     type Output = ();
57
58     fn should_run(_builder: &Builder, _path: &Path) -> bool {
59         false
60     }
61
62     /// Build a tool in `src/tools`
63     ///
64     /// This will build the specified tool with the specified `host` compiler in
65     /// `stage` into the normal cargo output directory.
66     fn run(self, builder: &Builder) {
67         let build = builder.build;
68         let stage = self.stage;
69         let target = self.target;
70         let mode = self.mode;
71
72         let compiler = builder.compiler(stage, build.build);
73
74         let stamp = match mode {
75             Mode::Libstd => libstd_stamp(build, compiler, target),
76             Mode::Libtest => libtest_stamp(build, compiler, target),
77             Mode::Librustc => librustc_stamp(build, compiler, target),
78             _ => panic!(),
79         };
80         let out_dir = build.cargo_out(compiler, Mode::Tool, target);
81         build.clear_if_dirty(&out_dir, &stamp);
82     }
83 }
84
85 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
86 pub struct ToolBuild {
87     pub stage: u32,
88     pub target: Interned<String>,
89     pub tool: &'static str,
90     pub mode: Mode,
91 }
92
93 impl Step for ToolBuild {
94     type Output = PathBuf;
95
96     fn should_run(_builder: &Builder, _path: &Path) -> bool {
97         false
98     }
99
100     /// Build a tool in `src/tools`
101     ///
102     /// This will build the specified tool with the specified `host` compiler in
103     /// `stage` into the normal cargo output directory.
104     fn run(self, builder: &Builder) -> PathBuf {
105         let build = builder.build;
106         let stage = self.stage;
107         let target = self.target;
108         let tool = self.tool;
109
110         let compiler = builder.compiler(stage, build.build);
111         builder.ensure(CleanTools { stage, target, mode: self.mode });
112         match self.mode {
113             Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
114             Mode::Libtest => builder.ensure(compile::Test { compiler, target }),
115             Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }),
116             Mode::Tool => panic!("unexpected Mode::Tool for tool build")
117         }
118
119         let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
120         println!("Building stage{} tool {} ({})", stage, tool, target);
121
122         let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
123         let dir = build.src.join("src/tools").join(tool);
124         cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
125
126         // We don't want to build tools dynamically as they'll be running across
127         // stages and such and it's just easier if they're not dynamically linked.
128         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
129
130         if let Some(dir) = build.openssl_install_dir(target) {
131             cargo.env("OPENSSL_STATIC", "1");
132             cargo.env("OPENSSL_DIR", dir);
133             cargo.env("LIBZ_SYS_STATIC", "1");
134         }
135
136         cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
137
138         let info = GitInfo::new(&dir);
139         if let Some(sha) = info.sha() {
140             cargo.env("CFG_COMMIT_HASH", sha);
141         }
142         if let Some(sha_short) = info.sha_short() {
143             cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
144         }
145         if let Some(date) = info.commit_date() {
146             cargo.env("CFG_COMMIT_DATE", date);
147         }
148
149         build.run(&mut cargo);
150         build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
151     }
152 }
153
154 macro_rules! tool {
155     ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
156         #[derive(Copy, Clone)]
157         pub enum Tool {
158             $(
159                 $name,
160             )+
161         }
162
163         impl<'a> Builder<'a> {
164             pub fn tool_exe(&self, tool: Tool) -> PathBuf {
165                 match tool {
166                     $(Tool::$name =>
167                         self.ensure($name {
168                             stage: 0,
169                             target: self.build.build,
170                         }),
171                     )+
172                 }
173             }
174         }
175
176         $(
177             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
178         pub struct $name {
179             pub stage: u32,
180             pub target: Interned<String>,
181         }
182
183         impl Step for $name {
184             type Output = PathBuf;
185
186             fn should_run(_builder: &Builder, path: &Path) -> bool {
187                 path.ends_with($path)
188             }
189
190             fn make_run(
191                 builder: &Builder,
192                 _path: Option<&Path>,
193                 _host: Interned<String>,
194                 target: Interned<String>
195             ) {
196                 builder.ensure($name {
197                     stage: builder.top_stage,
198                     target,
199                 });
200             }
201
202             fn run(self, builder: &Builder) -> PathBuf {
203                 builder.ensure(ToolBuild {
204                     stage: self.stage,
205                     target: self.target,
206                     tool: $tool_name,
207                     mode: $mode,
208                 })
209             }
210         }
211         )+
212     }
213 }
214
215 tool!(
216     // rules.build("tool-rustbook", "src/tools/rustbook")
217     //      .dep(|s| s.name("maybe-clean-tools"))
218     //      .dep(|s| s.name("librustc-tool"))
219     //      .run(move |s| compile::tool(build, s.stage, s.target, "rustbook"));
220     Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc;
221     // rules.build("tool-error-index", "src/tools/error_index_generator")
222     //      .dep(|s| s.name("maybe-clean-tools"))
223     //      .dep(|s| s.name("librustc-tool"))
224     //      .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator"));
225     ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc;
226     // rules.build("tool-unstable-book-gen", "src/tools/unstable-book-gen")
227     //      .dep(|s| s.name("maybe-clean-tools"))
228     //      .dep(|s| s.name("libstd-tool"))
229     //      .run(move |s| compile::tool(build, s.stage, s.target, "unstable-book-gen"));
230     UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
231     // rules.build("tool-tidy", "src/tools/tidy")
232     //      .dep(|s| s.name("maybe-clean-tools"))
233     //      .dep(|s| s.name("libstd-tool"))
234     //      .run(move |s| compile::tool(build, s.stage, s.target, "tidy"));
235     Tidy, "src/tools/tidy", "tidy", Mode::Libstd;
236     // rules.build("tool-linkchecker", "src/tools/linkchecker")
237     //      .dep(|s| s.name("maybe-clean-tools"))
238     //      .dep(|s| s.name("libstd-tool"))
239     //      .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker"));
240     Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
241     // rules.build("tool-cargotest", "src/tools/cargotest")
242     //      .dep(|s| s.name("maybe-clean-tools"))
243     //      .dep(|s| s.name("libstd-tool"))
244     //      .run(move |s| compile::tool(build, s.stage, s.target, "cargotest"));
245     CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
246     // rules.build("tool-compiletest", "src/tools/compiletest")
247     //      .dep(|s| s.name("maybe-clean-tools"))
248     //      .dep(|s| s.name("libtest-tool"))
249     //      .run(move |s| compile::tool(build, s.stage, s.target, "compiletest"));
250     Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
251     // rules.build("tool-build-manifest", "src/tools/build-manifest")
252     //      .dep(|s| s.name("maybe-clean-tools"))
253     //      .dep(|s| s.name("libstd-tool"))
254     //      .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest"));
255     BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Librustc;
256     // rules.build("tool-remote-test-client", "src/tools/remote-test-client")
257     //      .dep(|s| s.name("maybe-clean-tools"))
258     //      .dep(|s| s.name("libstd-tool"))
259     //      .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-client"));
260     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
261     // rules.build("tool-rust-installer", "src/tools/rust-installer")
262     //      .dep(|s| s.name("maybe-clean-tools"))
263     //      .dep(|s| s.name("libstd-tool"))
264     //      .run(move |s| compile::tool(build, s.stage, s.target, "rust-installer"));
265     RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
266 );
267
268 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
269 pub struct RemoteTestServer {
270     pub stage: u32,
271     pub target: Interned<String>,
272 }
273
274 impl Step for RemoteTestServer {
275     type Output = PathBuf;
276
277     fn should_run(_builder: &Builder, path: &Path) -> bool {
278         path.ends_with("src/tools/remote-test-server")
279     }
280
281     fn make_run(
282         builder: &Builder,
283         _path: Option<&Path>,
284         _host: Interned<String>,
285         target: Interned<String>
286     ) {
287         builder.ensure(RemoteTestServer {
288             stage: builder.top_stage,
289             target,
290         });
291     }
292
293     fn run(self, builder: &Builder) -> PathBuf {
294         builder.ensure(ToolBuild {
295             stage: self.stage,
296             target: self.target,
297             tool: "remote-test-server",
298             mode: Mode::Libstd,
299         })
300     }
301 }
302
303 // rules.build("tool-cargo", "src/tools/cargo")
304 //      .host(true)
305 //      .default(build.config.extended)
306 //      .dep(|s| s.name("maybe-clean-tools"))
307 //      .dep(|s| s.name("libstd-tool"))
308 //      .dep(|s| s.stage(0).host(s.target).name("openssl"))
309 //      .dep(move |s| {
310 //          // Cargo depends on procedural macros, which requires a full host
311 //          // compiler to be available, so we need to depend on that.
312 //          s.name("librustc-link")
313 //           .target(&build.build)
314 //           .host(&build.build)
315 //      })
316 //      .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
317 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
318 pub struct Cargo {
319     pub stage: u32,
320     pub target: Interned<String>,
321 }
322
323 impl Step for Cargo {
324     type Output = PathBuf;
325     const DEFAULT: bool = true;
326     const ONLY_HOSTS: bool = true;
327
328     fn should_run(_builder: &Builder, path: &Path) -> bool {
329         path.ends_with("src/tools/cargo")
330     }
331
332     fn make_run(
333         builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
334     ) {
335         if path.is_none() && !builder.build.config.extended {
336             return;
337         }
338         builder.ensure(Cargo {
339             stage: builder.top_stage,
340             target,
341         });
342     }
343
344     fn run(self, builder: &Builder) -> PathBuf {
345         builder.ensure(native::Openssl {
346             target: self.target,
347         });
348         // Cargo depends on procedural macros, which requires a full host
349         // compiler to be available, so we need to depend on that.
350         builder.ensure(Rustc {
351             compiler: builder.compiler(builder.top_stage, builder.build.build),
352             target: builder.build.build,
353         });
354         builder.ensure(ToolBuild {
355             stage: self.stage,
356             target: self.target,
357             tool: "cargo",
358             mode: Mode::Libstd,
359         })
360     }
361 }
362
363 // rules.build("tool-rls", "src/tools/rls")
364 //      .host(true)
365 //      .default(build.config.extended)
366 //      .dep(|s| s.name("librustc-tool"))
367 //      .dep(|s| s.stage(0).host(s.target).name("openssl"))
368 //      .dep(move |s| {
369 //          // rls, like cargo, uses procedural macros
370 //          s.name("librustc-link")
371 //           .target(&build.build)
372 //           .host(&build.build)
373 //      })
374 //      .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
375 //
376 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
377 pub struct Rls {
378     pub stage: u32,
379     pub target: Interned<String>,
380 }
381
382 impl Step for Rls {
383     type Output = PathBuf;
384     const DEFAULT: bool = true;
385     const ONLY_HOSTS: bool = true;
386
387     fn should_run(_builder: &Builder, path: &Path) -> bool {
388         path.ends_with("src/tools/rls")
389     }
390
391     fn make_run(
392         builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
393     ) {
394         if path.is_none() && !builder.build.config.extended {
395             return;
396         }
397         builder.ensure(Cargo {
398             stage: builder.top_stage,
399             target,
400         });
401     }
402
403     fn run(self, builder: &Builder) -> PathBuf {
404         builder.ensure(native::Openssl {
405             target: self.target,
406         });
407         // RLS depends on procedural macros, which requires a full host
408         // compiler to be available, so we need to depend on that.
409         builder.ensure(Rustc {
410             compiler: builder.compiler(builder.top_stage, builder.build.build),
411             target: builder.build.build,
412         });
413         builder.ensure(ToolBuild {
414             stage: self.stage,
415             target: self.target,
416             tool: "rls",
417             mode: Mode::Librustc,
418         })
419     }
420 }
421
422 impl<'a> Builder<'a> {
423     /// Get a `Command` which is ready to run `tool` in `stage` built for
424     /// `host`.
425     pub fn tool_cmd(&self, tool: Tool) -> Command {
426         let mut cmd = Command::new(self.tool_exe(tool));
427         let compiler = self.compiler(0, self.build.build);
428         self.prepare_tool_cmd(compiler, &mut cmd);
429         cmd
430     }
431
432     /// Prepares the `cmd` provided to be able to run the `compiler` provided.
433     ///
434     /// Notably this munges the dynamic library lookup path to point to the
435     /// right location to run `compiler`.
436     fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
437         let host = &compiler.host;
438         let mut paths: Vec<PathBuf> = vec![
439             PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
440             self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
441         ];
442
443         // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
444         // mode) and that C compiler may need some extra PATH modification. Do
445         // so here.
446         if compiler.host.contains("msvc") {
447             let curpaths = env::var_os("PATH").unwrap_or_default();
448             let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
449             for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
450                 if k != "PATH" {
451                     continue
452                 }
453                 for path in env::split_paths(v) {
454                     if !curpaths.contains(&path) {
455                         paths.push(path);
456                     }
457                 }
458             }
459         }
460         add_lib_path(paths, cmd);
461     }
462 }