]> git.lizzy.rs Git - rust.git/blobdiff - src/bootstrap/compile.rs
Auto merge of #36441 - alexcrichton:rustbuild-target, r=brson
[rust.git] / src / bootstrap / compile.rs
index 618fa3805b37fc0af6e2a3a576791f1c12d667b4..9de438cfa7d504756e1211fdcf2c8733c9ce57d2 100644 (file)
 //! compiler. This module is also responsible for assembling the sysroot as it
 //! goes along from the output of the previous stage.
 
+use std::cmp;
 use std::collections::HashMap;
-use std::fs;
+use std::fs::{self, File};
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use build_helper::output;
+use filetime::FileTime;
 
 use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
 use {Build, Compiler, Mode};
@@ -35,13 +37,23 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
     println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
              compiler.host, target);
 
-    // Move compiler-rt into place as it'll be required by the compiler when
-    // building the standard library to link the dylib of libstd
     let libdir = build.sysroot_libdir(compiler, target);
     let _ = fs::remove_dir_all(&libdir);
     t!(fs::create_dir_all(&libdir));
-    copy(&build.compiler_rt_built.borrow()[target],
-         &libdir.join(staticlib("compiler-rt", target)));
+    // FIXME(stage0) remove this `if` after the next snapshot
+    // The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
+    // never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
+    // `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
+    // an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
+    // it to the final binary because now `libcore.rlib` also contains the symbols that
+    // `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
+    // symbols are used instead of `libcompiler-rt.a`'s.
+    if compiler.stage == 0 {
+        let rtlib = &staticlib("compiler-rt", target);
+        let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
+            .join(target).join("lib").join(rtlib);
+        copy(&src, &libdir.join(rtlib));
+    }
 
     // Some platforms have startup objects that may be required to produce the
     // libstd dynamic library, for example.
@@ -66,6 +78,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
     }
 
     build.run(&mut cargo);
+    update_mtime(&libstd_stamp(build, compiler, target));
     std_link(build, target, compiler, compiler.host);
 }
 
@@ -83,12 +96,10 @@ pub fn std_link(build: &Build,
 
     // If we're linking one compiler host's output into another, then we weren't
     // called from the `std` method above. In that case we clean out what's
-    // already there and then also link compiler-rt into place.
+    // already there.
     if host != compiler.host {
         let _ = fs::remove_dir_all(&libdir);
         t!(fs::create_dir_all(&libdir));
-        copy(&build.compiler_rt_built.borrow()[target],
-             &libdir.join(staticlib("compiler-rt", target)));
     }
     add_to_sysroot(&out_dir, &libdir);
 
@@ -143,11 +154,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
     println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
              compiler.host, target);
     let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
-    build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target));
+    build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
     let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build");
     cargo.arg("--manifest-path")
          .arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
     build.run(&mut cargo);
+    update_mtime(&libtest_stamp(build, compiler, target));
     test_link(build, target, compiler, compiler.host);
 }
 
@@ -175,7 +187,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
              compiler.stage, compiler.host, target);
 
     let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
-    build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target));
+    build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target));
 
     let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build");
     cargo.arg("--features").arg(build.rustc_features())
@@ -240,14 +252,14 @@ pub fn rustc_link(build: &Build,
 
 /// Cargo's output path for the standard library in a given stage, compiled
 /// by a particular compiler for the specified target.
-fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
-    build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib")
+fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
+    build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
 }
 
 /// Cargo's output path for libtest in a given stage, compiled by a particular
 /// compiler for the specified target.
-fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
-    build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib")
+fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf {
+    build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
 }
 
 fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
@@ -360,10 +372,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
     //        Maybe when libstd is compiled it should clear out the rustc of the
     //        corresponding stage?
     // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target);
-    // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target));
+    // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target));
 
     let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build");
     cargo.arg("--manifest-path")
          .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool)));
     build.run(&mut cargo);
 }
+
+/// Updates the mtime of a stamp file if necessary, only changing it if it's
+/// older than some other file in the same directory.
+///
+/// We don't know what file Cargo is going to output (because there's a hash in
+/// the file name) but we know where it's going to put it. We use this helper to
+/// detect changes to that output file by looking at the modification time for
+/// all files in a directory and updating the stamp if any are newer.
+fn update_mtime(path: &Path) {
+    let mut max = None;
+    if let Ok(entries) = path.parent().unwrap().read_dir() {
+        for entry in entries.map(|e| t!(e)) {
+            if t!(entry.file_type()).is_file() {
+                let meta = t!(entry.metadata());
+                let time = FileTime::from_last_modification_time(&meta);
+                max = cmp::max(max, Some(time));
+            }
+        }
+    }
+
+    if !max.is_none() && max <= Some(mtime(path)) {
+        return
+    }
+    t!(File::create(path));
+}