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