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.
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.
12 use std::path::{Path, PathBuf};
13 use std::process::Command;
17 use builder::{Step, ShouldRun, Builder};
18 use util::{exe, add_lib_path};
19 use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
24 //// ========================================================================
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");
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));
48 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
49 pub struct CleanTools {
51 pub target: Interned<String>,
55 impl Step for CleanTools {
58 fn should_run(run: ShouldRun) -> ShouldRun {
62 /// Build a tool in `src/tools`
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;
72 let compiler = builder.compiler(stage, build.build);
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),
80 let out_dir = build.cargo_out(compiler, Mode::Tool, target);
81 build.clear_if_dirty(&out_dir, &stamp);
85 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
86 pub struct ToolBuild {
88 pub target: Interned<String>,
89 pub tool: &'static str,
93 impl Step for ToolBuild {
94 type Output = PathBuf;
96 fn should_run(run: ShouldRun) -> ShouldRun {
100 /// Build a tool in `src/tools`
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;
110 let compiler = builder.compiler(stage, build.build);
111 builder.ensure(CleanTools { stage, target, mode: 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")
119 let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
120 println!("Building stage{} tool {} ({})", stage, tool, target);
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"));
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");
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");
136 cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
138 let info = GitInfo::new(&dir);
139 if let Some(sha) = info.sha() {
140 cargo.env("CFG_COMMIT_HASH", sha);
142 if let Some(sha_short) = info.sha_short() {
143 cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
145 if let Some(date) = info.commit_date() {
146 cargo.env("CFG_COMMIT_DATE", date);
149 build.run(&mut cargo);
150 build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
155 ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
156 #[derive(Copy, Clone)]
163 impl<'a> Builder<'a> {
164 pub fn tool_exe(&self, tool: Tool) -> PathBuf {
169 target: self.build.build,
177 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
180 pub target: Interned<String>,
183 impl Step for $name {
184 type Output = PathBuf;
186 fn should_run(run: ShouldRun) -> ShouldRun {
192 _path: Option<&Path>,
193 _host: Interned<String>,
194 target: Interned<String>
196 builder.ensure($name {
197 stage: builder.top_stage,
202 fn run(self, builder: &Builder) -> PathBuf {
203 builder.ensure(ToolBuild {
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;
268 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
269 pub struct RemoteTestServer {
271 pub target: Interned<String>,
274 impl Step for RemoteTestServer {
275 type Output = PathBuf;
277 fn should_run(run: ShouldRun) -> ShouldRun {
278 run.path("src/tools/remote-test-server")
283 _path: Option<&Path>,
284 _host: Interned<String>,
285 target: Interned<String>
287 builder.ensure(RemoteTestServer {
288 stage: builder.top_stage,
293 fn run(self, builder: &Builder) -> PathBuf {
294 builder.ensure(ToolBuild {
297 tool: "remote-test-server",
303 // rules.build("tool-cargo", "src/tools/cargo")
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"))
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)
316 // .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
317 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
320 pub target: Interned<String>,
323 impl Step for Cargo {
324 type Output = PathBuf;
325 const DEFAULT: bool = true;
326 const ONLY_HOSTS: bool = true;
328 fn should_run(run: ShouldRun) -> ShouldRun {
329 run.path("src/tools/cargo")
333 builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
335 if path.is_none() && !builder.build.config.extended {
338 builder.ensure(Cargo {
339 stage: builder.top_stage,
344 fn run(self, builder: &Builder) -> PathBuf {
345 builder.ensure(native::Openssl {
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(compile::Rustc {
351 compiler: builder.compiler(self.stage, builder.build.build),
352 target: builder.build.build,
354 builder.ensure(ToolBuild {
363 // rules.build("tool-rls", "src/tools/rls")
365 // .default(build.config.extended)
366 // .dep(|s| s.name("librustc-tool"))
367 // .dep(|s| s.stage(0).host(s.target).name("openssl"))
369 // // rls, like cargo, uses procedural macros
370 // s.name("librustc-link")
371 // .target(&build.build)
372 // .host(&build.build)
374 // .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
376 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
379 pub target: Interned<String>,
383 type Output = PathBuf;
384 const DEFAULT: bool = true;
385 const ONLY_HOSTS: bool = true;
387 fn should_run(run: ShouldRun) -> ShouldRun {
388 run.path("src/tools/rls")
392 builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
394 if path.is_none() && !builder.build.config.extended {
398 stage: builder.top_stage,
403 fn run(self, builder: &Builder) -> PathBuf {
404 builder.ensure(native::Openssl {
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(compile::Rustc {
410 compiler: builder.compiler(self.stage, builder.build.build),
411 target: builder.build.build,
413 builder.ensure(ToolBuild {
417 mode: Mode::Librustc,
422 impl<'a> Builder<'a> {
423 /// Get a `Command` which is ready to run `tool` in `stage` built for
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);
432 /// Prepares the `cmd` provided to be able to run the `compiler` provided.
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"),
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
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() {
453 for path in env::split_paths(v) {
454 if !curpaths.contains(&path) {
460 add_lib_path(paths, cmd);