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