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, Builder};
18 use util::{exe, add_lib_path};
19 use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp, Rustc};
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 /// Build a tool in `src/tools`
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;
68 let compiler = builder.compiler(stage, build.build);
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),
76 let out_dir = build.cargo_out(compiler, Mode::Tool, target);
77 build.clear_if_dirty(&out_dir, &stamp);
81 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
82 pub struct ToolBuild {
84 pub target: Interned<String>,
85 pub tool: &'static str,
89 impl Step for ToolBuild {
90 type Output = PathBuf;
92 /// Build a tool in `src/tools`
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;
102 let compiler = builder.compiler(stage, build.build);
103 builder.ensure(CleanTools { stage, target, mode: 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")
111 let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
112 println!("Building stage{} tool {} ({})", stage, tool, target);
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"));
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");
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");
128 cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
130 let info = GitInfo::new(&dir);
131 if let Some(sha) = info.sha() {
132 cargo.env("CFG_COMMIT_HASH", sha);
134 if let Some(sha_short) = info.sha_short() {
135 cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
137 if let Some(date) = info.commit_date() {
138 cargo.env("CFG_COMMIT_DATE", date);
141 build.run(&mut cargo);
142 build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
147 ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
148 #[derive(Copy, Clone)]
155 impl<'a> Builder<'a> {
156 pub fn tool_exe(&self, tool: Tool) -> PathBuf {
161 target: self.build.build,
169 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
172 pub target: Interned<String>,
175 impl Step for $name {
176 type Output = PathBuf;
178 fn should_run(_builder: &Builder, path: &Path) -> bool {
179 path.ends_with($path)
184 _path: Option<&Path>,
185 _host: Interned<String>,
186 target: Interned<String>
188 builder.ensure($name {
189 stage: builder.top_stage,
194 fn run(self, builder: &Builder) -> PathBuf {
195 builder.ensure(ToolBuild {
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;
260 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
261 pub struct RemoteTestServer {
263 pub target: Interned<String>,
266 impl Step for RemoteTestServer {
267 type Output = PathBuf;
269 fn should_run(_builder: &Builder, path: &Path) -> bool {
270 path.ends_with("src/tools/remote-test-server")
275 _path: Option<&Path>,
276 _host: Interned<String>,
277 target: Interned<String>
279 builder.ensure(RemoteTestServer {
280 stage: builder.top_stage,
285 fn run(self, builder: &Builder) -> PathBuf {
286 builder.ensure(ToolBuild {
289 tool: "remote-test-server",
295 // rules.build("tool-cargo", "src/tools/cargo")
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"))
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)
308 // .run(move |s| compile::tool(build, s.stage, s.target, "cargo"));
309 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
312 pub target: Interned<String>,
315 impl Step for Cargo {
316 type Output = PathBuf;
317 const DEFAULT: bool = true;
318 const ONLY_HOSTS: bool = true;
320 fn should_run(_builder: &Builder, path: &Path) -> bool {
321 path.ends_with("src/tools/cargo")
325 builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
327 if path.is_none() && !builder.build.config.extended {
330 builder.ensure(Cargo {
331 stage: builder.top_stage,
336 fn run(self, builder: &Builder) -> PathBuf {
337 builder.ensure(native::Openssl {
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,
346 builder.ensure(ToolBuild {
355 // rules.build("tool-rls", "src/tools/rls")
357 // .default(build.config.extended)
358 // .dep(|s| s.name("librustc-tool"))
359 // .dep(|s| s.stage(0).host(s.target).name("openssl"))
361 // // rls, like cargo, uses procedural macros
362 // s.name("librustc-link")
363 // .target(&build.build)
364 // .host(&build.build)
366 // .run(move |s| compile::tool(build, s.stage, s.target, "rls"));
368 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
371 pub target: Interned<String>,
375 type Output = PathBuf;
376 const DEFAULT: bool = true;
377 const ONLY_HOSTS: bool = true;
379 fn should_run(_builder: &Builder, path: &Path) -> bool {
380 path.ends_with("src/tools/rls")
384 builder: &Builder, path: Option<&Path>, _host: Interned<String>, target: Interned<String>
386 if path.is_none() && !builder.build.config.extended {
389 builder.ensure(Cargo {
390 stage: builder.top_stage,
395 fn run(self, builder: &Builder) -> PathBuf {
396 builder.ensure(native::Openssl {
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,
405 builder.ensure(ToolBuild {
409 mode: Mode::Librustc,
414 impl<'a> Builder<'a> {
415 /// Get a `Command` which is ready to run `tool` in `stage` built for
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);
424 /// Prepares the `cmd` provided to be able to run the `compiler` provided.
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"),
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
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() {
445 for path in env::split_paths(v) {
446 if !curpaths.contains(&path) {
452 add_lib_path(paths, cmd);