]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/tool.rs
9db6493ba3172335e0a2b32efac750e332500800
[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, ShouldRun, Builder};
18 use util::{exe, add_lib_path};
19 use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
20 use native;
21 use channel::GitInfo;
22 use cache::Interned;
23
24 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
25 pub struct CleanTools {
26     pub stage: u32,
27     pub target: Interned<String>,
28     pub mode: Mode,
29 }
30
31 impl Step for CleanTools {
32     type Output = ();
33
34     fn should_run(run: ShouldRun) -> ShouldRun {
35         run.never()
36     }
37
38     /// Build a tool in `src/tools`
39     ///
40     /// This will build the specified tool with the specified `host` compiler in
41     /// `stage` into the normal cargo output directory.
42     fn run(self, builder: &Builder) {
43         let build = builder.build;
44         let stage = self.stage;
45         let target = self.target;
46         let mode = self.mode;
47
48         let compiler = builder.compiler(stage, build.build);
49
50         let stamp = match mode {
51             Mode::Libstd => libstd_stamp(build, compiler, target),
52             Mode::Libtest => libtest_stamp(build, compiler, target),
53             Mode::Librustc => librustc_stamp(build, compiler, target),
54             _ => panic!(),
55         };
56         let out_dir = build.cargo_out(compiler, Mode::Tool, target);
57         build.clear_if_dirty(&out_dir, &stamp);
58     }
59 }
60
61 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
62 pub struct ToolBuild {
63     pub stage: u32,
64     pub target: Interned<String>,
65     pub tool: &'static str,
66     pub mode: Mode,
67 }
68
69 impl Step for ToolBuild {
70     type Output = PathBuf;
71
72     fn should_run(run: ShouldRun) -> ShouldRun {
73         run.never()
74     }
75
76     /// Build a tool in `src/tools`
77     ///
78     /// This will build the specified tool with the specified `host` compiler in
79     /// `stage` into the normal cargo output directory.
80     fn run(self, builder: &Builder) -> PathBuf {
81         let build = builder.build;
82         let stage = self.stage;
83         let target = self.target;
84         let tool = self.tool;
85
86         let compiler = builder.compiler(stage, build.build);
87         builder.ensure(CleanTools { stage, target, mode: self.mode });
88         match self.mode {
89             Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
90             Mode::Libtest => builder.ensure(compile::Test { compiler, target }),
91             Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }),
92             Mode::Tool => panic!("unexpected Mode::Tool for tool build")
93         }
94
95         let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
96         println!("Building stage{} tool {} ({})", stage, tool, target);
97
98         let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
99         let dir = build.src.join("src/tools").join(tool);
100         cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
101
102         // We don't want to build tools dynamically as they'll be running across
103         // stages and such and it's just easier if they're not dynamically linked.
104         cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
105
106         if let Some(dir) = build.openssl_install_dir(target) {
107             cargo.env("OPENSSL_STATIC", "1");
108             cargo.env("OPENSSL_DIR", dir);
109             cargo.env("LIBZ_SYS_STATIC", "1");
110         }
111
112         cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
113
114         let info = GitInfo::new(&dir);
115         if let Some(sha) = info.sha() {
116             cargo.env("CFG_COMMIT_HASH", sha);
117         }
118         if let Some(sha_short) = info.sha_short() {
119             cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
120         }
121         if let Some(date) = info.commit_date() {
122             cargo.env("CFG_COMMIT_DATE", date);
123         }
124
125         build.run(&mut cargo);
126         build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
127     }
128 }
129
130 macro_rules! tool {
131     ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
132         #[derive(Copy, Clone)]
133         pub enum Tool {
134             $(
135                 $name,
136             )+
137         }
138
139         impl<'a> Builder<'a> {
140             pub fn tool_exe(&self, tool: Tool) -> PathBuf {
141                 match tool {
142                     $(Tool::$name =>
143                         self.ensure($name {
144                             stage: 0,
145                             target: self.build.build,
146                         }),
147                     )+
148                 }
149             }
150         }
151
152         $(
153             #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
154         pub struct $name {
155             pub stage: u32,
156             pub target: Interned<String>,
157         }
158
159         impl Step for $name {
160             type Output = PathBuf;
161
162             fn should_run(run: ShouldRun) -> ShouldRun {
163                 run.path($path)
164             }
165
166             fn make_run(
167                 builder: &Builder,
168                 _path: Option<&Path>,
169                 _host: Interned<String>,
170                 target: Interned<String>
171             ) {
172                 builder.ensure($name {
173                     stage: builder.top_stage,
174                     target,
175                 });
176             }
177
178             fn run(self, builder: &Builder) -> PathBuf {
179                 builder.ensure(ToolBuild {
180                     stage: self.stage,
181                     target: self.target,
182                     tool: $tool_name,
183                     mode: $mode,
184                 })
185             }
186         }
187         )+
188     }
189 }
190
191 tool!(
192     Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc;
193     ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc;
194     UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
195     Tidy, "src/tools/tidy", "tidy", Mode::Libstd;
196     Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
197     CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
198     Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
199     BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Librustc;
200     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
201     RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
202 );
203
204 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
205 pub struct RemoteTestServer {
206     pub stage: u32,
207     pub target: Interned<String>,
208 }
209
210 impl Step for RemoteTestServer {
211     type Output = PathBuf;
212
213     fn should_run(run: ShouldRun) -> ShouldRun {
214         run.path("src/tools/remote-test-server")
215     }
216
217     fn make_run(
218         builder: &Builder,
219         _path: Option<&Path>,
220         _host: Interned<String>,
221         target: Interned<String>
222     ) {
223         builder.ensure(RemoteTestServer {
224             stage: builder.top_stage,
225             target,
226         });
227     }
228
229     fn run(self, builder: &Builder) -> PathBuf {
230         builder.ensure(ToolBuild {
231             stage: self.stage,
232             target: self.target,
233             tool: "remote-test-server",
234             mode: Mode::Libstd,
235         })
236     }
237 }
238
239 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
240 pub struct Cargo {
241     pub stage: u32,
242     pub target: Interned<String>,
243 }
244
245 impl Step for Cargo {
246     type Output = PathBuf;
247     const DEFAULT: bool = true;
248     const ONLY_HOSTS: bool = true;
249
250     fn should_run(run: ShouldRun) -> ShouldRun {
251         run.path("src/tools/cargo")
252     }
253
254     fn make_run(
255         builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
256     ) {
257         if path.is_none() && !builder.build.config.extended {
258             return;
259         }
260         builder.ensure(Cargo {
261             stage: builder.top_stage,
262             target,
263         });
264     }
265
266     fn run(self, builder: &Builder) -> PathBuf {
267         builder.ensure(native::Openssl {
268             target: self.target,
269         });
270         // Cargo depends on procedural macros, which requires a full host
271         // compiler to be available, so we need to depend on that.
272         builder.ensure(compile::Rustc {
273             compiler: builder.compiler(self.stage, builder.build.build),
274             target: builder.build.build,
275         });
276         builder.ensure(ToolBuild {
277             stage: self.stage,
278             target: self.target,
279             tool: "cargo",
280             mode: Mode::Libstd,
281         })
282     }
283 }
284
285 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
286 pub struct Rls {
287     pub stage: u32,
288     pub target: Interned<String>,
289 }
290
291 impl Step for Rls {
292     type Output = PathBuf;
293     const DEFAULT: bool = true;
294     const ONLY_HOSTS: bool = true;
295
296     fn should_run(run: ShouldRun) -> ShouldRun {
297         run.path("src/tools/rls")
298     }
299
300     fn make_run(
301         builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
302     ) {
303         if path.is_none() && !builder.build.config.extended {
304             return;
305         }
306         builder.ensure(Rls {
307             stage: builder.top_stage,
308             target,
309         });
310     }
311
312     fn run(self, builder: &Builder) -> PathBuf {
313         builder.ensure(native::Openssl {
314             target: self.target,
315         });
316         // RLS depends on procedural macros, which requires a full host
317         // compiler to be available, so we need to depend on that.
318         builder.ensure(compile::Rustc {
319             compiler: builder.compiler(self.stage, builder.build.build),
320             target: builder.build.build,
321         });
322         builder.ensure(ToolBuild {
323             stage: self.stage,
324             target: self.target,
325             tool: "rls",
326             mode: Mode::Librustc,
327         })
328     }
329 }
330
331 impl<'a> Builder<'a> {
332     /// Get a `Command` which is ready to run `tool` in `stage` built for
333     /// `host`.
334     pub fn tool_cmd(&self, tool: Tool) -> Command {
335         let mut cmd = Command::new(self.tool_exe(tool));
336         let compiler = self.compiler(0, self.build.build);
337         self.prepare_tool_cmd(compiler, &mut cmd);
338         cmd
339     }
340
341     /// Prepares the `cmd` provided to be able to run the `compiler` provided.
342     ///
343     /// Notably this munges the dynamic library lookup path to point to the
344     /// right location to run `compiler`.
345     fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
346         let host = &compiler.host;
347         let mut paths: Vec<PathBuf> = vec![
348             PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
349             self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
350         ];
351
352         // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
353         // mode) and that C compiler may need some extra PATH modification. Do
354         // so here.
355         if compiler.host.contains("msvc") {
356             let curpaths = env::var_os("PATH").unwrap_or_default();
357             let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
358             for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
359                 if k != "PATH" {
360                     continue
361                 }
362                 for path in env::split_paths(v) {
363                     if !curpaths.contains(&path) {
364                         paths.push(path);
365                     }
366                 }
367             }
368         }
369         add_lib_path(paths, cmd);
370     }
371 }