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.
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.
11 use std
::cell
::RefCell
;
12 use std
::collections
::HashMap
;
14 use std
::fs
::{self, File}
;
15 use std
::path
::{PathBuf, Path}
;
16 use std
::process
::Command
;
18 use build_helper
::{run_silent, output}
;
22 use build
::util
::{exe, mtime, libdir, add_lib_path}
;
25 ($e
:expr
) => (match $e
{
27 Err(e
) => panic
!("{} failed with {}", stringify
!($e
), e
),
50 pub unsafe fn setup() {}
53 pub use build
::config
::Config
;
54 pub use build
::flags
::Flags
;
56 #[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
57 pub struct Compiler
<'a
> {
63 // User-specified configuration via config.toml
66 // User-specified configuration via CLI flags
69 // Derived properties from the above two configurations
75 unstable_features
: bool
,
76 ver_hash
: Option
<String
>,
77 short_ver_hash
: Option
<String
>,
78 ver_date
: Option
<String
>,
81 bootstrap_key
: String
,
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
>>,
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");
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
)),
107 let cargo
= match config
.cargo
{
108 Some(ref s
) => PathBuf
::from(s
),
109 None
=> stage0_root
.join(exe("cargo", &config
.build
)),
120 release
: String
::new(),
121 unstable_features
: false,
123 short_ver_hash
: None
,
125 version
: String
::new(),
126 bootstrap_key
: String
::new(),
127 package_vers
: String
::new(),
130 compiler_rt_built
: RefCell
::new(HashMap
::new()),
134 pub fn build(&mut self) {
135 use build
::step
::Source
::*;
141 if self.flags
.clean
{
142 return clean
::clean(self);
145 self.verbose("finding compilers");
147 self.verbose("running sanity check");
149 self.verbose("collecting channel variables");
150 channel
::collect(self);
151 self.verbose("updating submodules");
152 self.update_submodules();
154 for target
in step
::all(self) {
155 let doc_out
= self.out
.join(&target
.target
).join("doc");
158 native
::llvm(self, target
.target
);
160 CompilerRt { _dummy }
=> {
161 native
::compiler_rt(self, target
.target
);
163 Libstd { compiler }
=> {
164 compile
::std(self, target
.target
, &compiler
);
166 Libtest { compiler }
=> {
167 compile
::test(self, target
.target
, &compiler
);
169 Librustc { compiler }
=> {
170 compile
::rustc(self, target
.target
, &compiler
);
172 LibstdLink { compiler, host }
=> {
173 compile
::std_link(self, target
.target
, &compiler
, host
);
175 LibtestLink { compiler, host }
=> {
176 compile
::test_link(self, target
.target
, &compiler
, host
);
178 LibrustcLink { compiler, host }
=> {
179 compile
::rustc_link(self, target
.target
, &compiler
, host
);
181 Rustc { stage: 0 }
=> {
185 compile
::assemble_rustc(self, stage
, target
.target
);
187 ToolLinkchecker { stage }
=> {
188 compile
::tool(self, stage
, target
.target
, "linkchecker");
190 ToolRustbook { stage }
=> {
191 compile
::tool(self, stage
, target
.target
, "rustbook");
193 ToolErrorIndex { stage }
=> {
194 compile
::tool(self, stage
, target
.target
,
195 "error_index_generator");
197 ToolCargoTest { stage }
=> {
198 compile
::tool(self, stage
, target
.target
, "cargotest");
200 DocBook { stage }
=> {
201 doc
::rustbook(self, stage
, target
.target
, "book", &doc_out
);
203 DocNomicon { stage }
=> {
204 doc
::rustbook(self, stage
, target
.target
, "nomicon",
207 DocStyle { stage }
=> {
208 doc
::rustbook(self, stage
, target
.target
, "style",
211 DocStandalone { stage }
=> {
212 doc
::standalone(self, stage
, target
.target
, &doc_out
);
214 DocStd { stage }
=> {
215 doc
::std(self, stage
, target
.target
, &doc_out
);
217 DocTest { stage }
=> {
218 doc
::test(self, stage
, target
.target
, &doc_out
);
220 DocRustc { stage }
=> {
221 doc
::rustc(self, stage
, target
.target
, &doc_out
);
223 DocErrorIndex { stage }
=> {
224 doc
::error_index(self, stage
, target
.target
, &doc_out
);
227 CheckLinkcheck { stage }
=> {
228 check
::linkcheck(self, stage
, target
.target
);
230 CheckCargoTest { stage }
=> {
231 check
::cargotest(self, stage
, target
.target
);
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
),
240 Doc { .. }
| // pseudo-steps
246 fn update_submodules(&self) {
247 if !self.config
.submodules
{
250 if fs
::metadata(self.src
.join(".git")).is_err() {
253 let git_submodule
= || {
254 let mut cmd
= Command
::new("git");
255 cmd
.current_dir(&self.src
).arg("submodule");
258 let out
= output(git_submodule().arg("status"));
259 if !out
.lines().any(|l
| l
.starts_with("+") || l
.starts_with("-")) {
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("."));
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
);
282 t
!(fs
::create_dir_all(dir
));
283 t
!(File
::create(stamp
));
286 /// Prepares an invocation of `cargo` to be run.
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`.
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
)
300 .arg("-j").arg(self.jobs().to_string())
301 .arg("--target").arg(target
);
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(" "));
322 // Specify some various options for build scripts used throughout
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(" "));
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");
338 // Environment variables *required* needed throughout the build
340 // FIXME: should update code to not require this env vars
341 cargo
.env("CFG_COMPILER_HOST_TRIPLE", target
);
343 if self.config
.verbose
|| self.flags
.verbose
{
346 if self.config
.rust_optimize
{
347 cargo
.arg("--release");
349 self.add_rustc_lib_path(compiler
, &mut cargo
);
353 /// Get a path to the compiler specified.
354 fn compiler_path(&self, compiler
: &Compiler
) -> PathBuf
{
355 if compiler
.is_snapshot(self) {
358 self.sysroot(compiler
).join("bin").join(exe("rustc", compiler
.host
))
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
))
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
);
372 rustdoc
.push(exe("rustdoc", compiler
.host
));
376 /// Get a `Command` which is ready to run `tool` in `stage` built for
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
;
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"),
386 add_lib_path(paths
, &mut cmd
);
390 /// Get the space-separated set of activated features for the standard
392 fn std_features(&self) -> String
{
393 let mut features
= String
::new();
394 if self.config
.debug_jemalloc
{
395 features
.push_str(" debug-jemalloc");
397 if self.config
.use_jemalloc
{
398 features
.push_str(" jemalloc");
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");
412 /// Component directory that Cargo will produce output into (e.g.
414 fn cargo_dir(&self) -> &'
static str {
415 if self.config
.rust_optimize {"release"}
else {"debug"}
418 fn sysroot(&self, compiler
: &Compiler
) -> PathBuf
{
419 if compiler
.stage
== 0 {
420 self.out
.join(compiler
.host
).join("stage0-sysroot")
422 self.out
.join(compiler
.host
).join(format
!("stage{}", compiler
.stage
))
426 fn sysroot_libdir(&self, compiler
: &Compiler
, target
: &str) -> PathBuf
{
427 self.sysroot(compiler
).join("lib").join("rustlib")
428 .join(target
).join("lib")
431 /// Returns the root directory for all output generated in a particular
432 /// stage when running with a particular host compiler.
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",
441 self.out
.join(compiler
.host
)
442 .join(format
!("stage{}{}", compiler
.stage
, suffix
))
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.
451 target
: &str) -> PathBuf
{
452 self.stage_out(compiler
, mode
).join(target
).join(self.cargo_dir())
455 /// Root output directory for LLVM compiled for `target`
456 fn llvm_out(&self, target
: &str) -> PathBuf
{
457 self.out
.join(target
).join("llvm")
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")
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
469 if cfg
!(windows
) { return }
471 add_lib_path(vec
![self.rustc_libdir(compiler
)], cmd
);
474 fn rustc_libdir(&self, compiler
: &Compiler
) -> PathBuf
{
475 if compiler
.is_snapshot(self) {
476 self.rustc_snapshot_libdir()
478 self.sysroot(compiler
).join(libdir(compiler
.host
))
482 fn rustc_snapshot_libdir(&self) -> PathBuf
{
483 self.rustc
.parent().unwrap().parent().unwrap()
484 .join(libdir(&self.config
.build
))
487 fn run(&self, cmd
: &mut Command
) {
488 self.verbose(&format
!("running: {:?}", cmd
));
492 fn verbose(&self, msg
: &str) {
493 if self.flags
.verbose
|| self.config
.verbose
{
498 fn jobs(&self) -> u32 {
499 self.flags
.jobs
.unwrap_or(num_cpus
::get() as u32)
502 fn cc(&self, target
: &str) -> &Path
{
503 self.cc
[target
].0.path()
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
<_
>>();
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());
522 fn ar(&self, target
: &str) -> &Path
{
526 fn cxx(&self, target
: &str) -> &Path
{
527 self.cxx
[target
].path()
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()));
539 impl<'a
> Compiler
<'a
> {
540 fn new(stage
: u32, host
: &'a
str) -> Compiler
<'a
> {
541 Compiler { stage: stage, host: host }
544 fn is_snapshot(&self, build
: &Build
) -> bool
{
545 self.stage
== 0 && self.host
== build
.config
.build