compile.rs 39.9 KB
Newer Older
A
Alex Crichton 已提交
1 2 3 4 5 6 7 8 9 10
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12 13 14 15 16 17 18
//! Implementation of compiling various phases of the compiler and standard
//! library.
//!
//! This module contains some of the real meat in the rustbuild build system
//! which is where Cargo is used to compiler the standard library, libtest, and
//! compiler. This module is also responsible for assembling the sysroot as it
//! goes along from the output of the previous stage.

19
use std::env;
20
use std::fs::{self, File};
21 22
use std::io::BufReader;
use std::io::prelude::*;
A
Alex Crichton 已提交
23
use std::path::{Path, PathBuf};
24 25
use std::process::{Command, Stdio};
use std::str;
M
Mark Simulacrum 已提交
26
use std::cmp::min;
A
Alex Crichton 已提交
27

28
use build_helper::{output, mtime, up_to_date};
29
use filetime::FileTime;
M
Mark Simulacrum 已提交
30
use serde_json;
A
Alex Crichton 已提交
31

32
use util::{exe, libdir, is_dylib, copy, read_stamp_file, CiEnv};
33
use {Build, Compiler, Mode};
34
use native;
35
use tool;
36

37
use cache::{INTERNER, Interned};
38
use builder::{Step, RunConfig, ShouldRun, Builder};
A
Alex Crichton 已提交
39

40 41 42 43
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Std {
    pub target: Interned<String>,
    pub compiler: Compiler,
44
}
P
Peter Wagenet 已提交
45

46
impl Step for Std {
47
    type Output = ();
48 49
    const DEFAULT: bool = true;

50 51
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/libstd").krate("std")
52 53
    }

54 55 56 57
    fn make_run(run: RunConfig) {
        run.builder.ensure(Std {
            compiler: run.builder.compiler(run.builder.top_stage, run.host),
            target: run.target,
58
        });
59
    }
60 61 62 63 64 65 66 67 68 69

    /// Build the standard library.
    ///
    /// This will build the standard library for a particular stage of the build
    /// using the `compiler` targeting the `target` architecture. The artifacts
    /// created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder) {
        let build = builder.build;
        let target = self.target;
        let compiler = self.compiler;
70 71 72 73

        builder.ensure(StartupObjects { compiler, target });

        if build.force_use_stage1(compiler, target) {
74
            let from = builder.compiler(1, build.build);
75 76
            builder.ensure(Std {
                compiler: from,
77
                target,
78 79
            });
            println!("Uplifting stage1 std ({} -> {})", from.host, target);
80 81 82 83 84 85 86 87

            // Even if we're not building std this stage, the new sysroot must
            // still contain the musl startup objects.
            if target.contains("musl") && !target.contains("mips") {
                let libdir = builder.sysroot_libdir(compiler, target);
                copy_musl_third_party_objects(build, target, &libdir);
            }

88 89 90
            builder.ensure(StdLink {
                compiler: from,
                target_compiler: compiler,
91
                target,
92 93 94
            });
            return;
        }
95 96 97

        let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
        println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
98
                &compiler.host, target);
99

100 101 102 103 104
        if target.contains("musl") && !target.contains("mips") {
            let libdir = builder.sysroot_libdir(compiler, target);
            copy_musl_third_party_objects(build, target, &libdir);
        }

105
        let out_dir = build.stage_out(compiler, Mode::Libstd);
106
        build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
107
        let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
A
Alex Crichton 已提交
108
        std_cargo(build, &compiler, target, &mut cargo);
109
        run_cargo(build,
110
                  &mut cargo,
111 112
                  &libstd_stamp(build, compiler, target),
                  false);
113 114

        builder.ensure(StdLink {
115
            compiler: builder.compiler(compiler.stage, build.build),
116
            target_compiler: compiler,
117
            target,
118
        });
119
    }
120 121
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135
/// Copies the crt(1,i,n).o startup objects
///
/// Since musl supports fully static linking, we can cross link for it even
/// with a glibc-targeting toolchain, given we have the appropriate startup
/// files. As those shipped with glibc won't work, copy the ones provided by
/// musl so we have them on linux-gnu hosts.
fn copy_musl_third_party_objects(build: &Build,
                                 target: Interned<String>,
                                 into: &Path) {
    for &obj in &["crt1.o", "crti.o", "crtn.o"] {
        copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
    }
}

A
Alex Crichton 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
/// Configure cargo to compile the standard library, adding appropriate env vars
/// and such.
pub fn std_cargo(build: &Build,
                 compiler: &Compiler,
                 target: Interned<String>,
                 cargo: &mut Command) {
    let mut features = build.std_features();

    if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
        cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
    }

    // When doing a local rebuild we tell cargo that we're stage1 rather than
    // stage0. This works fine if the local rust and being-built rust have the
    // same view of what the default allocator is, but fails otherwise. Since
    // we don't have a way to express an allocator preference yet, work
    // around the issue in the case of a local rebuild with jemalloc disabled.
    if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
        features.push_str(" force_alloc_system");
    }

    if compiler.stage != 0 && build.config.sanitizers {
        // This variable is used by the sanitizer runtime crates, e.g.
        // rustc_lsan, to build the sanitizer runtime from C code
        // When this variable is missing, those crates won't compile the C code,
        // so we don't set this variable during stage0 where llvm-config is
        // missing
        // We also only build the runtimes when --enable-sanitizers (or its
        // config.toml equivalent) is used
        cargo.env("LLVM_CONFIG", build.llvm_config(target));
    }

    cargo.arg("--features").arg(features)
        .arg("--manifest-path")
        .arg(build.src.join("src/libstd/Cargo.toml"));

    if let Some(target) = build.config.target_config.get(&target) {
        if let Some(ref jemalloc) = target.jemalloc {
            cargo.env("JEMALLOC_OVERRIDE", jemalloc);
        }
    }
    if target.contains("musl") {
        if let Some(p) = build.musl_root(target) {
            cargo.env("MUSL_ROOT", p);
        }
    }
}
M
Mark Simulacrum 已提交
183

184 185 186 187 188
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct StdLink {
    pub compiler: Compiler,
    pub target_compiler: Compiler,
    pub target: Interned<String>,
189 190
}

191
impl Step for StdLink {
192 193
    type Output = ();

194 195
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
196 197
    }

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
    /// Link all libstd rlibs/dylibs into the sysroot location.
    ///
    /// Links those artifacts generated by `compiler` to a the `stage` compiler's
    /// sysroot for the specified `host` and `target`.
    ///
    /// Note that this assumes that `compiler` has already generated the libstd
    /// libraries for `target`, and this method will find them in the relevant
    /// output directory.
    fn run(self, builder: &Builder) {
        let build = builder.build;
        let compiler = self.compiler;
        let target_compiler = self.target_compiler;
        let target = self.target;
        println!("Copying stage{} std from stage{} ({} -> {} / {})",
                target_compiler.stage,
                compiler.stage,
214
                &compiler.host,
215 216
                target_compiler.host,
                target);
217
        let libdir = builder.sysroot_libdir(target_compiler, target);
218 219 220 221 222 223 224 225
        add_to_sysroot(&libdir, &libstd_stamp(build, compiler, target));

        if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
            // The sanitizers are only built in stage1 or above, so the dylibs will
            // be missing in stage0 and causes panic. See the `std()` function above
            // for reason why the sanitizers are not built in stage0.
            copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir);
        }
226 227 228

        builder.ensure(tool::CleanTools {
            compiler: target_compiler,
229
            target,
230 231
            mode: Mode::Libstd,
        });
232
    }
233 234
}

235 236 237 238 239 240 241 242 243 244 245 246
fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) {
    for &sanitizer in &["asan", "tsan"] {
        let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
        let mut src_path = native_dir.join(sanitizer);
        src_path.push("build");
        src_path.push("lib");
        src_path.push("darwin");
        src_path.push(&filename);
        copy(&src_path, &into.join(filename));
    }
}

247 248 249 250
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct StartupObjects {
    pub compiler: Compiler,
    pub target: Interned<String>,
251
}
252

253
impl Step for StartupObjects {
254 255
    type Output = ();

256 257
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/rtstartup")
258 259
    }

260 261 262 263
    fn make_run(run: RunConfig) {
        run.builder.ensure(StartupObjects {
            compiler: run.builder.compiler(run.builder.top_stage, run.host),
            target: run.target,
264
        });
265 266
    }

267 268 269 270 271 272 273 274
    /// Build and prepare startup objects like rsbegin.o and rsend.o
    ///
    /// These are primarily used on Windows right now for linking executables/dlls.
    /// They don't require any library support as they're just plain old object
    /// files, so we just use the nightly snapshot compiler to always build them (as
    /// no other compilers are guaranteed to be available).
    fn run(self, builder: &Builder) {
        let build = builder.build;
275
        let for_compiler = self.compiler;
276 277 278
        let target = self.target;
        if !target.contains("pc-windows-gnu") {
            return
279 280
        }

281 282
        let src_dir = &build.src.join("src/rtstartup");
        let dst_dir = &build.native_dir(target).join("rtstartup");
283
        let sysroot_dir = &builder.sysroot_libdir(for_compiler, target);
284 285 286 287 288 289
        t!(fs::create_dir_all(dst_dir));

        for file in &["rsbegin", "rsend"] {
            let src_file = &src_dir.join(file.to_string() + ".rs");
            let dst_file = &dst_dir.join(file.to_string() + ".o");
            if !up_to_date(src_file, dst_file) {
M
Mark Simulacrum 已提交
290
                let mut cmd = Command::new(&build.initial_rustc);
291
                build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
M
Mark Simulacrum 已提交
292
                            .arg("--cfg").arg("stage0")
293 294
                            .arg("--target").arg(target)
                            .arg("--emit=obj")
M
Mark Simulacrum 已提交
295
                            .arg("-o").arg(dst_file)
296 297
                            .arg(src_file));
            }
A
Alex Crichton 已提交
298

299 300 301 302
            copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
        }

        for obj in ["crt2.o", "dllcrt2.o"].iter() {
303 304 305 306 307
            let src = compiler_file(build,
                                    build.cc(target),
                                    target,
                                    obj);
            copy(&src, &sysroot_dir.join(obj));
308
        }
A
Alex Crichton 已提交
309 310 311
    }
}

312 313 314 315
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Test {
    pub compiler: Compiler,
    pub target: Interned<String>,
316 317
}

318
impl Step for Test {
319
    type Output = ();
320 321
    const DEFAULT: bool = true;

322 323
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/libtest").krate("test")
324 325
    }

326 327 328 329
    fn make_run(run: RunConfig) {
        run.builder.ensure(Test {
            compiler: run.builder.compiler(run.builder.top_stage, run.host),
            target: run.target,
330
        });
331
    }
332 333 334 335 336 337 338 339 340 341

    /// Build libtest.
    ///
    /// This will build libtest and supporting libraries for a particular stage of
    /// the build using the `compiler` targeting the `target` architecture. The
    /// artifacts created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder) {
        let build = builder.build;
        let target = self.target;
        let compiler = self.compiler;
342 343 344 345 346

        builder.ensure(Std { compiler, target });

        if build.force_use_stage1(compiler, target) {
            builder.ensure(Test {
347
                compiler: builder.compiler(1, build.build),
348
                target,
349 350 351
            });
            println!("Uplifting stage1 test ({} -> {})", &build.build, target);
            builder.ensure(TestLink {
352
                compiler: builder.compiler(1, build.build),
353
                target_compiler: compiler,
354
                target,
355 356 357 358
            });
            return;
        }

359 360
        let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
        println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
361
                &compiler.host, target);
362
        let out_dir = build.stage_out(compiler, Mode::Libtest);
363
        build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
364
        let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build");
A
Alex Crichton 已提交
365
        test_cargo(build, &compiler, target, &mut cargo);
366
        run_cargo(build,
367
                  &mut cargo,
368 369
                  &libtest_stamp(build, compiler, target),
                  false);
370 371

        builder.ensure(TestLink {
372
            compiler: builder.compiler(compiler.stage, build.build),
373
            target_compiler: compiler,
374
            target,
375
        });
P
Peter Wagenet 已提交
376
    }
377 378
}

A
Alex Crichton 已提交
379 380 381 382 383 384 385 386 387 388 389 390
/// Same as `std_cargo`, but for libtest
pub fn test_cargo(build: &Build,
                  _compiler: &Compiler,
                  _target: Interned<String>,
                  cargo: &mut Command) {
    if let Some(target) = env::var_os("MACOSX_STD_DEPLOYMENT_TARGET") {
        cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
    }
    cargo.arg("--manifest-path")
        .arg(build.src.join("src/libtest/Cargo.toml"));
}

391 392 393 394 395
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TestLink {
    pub compiler: Compiler,
    pub target_compiler: Compiler,
    pub target: Interned<String>,
396 397
}

398
impl Step for TestLink {
399 400
    type Output = ();

401 402
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
403 404
    }

405 406 407 408 409 410 411 412 413
    /// Same as `std_link`, only for libtest
    fn run(self, builder: &Builder) {
        let build = builder.build;
        let compiler = self.compiler;
        let target_compiler = self.target_compiler;
        let target = self.target;
        println!("Copying stage{} test from stage{} ({} -> {} / {})",
                target_compiler.stage,
                compiler.stage,
414
                &compiler.host,
415 416
                target_compiler.host,
                target);
417
        add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
418
                    &libtest_stamp(build, compiler, target));
419 420
        builder.ensure(tool::CleanTools {
            compiler: target_compiler,
421
            target,
422 423
            mode: Mode::Libtest,
        });
424
    }
425
}
A
Alex Crichton 已提交
426

427 428 429 430
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Rustc {
    pub compiler: Compiler,
    pub target: Interned<String>,
431 432
}

433
impl Step for Rustc {
434
    type Output = ();
435 436 437
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

438 439
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/librustc").krate("rustc-main")
440 441
    }

442 443 444 445
    fn make_run(run: RunConfig) {
        run.builder.ensure(Rustc {
            compiler: run.builder.compiler(run.builder.top_stage, run.host),
            target: run.target,
446
        });
447
    }
448 449 450 451 452 453 454 455 456 457

    /// Build the compiler.
    ///
    /// This will build the compiler for a particular stage of the build using
    /// the `compiler` targeting the `target` architecture. The artifacts
    /// created will also be linked into the sysroot directory.
    fn run(self, builder: &Builder) {
        let build = builder.build;
        let compiler = self.compiler;
        let target = self.target;
458 459 460 461 462

        builder.ensure(Test { compiler, target });

        if build.force_use_stage1(compiler, target) {
            builder.ensure(Rustc {
463
                compiler: builder.compiler(1, build.build),
464
                target,
465 466 467
            });
            println!("Uplifting stage1 rustc ({} -> {})", &build.build, target);
            builder.ensure(RustcLink {
468
                compiler: builder.compiler(1, build.build),
469 470 471 472 473 474 475 476
                target_compiler: compiler,
                target,
            });
            return;
        }

        // Ensure that build scripts have a std to link against.
        builder.ensure(Std {
477 478
            compiler: builder.compiler(self.compiler.stage, build.build),
            target: build.build,
479 480
        });

481 482
        let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
        println!("Building stage{} compiler artifacts ({} -> {})",
483
                 compiler.stage, &compiler.host, target);
484

485 486 487
        let stage_out = builder.stage_out(compiler, Mode::Librustc);
        build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
        build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
488

489
        let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
490
        rustc_cargo(build, &mut cargo);
491 492
        run_cargo(build,
                  &mut cargo,
493 494
                  &librustc_stamp(build, compiler, target),
                  false);
495 496

        builder.ensure(RustcLink {
497
            compiler: builder.compiler(compiler.stage, build.build),
498 499 500
            target_compiler: compiler,
            target,
        });
A
Alex Crichton 已提交
501
    }
502 503
}

504
pub fn rustc_cargo(build: &Build, cargo: &mut Command) {
A
Alex Crichton 已提交
505 506 507
    cargo.arg("--features").arg(build.rustc_features())
         .arg("--manifest-path")
         .arg(build.src.join("src/rustc/Cargo.toml"));
508 509
    rustc_cargo_env(build, cargo);
}
A
Alex Crichton 已提交
510

511
fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
A
Alex Crichton 已提交
512 513 514 515 516 517 518
    // Set some configuration variables picked up by build scripts and
    // the compiler alike
    cargo.env("CFG_RELEASE", build.rust_release())
         .env("CFG_RELEASE_CHANNEL", &build.config.channel)
         .env("CFG_VERSION", build.rust_version())
         .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default());

O
O01eg 已提交
519
    let libdir_relative =
520
        build.config.libdir.clone().unwrap_or(PathBuf::from("lib"));
O
O01eg 已提交
521
    cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
A
Alex Crichton 已提交
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541

    // If we're not building a compiler with debugging information then remove
    // these two env vars which would be set otherwise.
    if build.config.rust_debuginfo_only_std {
        cargo.env_remove("RUSTC_DEBUGINFO");
        cargo.env_remove("RUSTC_DEBUGINFO_LINES");
    }

    if let Some(ref ver_date) = build.rust_info.commit_date() {
        cargo.env("CFG_VER_DATE", ver_date);
    }
    if let Some(ref ver_hash) = build.rust_info.sha() {
        cargo.env("CFG_VER_HASH", ver_hash);
    }
    if !build.unstable_features() {
        cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
    }
    if let Some(ref s) = build.config.rustc_default_linker {
        cargo.env("CFG_DEFAULT_LINKER", s);
    }
542 543 544
    if build.config.rustc_parallel_queries {
        cargo.env("RUSTC_PARALLEL_QUERIES", "1");
    }
A
Alex Crichton 已提交
545 546
}

547 548 549 550 551
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
struct RustcLink {
    pub compiler: Compiler,
    pub target_compiler: Compiler,
    pub target: Interned<String>,
552 553
}

554
impl Step for RustcLink {
555 556
    type Output = ();

557 558
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
559 560
    }

561 562 563 564 565 566 567 568 569
    /// Same as `std_link`, only for librustc
    fn run(self, builder: &Builder) {
        let build = builder.build;
        let compiler = self.compiler;
        let target_compiler = self.target_compiler;
        let target = self.target;
        println!("Copying stage{} rustc from stage{} ({} -> {} / {})",
                 target_compiler.stage,
                 compiler.stage,
570
                 &compiler.host,
571 572
                 target_compiler.host,
                 target);
573
        add_to_sysroot(&builder.sysroot_libdir(target_compiler, target),
574
                       &librustc_stamp(build, compiler, target));
575 576
        builder.ensure(tool::CleanTools {
            compiler: target_compiler,
577
            target,
578 579
            mode: Mode::Librustc,
        });
580
    }
A
Alex Crichton 已提交
581 582
}

583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct RustcTrans {
    pub compiler: Compiler,
    pub target: Interned<String>,
}

impl Step for RustcTrans {
    type Output = ();
    const ONLY_HOSTS: bool = true;
    const DEFAULT: bool = true;

    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/librustc_trans").krate("rustc_trans")
    }

    fn make_run(run: RunConfig) {
        run.builder.ensure(RustcTrans {
            compiler: run.builder.compiler(run.builder.top_stage, run.host),
            target: run.target,
        });
    }

    fn run(self, builder: &Builder) {
        let build = builder.build;
        let compiler = self.compiler;
        let target = self.target;

        builder.ensure(Rustc { compiler, target });

        // Build LLVM for our target. This will implicitly build the host LLVM
        // if necessary.
        builder.ensure(native::Llvm { target });

        if build.force_use_stage1(compiler, target) {
            builder.ensure(RustcTrans {
                compiler: builder.compiler(1, build.build),
                target,
            });
            return;
        }

        let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
        println!("Building stage{} trans artifacts ({} -> {})",
                 compiler.stage, &compiler.host, target);

        let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
        cargo.arg("--manifest-path")
            .arg(build.src.join("src/librustc_trans/Cargo.toml"))
            .arg("--features").arg(build.rustc_features());
        rustc_cargo_env(build, &mut cargo);

        // Pass down configuration from the LLVM build into the build of
        // librustc_llvm and librustc_trans.
        if build.is_rust_llvm(target) {
            cargo.env("LLVM_RUSTLLVM", "1");
        }
        cargo.env("LLVM_CONFIG", build.llvm_config(target));
        let target_config = build.config.target_config.get(&target);
        if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
            cargo.env("CFG_LLVM_ROOT", s);
        }
        // Building with a static libstdc++ is only supported on linux right now,
        // not for MSVC or macOS
        if build.config.llvm_static_stdcpp &&
           !target.contains("freebsd") &&
           !target.contains("windows") &&
           !target.contains("apple") {
            let file = compiler_file(build,
                                     build.cxx(target).unwrap(),
                                     target,
                                     "libstdc++.a");
            cargo.env("LLVM_STATIC_STDCPP", file);
        }
        if build.config.llvm_link_shared {
            cargo.env("LLVM_LINK_SHARED", "1");
        }

        run_cargo(build,
                  &mut cargo,
                  &librustc_trans_stamp(build, compiler, target),
                  false);
    }
}

/// Creates the `codegen-backends` folder for a compiler that's about to be
/// assembled as a complete compiler.
///
/// This will take the codegen artifacts produced by `compiler` and link them
/// into an appropriate location for `target_compiler` to be a functional
/// compiler.
fn copy_codegen_backends_to_sysroot(builder: &Builder,
                                    compiler: Compiler,
                                    target_compiler: Compiler) {
    let build = builder.build;
    let target = target_compiler.host;

    // Note that this step is different than all the other `*Link` steps in
    // that it's not assembling a bunch of libraries but rather is primarily
    // moving the codegen backend into place. The codegen backend of rustc is
    // not linked into the main compiler by default but is rather dynamically
    // selected at runtime for inclusion.
    //
    // Here we're looking for the output dylib of the `RustcTrans` step and
    // we're copying that into the `codegen-backends` folder.
    let libdir = builder.sysroot_libdir(target_compiler, target);
    let dst = libdir.join("codegen-backends");
    t!(fs::create_dir_all(&dst));
    let stamp = librustc_trans_stamp(build, compiler, target);

    let mut copied = None;
    for file in read_stamp_file(&stamp) {
        let filename = match file.file_name().and_then(|s| s.to_str()) {
            Some(s) => s,
            None => continue,
        };
        if !is_dylib(filename) || !filename.contains("rustc_trans-") {
            continue
        }
        match copied {
            None => copied = Some(file.clone()),
            Some(ref s) => {
                panic!("copied two codegen backends:\n{}\n{}",
                       s.display(),
                       file.display());
            }
        }
        copy(&file, &dst.join(filename));
    }
    assert!(copied.is_some(), "failed to find a codegen backend to copy");
}

A
Alex Crichton 已提交
714 715
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
716
pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
717
    build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
A
Alex Crichton 已提交
718 719
}

720 721
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
722
pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
723
    build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
724 725
}

726 727
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
728
pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
729 730 731
    build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
}

732 733 734 735 736 737 738 739 740 741 742 743 744 745
pub fn librustc_trans_stamp(build: &Build,
                            compiler: Compiler,
                            target: Interned<String>) -> PathBuf {
    build.cargo_out(compiler, Mode::Librustc, target).join(".librustc_trans.stamp")
}

fn compiler_file(build: &Build,
                 compiler: &Path,
                 target: Interned<String>,
                 file: &str) -> PathBuf {
    let mut cmd = Command::new(compiler);
    cmd.args(build.cflags(target));
    cmd.arg(format!("-print-file-name={}", file));
    let out = output(&mut cmd);
746
    PathBuf::from(out.trim())
A
Alex Crichton 已提交
747 748
}

749 750 751
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Sysroot {
    pub compiler: Compiler,
752 753
}

754 755
impl Step for Sysroot {
    type Output = Interned<PathBuf>;
756

757 758
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.never()
759 760
    }

761 762 763 764 765 766
    /// Returns the sysroot for the `compiler` specified that *this build system
    /// generates*.
    ///
    /// That is, the sysroot for the stage0 compiler is not what the compiler
    /// thinks it is by default, but it's the same as the default for stages
    /// 1-3.
767
    fn run(self, builder: &Builder) -> Interned<PathBuf> {
768 769
        let build = builder.build;
        let compiler = self.compiler;
770
        let sysroot = if compiler.stage == 0 {
771
            build.out.join(&compiler.host).join("stage0-sysroot")
772
        } else {
773
            build.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
774
        };
775 776
        let _ = fs::remove_dir_all(&sysroot);
        t!(fs::create_dir_all(&sysroot));
777
        INTERNER.intern_path(sysroot)
778
    }
779 780
}

781 782
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Assemble {
783 784 785 786
    /// The compiler which we will produce in this step. Assemble itself will
    /// take care of ensuring that the necessary prerequisites to do so exist,
    /// that is, this target can be a stage2 compiler and Assemble will build
    /// previous stages for you.
787
    pub target_compiler: Compiler,
788
}
789

790 791
impl Step for Assemble {
    type Output = Compiler;
792

793 794
    fn should_run(run: ShouldRun) -> ShouldRun {
        run.path("src/rustc")
795 796
    }

797 798 799 800 801
    /// Prepare a new compiler from the artifacts in `stage`
    ///
    /// This will assemble a compiler in `build/$host/stage$stage`. The compiler
    /// must have been previously produced by the `stage - 1` build.build
    /// compiler.
802
    fn run(self, builder: &Builder) -> Compiler {
803
        let build = builder.build;
804
        let target_compiler = self.target_compiler;
805

806 807 808 809 810 811
        if target_compiler.stage == 0 {
            assert_eq!(build.build, target_compiler.host,
                "Cannot obtain compiler for non-native build triple at stage 0");
            // The stage 0 compiler for the build triple is always pre-built.
            return target_compiler;
        }
812

813
        // Get the compiler that we'll use to bootstrap ourselves.
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
        //
        // Note that this is where the recursive nature of the bootstrap
        // happens, as this will request the previous stage's compiler on
        // downwards to stage 0.
        //
        // Also note that we're building a compiler for the host platform. We
        // only assume that we can run `build` artifacts, which means that to
        // produce some other architecture compiler we need to start from
        // `build` to get there.
        //
        // FIXME: Perhaps we should download those libraries?
        //        It would make builds faster...
        //
        // FIXME: It may be faster if we build just a stage 1 compiler and then
        //        use that to bootstrap this compiler forward.
        let build_compiler =
            builder.compiler(target_compiler.stage - 1, build.build);
831 832 833 834 835 836

        // Build the libraries for this compiler to link to (i.e., the libraries
        // it uses at runtime). NOTE: Crates the target compiler compiles don't
        // link to these. (FIXME: Is that correct? It seems to be correct most
        // of the time but I think we do link to these for stage2/bin compilers
        // when not performing a full bootstrap).
M
Mark Simulacrum 已提交
837
        if builder.build.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) {
M
Mark Simulacrum 已提交
838 839
            builder.verbose("skipping compilation of compiler due to --keep-stage");
            let compiler = build_compiler;
M
Mark Simulacrum 已提交
840
            for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) {
M
Mark Simulacrum 已提交
841
                let target_compiler = builder.compiler(stage, target_compiler.host);
M
Mark Simulacrum 已提交
842 843 844 845
                let target = target_compiler.host;
                builder.ensure(StdLink { compiler, target_compiler, target });
                builder.ensure(TestLink { compiler, target_compiler, target });
                builder.ensure(RustcLink { compiler, target_compiler, target });
M
Mark Simulacrum 已提交
846 847
            }
        } else {
848 849 850 851 852 853 854 855
            builder.ensure(Rustc {
                compiler: build_compiler,
                target: target_compiler.host,
            });
            builder.ensure(RustcTrans {
                compiler: build_compiler,
                target: target_compiler.host,
            });
M
Mark Simulacrum 已提交
856
        }
857 858 859 860

        let stage = target_compiler.stage;
        let host = target_compiler.host;
        println!("Assembling stage{} compiler ({})", stage, host);
861 862

        // Link in all dylibs to the libdir
863
        let sysroot = builder.sysroot(target_compiler);
864
        let sysroot_libdir = sysroot.join(libdir(&*host));
865
        t!(fs::create_dir_all(&sysroot_libdir));
866
        let src_libdir = builder.sysroot_libdir(build_compiler, host);
867 868 869 870 871
        for f in t!(fs::read_dir(&src_libdir)).map(|f| t!(f)) {
            let filename = f.file_name().into_string().unwrap();
            if is_dylib(&filename) {
                copy(&f.path(), &sysroot_libdir.join(&filename));
            }
A
Alex Crichton 已提交
872 873
        }

874 875 876
        copy_codegen_backends_to_sysroot(builder,
                                         build_compiler,
                                         target_compiler);
877 878

        // Link the compiler binary itself into place
879
        let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
880
        let rustc = out_dir.join(exe("rustc", &*host));
881 882
        let bindir = sysroot.join("bin");
        t!(fs::create_dir_all(&bindir));
883
        let compiler = builder.rustc(target_compiler);
884 885 886
        let _ = fs::remove_file(&compiler);
        copy(&rustc, &compiler);

887
        target_compiler
A
Alex Crichton 已提交
888 889 890 891 892
    }
}

/// Link some files into a rustc sysroot.
///
893 894
/// For a particular stage this will link the file listed in `stamp` into the
/// `sysroot_dst` provided.
895
pub fn add_to_sysroot(sysroot_dst: &Path, stamp: &Path) {
896
    t!(fs::create_dir_all(&sysroot_dst));
897
    for path in read_stamp_file(stamp) {
898
        copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
A
Alex Crichton 已提交
899 900
    }
}
901

M
Mark Simulacrum 已提交
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
// Avoiding a dependency on winapi to keep compile times down
#[cfg(unix)]
fn stderr_isatty() -> bool {
    use libc;
    unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
}
#[cfg(windows)]
fn stderr_isatty() -> bool {
    type DWORD = u32;
    type BOOL = i32;
    type HANDLE = *mut u8;
    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
    extern "system" {
        fn GetStdHandle(which: DWORD) -> HANDLE;
        fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: *mut DWORD) -> BOOL;
    }
    unsafe {
        let handle = GetStdHandle(STD_ERROR_HANDLE);
        let mut out = 0;
        GetConsoleMode(handle, &mut out) != 0
    }
}

925
pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) {
926 927 928 929
    // Instruct Cargo to give us json messages on stdout, critically leaving
    // stderr as piped so we can get those pretty colors.
    cargo.arg("--message-format").arg("json")
         .stdout(Stdio::piped());
M
Mark Simulacrum 已提交
930

931
    if stderr_isatty() && build.ci_env == CiEnv::None {
M
Mark Simulacrum 已提交
932 933 934 935 936 937
        // since we pass message-format=json to cargo, we need to tell the rustc
        // wrapper to give us colored output if necessary. This is because we
        // only want Cargo's JSON output, not rustcs.
        cargo.env("RUSTC_COLOR", "1");
    }

938 939 940 941
    build.verbose(&format!("running: {:?}", cargo));
    let mut child = match cargo.spawn() {
        Ok(child) => child,
        Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
942 943
    };

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
    // `target_root_dir` looks like $dir/$target/release
    let target_root_dir = stamp.parent().unwrap();
    // `target_deps_dir` looks like $dir/$target/release/deps
    let target_deps_dir = target_root_dir.join("deps");
    // `host_root_dir` looks like $dir/release
    let host_root_dir = target_root_dir.parent().unwrap() // chop off `release`
                                       .parent().unwrap() // chop off `$target`
                                       .join(target_root_dir.file_name().unwrap());

    // Spawn Cargo slurping up its JSON output. We'll start building up the
    // `deps` array of all files it generated along with a `toplevel` array of
    // files we need to probe for later.
    let mut deps = Vec::new();
    let mut toplevel = Vec::new();
    let stdout = BufReader::new(child.stdout.take().unwrap());
    for line in stdout.lines() {
        let line = t!(line);
M
Mark Simulacrum 已提交
961 962
        let json: serde_json::Value = if line.starts_with("{") {
            t!(serde_json::from_str(&line))
963 964 965 966 967
        } else {
            // If this was informational, just print it out and continue
            println!("{}", line);
            continue
        };
M
Mark Simulacrum 已提交
968
        if json["reason"].as_str() != Some("compiler-artifact") {
969 970 971
            continue
        }
        for filename in json["filenames"].as_array().unwrap() {
M
Mark Simulacrum 已提交
972
            let filename = filename.as_str().unwrap();
973 974 975
            // Skip files like executables
            if !filename.ends_with(".rlib") &&
               !filename.ends_with(".lib") &&
976 977
               !is_dylib(&filename) &&
               !(is_check && filename.ends_with(".rmeta")) {
978 979 980 981 982 983 984 985
                continue
            }

            let filename = Path::new(filename);

            // If this was an output file in the "host dir" we don't actually
            // worry about it, it's not relevant for us.
            if filename.starts_with(&host_root_dir) {
M
Mark Simulacrum 已提交
986 987
                continue;
            }
988 989 990

            // If this was output in the `deps` dir then this is a precise file
            // name (hash included) so we start tracking it.
M
Mark Simulacrum 已提交
991
            if filename.starts_with(&target_deps_dir) {
992
                deps.push(filename.to_path_buf());
M
Mark Simulacrum 已提交
993 994
                continue;
            }
995 996 997 998 999

            // Otherwise this was a "top level artifact" which right now doesn't
            // have a hash in the name, but there's a version of this file in
            // the `deps` folder which *does* have a hash in the name. That's
            // the one we'll want to we'll probe for it later.
1000 1001 1002 1003 1004 1005
            //
            // We do not use `Path::file_stem` or `Path::extension` here,
            // because some generated files may have multiple extensions e.g.
            // `std-<hash>.dll.lib` on Windows. The aforementioned methods only
            // split the file name by the last extension (`.lib`) while we need
            // to split by all extensions (`.dll.lib`).
1006
            let expected_len = t!(filename.metadata()).len();
1007 1008 1009 1010 1011
            let filename = filename.file_name().unwrap().to_str().unwrap();
            let mut parts = filename.splitn(2, '.');
            let file_stem = parts.next().unwrap().to_owned();
            let extension = parts.next().unwrap().to_owned();

1012
            toplevel.push((file_stem, extension, expected_len));
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
        }
    }

    // Make sure Cargo actually succeeded after we read all of its stdout.
    let status = t!(child.wait());
    if !status.success() {
        panic!("command did not execute successfully: {:?}\n\
                expected success, got: {}",
               cargo,
               status);
    }

    // Ok now we need to actually find all the files listed in `toplevel`. We've
    // got a list of prefix/extensions and we basically just need to find the
    // most recent file in the `deps` folder corresponding to each one.
    let contents = t!(target_deps_dir.read_dir())
        .map(|e| t!(e))
        .map(|e| (e.path(), e.file_name().into_string().unwrap(), t!(e.metadata())))
        .collect::<Vec<_>>();
1032 1033
    for (prefix, extension, expected_len) in toplevel {
        let candidates = contents.iter().filter(|&&(_, ref filename, ref meta)| {
1034 1035
            filename.starts_with(&prefix[..]) &&
                filename[prefix.len()..].starts_with("-") &&
1036 1037
                filename.ends_with(&extension[..]) &&
                meta.len() == expected_len
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
        });
        let max = candidates.max_by_key(|&&(_, _, ref metadata)| {
            FileTime::from_last_modification_time(metadata)
        });
        let path_to_add = match max {
            Some(triple) => triple.0.to_str().unwrap(),
            None => panic!("no output generated for {:?} {:?}", prefix, extension),
        };
        if is_dylib(path_to_add) {
            let candidate = format!("{}.lib", path_to_add);
            let candidate = PathBuf::from(candidate);
            if candidate.exists() {
                deps.push(candidate);
            }
        }
        deps.push(path_to_add.into());
    }

    // Now we want to update the contents of the stamp file, if necessary. First
    // we read off the previous contents along with its mtime. If our new
    // contents (the list of files to copy) is different or if any dep's mtime
    // is newer then we rewrite the stamp file.
    deps.sort();
    let mut stamp_contents = Vec::new();
    if let Ok(mut f) = File::open(stamp) {
        t!(f.read_to_end(&mut stamp_contents));
    }
    let stamp_mtime = mtime(&stamp);
    let mut new_contents = Vec::new();
    let mut max = None;
    let mut max_path = None;
    for dep in deps {
        let mtime = mtime(&dep);
        if Some(mtime) > max {
            max = Some(mtime);
            max_path = Some(dep.clone());
        }
        new_contents.extend(dep.to_str().unwrap().as_bytes());
        new_contents.extend(b"\0");
    }
    let max = max.unwrap();
    let max_path = max_path.unwrap();
    if stamp_contents == new_contents && max <= stamp_mtime {
1081 1082
        build.verbose(&format!("not updating {:?}; contents equal and {} <= {}",
                stamp, max, stamp_mtime));
1083 1084 1085 1086 1087 1088
        return
    }
    if max > stamp_mtime {
        build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
    } else {
        build.verbose(&format!("updating {:?} as deps changed", stamp));
1089
    }
1090
    t!(t!(File::create(stamp)).write_all(&new_contents));
1091
}