]> git.proxmox.com Git - rustc.git/blob - src/bootstrap/build/mod.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / bootstrap / build / mod.rs
1 // Copyright 2015 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::cell::RefCell;
12 use std::collections::HashMap;
13 use std::env;
14 use std::fs::{self, File};
15 use std::path::{PathBuf, Path};
16 use std::process::Command;
17
18 use build_helper::{run_silent, output};
19 use gcc;
20 use num_cpus;
21
22 use build::util::{exe, mtime, libdir, add_lib_path};
23
24 macro_rules! t {
25 ($e:expr) => (match $e {
26 Ok(e) => e,
27 Err(e) => panic!("{} failed with {}", stringify!($e), e),
28 })
29 }
30
31 mod cc;
32 mod channel;
33 mod check;
34 mod clean;
35 mod compile;
36 mod config;
37 mod dist;
38 mod doc;
39 mod flags;
40 mod native;
41 mod sanity;
42 mod step;
43 mod util;
44
45 #[cfg(windows)]
46 mod job;
47
48 #[cfg(not(windows))]
49 mod job {
50 pub unsafe fn setup() {}
51 }
52
53 pub use build::config::Config;
54 pub use build::flags::Flags;
55
56 #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
57 pub struct Compiler<'a> {
58 stage: u32,
59 host: &'a str,
60 }
61
62 pub struct Build {
63 // User-specified configuration via config.toml
64 config: Config,
65
66 // User-specified configuration via CLI flags
67 flags: Flags,
68
69 // Derived properties from the above two configurations
70 cargo: PathBuf,
71 rustc: PathBuf,
72 src: PathBuf,
73 out: PathBuf,
74 release: String,
75 unstable_features: bool,
76 ver_hash: Option<String>,
77 short_ver_hash: Option<String>,
78 ver_date: Option<String>,
79 version: String,
80 package_vers: String,
81 bootstrap_key: String,
82
83 // Runtime state filled in later on
84 cc: HashMap<String, (gcc::Tool, PathBuf)>,
85 cxx: HashMap<String, gcc::Tool>,
86 compiler_rt_built: RefCell<HashMap<String, PathBuf>>,
87 }
88
89 pub enum Mode {
90 Libstd,
91 Libtest,
92 Librustc,
93 Tool,
94 }
95
96 impl Build {
97 pub fn new(flags: Flags, config: Config) -> Build {
98 let cwd = t!(env::current_dir());
99 let src = flags.src.clone().unwrap_or(cwd.clone());
100 let out = cwd.join("build");
101
102 let stage0_root = out.join(&config.build).join("stage0/bin");
103 let rustc = match config.rustc {
104 Some(ref s) => PathBuf::from(s),
105 None => stage0_root.join(exe("rustc", &config.build)),
106 };
107 let cargo = match config.cargo {
108 Some(ref s) => PathBuf::from(s),
109 None => stage0_root.join(exe("cargo", &config.build)),
110 };
111
112 Build {
113 flags: flags,
114 config: config,
115 cargo: cargo,
116 rustc: rustc,
117 src: src,
118 out: out,
119
120 release: String::new(),
121 unstable_features: false,
122 ver_hash: None,
123 short_ver_hash: None,
124 ver_date: None,
125 version: String::new(),
126 bootstrap_key: String::new(),
127 package_vers: String::new(),
128 cc: HashMap::new(),
129 cxx: HashMap::new(),
130 compiler_rt_built: RefCell::new(HashMap::new()),
131 }
132 }
133
134 pub fn build(&mut self) {
135 use build::step::Source::*;
136
137 unsafe {
138 job::setup();
139 }
140
141 if self.flags.clean {
142 return clean::clean(self);
143 }
144
145 self.verbose("finding compilers");
146 cc::find(self);
147 self.verbose("running sanity check");
148 sanity::check(self);
149 self.verbose("collecting channel variables");
150 channel::collect(self);
151 self.verbose("updating submodules");
152 self.update_submodules();
153
154 for target in step::all(self) {
155 let doc_out = self.out.join(&target.target).join("doc");
156 match target.src {
157 Llvm { _dummy } => {
158 native::llvm(self, target.target);
159 }
160 CompilerRt { _dummy } => {
161 native::compiler_rt(self, target.target);
162 }
163 Libstd { compiler } => {
164 compile::std(self, target.target, &compiler);
165 }
166 Libtest { compiler } => {
167 compile::test(self, target.target, &compiler);
168 }
169 Librustc { compiler } => {
170 compile::rustc(self, target.target, &compiler);
171 }
172 LibstdLink { compiler, host } => {
173 compile::std_link(self, target.target, &compiler, host);
174 }
175 LibtestLink { compiler, host } => {
176 compile::test_link(self, target.target, &compiler, host);
177 }
178 LibrustcLink { compiler, host } => {
179 compile::rustc_link(self, target.target, &compiler, host);
180 }
181 Rustc { stage: 0 } => {
182 // nothing to do...
183 }
184 Rustc { stage } => {
185 compile::assemble_rustc(self, stage, target.target);
186 }
187 ToolLinkchecker { stage } => {
188 compile::tool(self, stage, target.target, "linkchecker");
189 }
190 ToolRustbook { stage } => {
191 compile::tool(self, stage, target.target, "rustbook");
192 }
193 ToolErrorIndex { stage } => {
194 compile::tool(self, stage, target.target,
195 "error_index_generator");
196 }
197 ToolCargoTest { stage } => {
198 compile::tool(self, stage, target.target, "cargotest");
199 }
200 DocBook { stage } => {
201 doc::rustbook(self, stage, target.target, "book", &doc_out);
202 }
203 DocNomicon { stage } => {
204 doc::rustbook(self, stage, target.target, "nomicon",
205 &doc_out);
206 }
207 DocStyle { stage } => {
208 doc::rustbook(self, stage, target.target, "style",
209 &doc_out);
210 }
211 DocStandalone { stage } => {
212 doc::standalone(self, stage, target.target, &doc_out);
213 }
214 DocStd { stage } => {
215 doc::std(self, stage, target.target, &doc_out);
216 }
217 DocTest { stage } => {
218 doc::test(self, stage, target.target, &doc_out);
219 }
220 DocRustc { stage } => {
221 doc::rustc(self, stage, target.target, &doc_out);
222 }
223 DocErrorIndex { stage } => {
224 doc::error_index(self, stage, target.target, &doc_out);
225 }
226
227 CheckLinkcheck { stage } => {
228 check::linkcheck(self, stage, target.target);
229 }
230 CheckCargoTest { stage } => {
231 check::cargotest(self, stage, target.target);
232 }
233
234 DistDocs { stage } => dist::docs(self, stage, target.target),
235 DistMingw { _dummy } => dist::mingw(self, target.target),
236 DistRustc { stage } => dist::rustc(self, stage, target.target),
237 DistStd { compiler } => dist::std(self, &compiler, target.target),
238
239 Dist { .. } |
240 Doc { .. } | // pseudo-steps
241 Check { .. } => {}
242 }
243 }
244 }
245
246 fn update_submodules(&self) {
247 if !self.config.submodules {
248 return
249 }
250 if fs::metadata(self.src.join(".git")).is_err() {
251 return
252 }
253 let git_submodule = || {
254 let mut cmd = Command::new("git");
255 cmd.current_dir(&self.src).arg("submodule");
256 return cmd
257 };
258 let out = output(git_submodule().arg("status"));
259 if !out.lines().any(|l| l.starts_with("+") || l.starts_with("-")) {
260 return
261 }
262
263 self.run(git_submodule().arg("sync"));
264 self.run(git_submodule().arg("init"));
265 self.run(git_submodule().arg("update"));
266 self.run(git_submodule().arg("update").arg("--recursive"));
267 self.run(git_submodule().arg("status").arg("--recursive"));
268 self.run(git_submodule().arg("foreach").arg("--recursive")
269 .arg("git").arg("clean").arg("-fdx"));
270 self.run(git_submodule().arg("foreach").arg("--recursive")
271 .arg("git").arg("checkout").arg("."));
272 }
273
274 /// Clear out `dir` if our build has been flagged as dirty, and also set
275 /// ourselves as dirty if `file` changes when `f` is executed.
276 fn clear_if_dirty(&self, dir: &Path, input: &Path) {
277 let stamp = dir.join(".stamp");
278 if mtime(&stamp) < mtime(input) {
279 self.verbose(&format!("Dirty - {}", dir.display()));
280 let _ = fs::remove_dir_all(dir);
281 }
282 t!(fs::create_dir_all(dir));
283 t!(File::create(stamp));
284 }
285
286 /// Prepares an invocation of `cargo` to be run.
287 ///
288 /// This will create a `Command` that represents a pending execution of
289 /// Cargo for the specified stage, whether or not the standard library is
290 /// being built, and using the specified compiler targeting `target`.
291 fn cargo(&self,
292 compiler: &Compiler,
293 mode: Mode,
294 target: &str,
295 cmd: &str) -> Command {
296 let mut cargo = Command::new(&self.cargo);
297 let out_dir = self.stage_out(compiler, mode);
298 cargo.env("CARGO_TARGET_DIR", out_dir)
299 .arg(cmd)
300 .arg("-j").arg(self.jobs().to_string())
301 .arg("--target").arg(target);
302
303 // Customize the compiler we're running. Specify the compiler to cargo
304 // as our shim and then pass it some various options used to configure
305 // how the actual compiler itself is called.
306 cargo.env("RUSTC", self.out.join("bootstrap/debug/rustc"))
307 .env("RUSTC_REAL", self.compiler_path(compiler))
308 .env("RUSTC_STAGE", compiler.stage.to_string())
309 .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string())
310 .env("RUSTC_CODEGEN_UNITS",
311 self.config.rust_codegen_units.to_string())
312 .env("RUSTC_DEBUG_ASSERTIONS",
313 self.config.rust_debug_assertions.to_string())
314 .env("RUSTC_SNAPSHOT", &self.rustc)
315 .env("RUSTC_SYSROOT", self.sysroot(compiler))
316 .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir())
317 .env("RUSTC_RPATH", self.config.rust_rpath.to_string())
318 .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
319 .env("RUSTDOC_REAL", self.rustdoc(compiler))
320 .env("RUSTC_FLAGS", self.rustc_flags(target).join(" "));
321
322 // Specify some various options for build scripts used throughout
323 // the build.
324 //
325 // FIXME: the guard against msvc shouldn't need to be here
326 if !target.contains("msvc") {
327 cargo.env(format!("CC_{}", target), self.cc(target))
328 .env(format!("AR_{}", target), self.ar(target))
329 .env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
330 }
331
332 // If we're building for OSX, inform the compiler and the linker that
333 // we want to build a compiler runnable on 10.7
334 if target.contains("apple-darwin") {
335 cargo.env("MACOSX_DEPLOYMENT_TARGET", "10.7");
336 }
337
338 // Environment variables *required* needed throughout the build
339 //
340 // FIXME: should update code to not require this env vars
341 cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
342
343 if self.config.verbose || self.flags.verbose {
344 cargo.arg("-v");
345 }
346 if self.config.rust_optimize {
347 cargo.arg("--release");
348 }
349 self.add_rustc_lib_path(compiler, &mut cargo);
350 return cargo
351 }
352
353 /// Get a path to the compiler specified.
354 fn compiler_path(&self, compiler: &Compiler) -> PathBuf {
355 if compiler.is_snapshot(self) {
356 self.rustc.clone()
357 } else {
358 self.sysroot(compiler).join("bin").join(exe("rustc", compiler.host))
359 }
360 }
361
362 /// Get the specified tool built by the specified compiler
363 fn tool(&self, compiler: &Compiler, tool: &str) -> PathBuf {
364 self.cargo_out(compiler, Mode::Tool, compiler.host)
365 .join(exe(tool, compiler.host))
366 }
367
368 /// Get the `rustdoc` executable next to the specified compiler
369 fn rustdoc(&self, compiler: &Compiler) -> PathBuf {
370 let mut rustdoc = self.compiler_path(compiler);
371 rustdoc.pop();
372 rustdoc.push(exe("rustdoc", compiler.host));
373 return rustdoc
374 }
375
376 /// Get a `Command` which is ready to run `tool` in `stage` built for
377 /// `host`.
378 fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
379 let mut cmd = Command::new(self.tool(&compiler, tool));
380 let host = compiler.host;
381 let paths = vec![
382 self.cargo_out(compiler, Mode::Libstd, host).join("deps"),
383 self.cargo_out(compiler, Mode::Libtest, host).join("deps"),
384 self.cargo_out(compiler, Mode::Librustc, host).join("deps"),
385 ];
386 add_lib_path(paths, &mut cmd);
387 return cmd
388 }
389
390 /// Get the space-separated set of activated features for the standard
391 /// library.
392 fn std_features(&self) -> String {
393 let mut features = String::new();
394 if self.config.debug_jemalloc {
395 features.push_str(" debug-jemalloc");
396 }
397 if self.config.use_jemalloc {
398 features.push_str(" jemalloc");
399 }
400 return features
401 }
402
403 /// Get the space-separated set of activated features for the compiler.
404 fn rustc_features(&self) -> String {
405 let mut features = String::new();
406 if self.config.use_jemalloc {
407 features.push_str(" jemalloc");
408 }
409 return features
410 }
411
412 /// Component directory that Cargo will produce output into (e.g.
413 /// release/debug)
414 fn cargo_dir(&self) -> &'static str {
415 if self.config.rust_optimize {"release"} else {"debug"}
416 }
417
418 fn sysroot(&self, compiler: &Compiler) -> PathBuf {
419 if compiler.stage == 0 {
420 self.out.join(compiler.host).join("stage0-sysroot")
421 } else {
422 self.out.join(compiler.host).join(format!("stage{}", compiler.stage))
423 }
424 }
425
426 fn sysroot_libdir(&self, compiler: &Compiler, target: &str) -> PathBuf {
427 self.sysroot(compiler).join("lib").join("rustlib")
428 .join(target).join("lib")
429 }
430
431 /// Returns the root directory for all output generated in a particular
432 /// stage when running with a particular host compiler.
433 ///
434 /// The mode indicates what the root directory is for.
435 fn stage_out(&self, compiler: &Compiler, mode: Mode) -> PathBuf {
436 let suffix = match mode {
437 Mode::Libstd => "-std",
438 Mode::Libtest => "-test",
439 Mode::Tool | Mode::Librustc => "-rustc",
440 };
441 self.out.join(compiler.host)
442 .join(format!("stage{}{}", compiler.stage, suffix))
443 }
444
445 /// Returns the root output directory for all Cargo output in a given stage,
446 /// running a particular comipler, wehther or not we're building the
447 /// standard library, and targeting the specified architecture.
448 fn cargo_out(&self,
449 compiler: &Compiler,
450 mode: Mode,
451 target: &str) -> PathBuf {
452 self.stage_out(compiler, mode).join(target).join(self.cargo_dir())
453 }
454
455 /// Root output directory for LLVM compiled for `target`
456 fn llvm_out(&self, target: &str) -> PathBuf {
457 self.out.join(target).join("llvm")
458 }
459
460 /// Root output directory for compiler-rt compiled for `target`
461 fn compiler_rt_out(&self, target: &str) -> PathBuf {
462 self.out.join(target).join("compiler-rt")
463 }
464
465 fn add_rustc_lib_path(&self, compiler: &Compiler, cmd: &mut Command) {
466 // Windows doesn't need dylib path munging because the dlls for the
467 // compiler live next to the compiler and the system will find them
468 // automatically.
469 if cfg!(windows) { return }
470
471 add_lib_path(vec![self.rustc_libdir(compiler)], cmd);
472 }
473
474 fn rustc_libdir(&self, compiler: &Compiler) -> PathBuf {
475 if compiler.is_snapshot(self) {
476 self.rustc_snapshot_libdir()
477 } else {
478 self.sysroot(compiler).join(libdir(compiler.host))
479 }
480 }
481
482 fn rustc_snapshot_libdir(&self) -> PathBuf {
483 self.rustc.parent().unwrap().parent().unwrap()
484 .join(libdir(&self.config.build))
485 }
486
487 fn run(&self, cmd: &mut Command) {
488 self.verbose(&format!("running: {:?}", cmd));
489 run_silent(cmd)
490 }
491
492 fn verbose(&self, msg: &str) {
493 if self.flags.verbose || self.config.verbose {
494 println!("{}", msg);
495 }
496 }
497
498 fn jobs(&self) -> u32 {
499 self.flags.jobs.unwrap_or(num_cpus::get() as u32)
500 }
501
502 fn cc(&self, target: &str) -> &Path {
503 self.cc[target].0.path()
504 }
505
506 fn cflags(&self, target: &str) -> Vec<String> {
507 let mut base = self.cc[target].0.args().iter()
508 .map(|s| s.to_string_lossy().into_owned())
509 .collect::<Vec<_>>();
510
511 // If we're compiling on OSX then we add a few unconditional flags
512 // indicating that we want libc++ (more filled out than libstdc++) and
513 // we want to compile for 10.7. This way we can ensure that
514 // LLVM/jemalloc/etc are all properly compiled.
515 if target.contains("apple-darwin") {
516 base.push("-stdlib=libc++".into());
517 base.push("-mmacosx-version-min=10.7".into());
518 }
519 return base
520 }
521
522 fn ar(&self, target: &str) -> &Path {
523 &self.cc[target].1
524 }
525
526 fn cxx(&self, target: &str) -> &Path {
527 self.cxx[target].path()
528 }
529
530 fn rustc_flags(&self, target: &str) -> Vec<String> {
531 let mut base = Vec::new();
532 if target != self.config.build && !target.contains("msvc") {
533 base.push(format!("-Clinker={}", self.cc(target).display()));
534 }
535 return base
536 }
537 }
538
539 impl<'a> Compiler<'a> {
540 fn new(stage: u32, host: &'a str) -> Compiler<'a> {
541 Compiler { stage: stage, host: host }
542 }
543
544 fn is_snapshot(&self, build: &Build) -> bool {
545 self.stage == 0 && self.host == build.config.build
546 }
547 }