|
16 | 16 | //! compiler. This module is also responsible for assembling the sysroot as it |
17 | 17 | //! goes along from the output of the previous stage. |
18 | 18 |
|
| 19 | +use std::cmp; |
19 | 20 | use std::collections::HashMap; |
20 | | -use std::fs; |
| 21 | +use std::fs::{self, File}; |
21 | 22 | use std::path::{Path, PathBuf}; |
22 | 23 | use std::process::Command; |
23 | 24 |
|
24 | 25 | use build_helper::output; |
| 26 | +use filetime::FileTime; |
25 | 27 |
|
26 | 28 | use util::{exe, staticlib, libdir, mtime, is_dylib, copy}; |
27 | 29 | use {Build, Compiler, Mode}; |
@@ -76,6 +78,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { |
76 | 78 | } |
77 | 79 |
|
78 | 80 | build.run(&mut cargo); |
| 81 | + update_mtime(&libstd_stamp(build, compiler, target)); |
79 | 82 | std_link(build, target, compiler, compiler.host); |
80 | 83 | } |
81 | 84 |
|
@@ -149,11 +152,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { |
149 | 152 | println!("Building stage{} test artifacts ({} -> {})", compiler.stage, |
150 | 153 | compiler.host, target); |
151 | 154 | let out_dir = build.cargo_out(compiler, Mode::Libtest, target); |
152 | | - build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target)); |
| 155 | + build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); |
153 | 156 | let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); |
154 | 157 | cargo.arg("--manifest-path") |
155 | 158 | .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); |
156 | 159 | build.run(&mut cargo); |
| 160 | + update_mtime(&libtest_stamp(build, compiler, target)); |
157 | 161 | test_link(build, target, compiler, compiler.host); |
158 | 162 | } |
159 | 163 |
|
@@ -181,7 +185,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { |
181 | 185 | compiler.stage, compiler.host, target); |
182 | 186 |
|
183 | 187 | let out_dir = build.cargo_out(compiler, Mode::Librustc, target); |
184 | | - build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target)); |
| 188 | + build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target)); |
185 | 189 |
|
186 | 190 | let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build"); |
187 | 191 | cargo.arg("--features").arg(build.rustc_features()) |
@@ -246,14 +250,14 @@ pub fn rustc_link(build: &Build, |
246 | 250 |
|
247 | 251 | /// Cargo's output path for the standard library in a given stage, compiled |
248 | 252 | /// by a particular compiler for the specified target. |
249 | | -fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { |
250 | | - build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib") |
| 253 | +fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { |
| 254 | + build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") |
251 | 255 | } |
252 | 256 |
|
253 | 257 | /// Cargo's output path for libtest in a given stage, compiled by a particular |
254 | 258 | /// compiler for the specified target. |
255 | | -fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { |
256 | | - build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib") |
| 259 | +fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { |
| 260 | + build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") |
257 | 261 | } |
258 | 262 |
|
259 | 263 | fn compiler_file(compiler: &Path, file: &str) -> PathBuf { |
@@ -366,10 +370,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) { |
366 | 370 | // Maybe when libstd is compiled it should clear out the rustc of the |
367 | 371 | // corresponding stage? |
368 | 372 | // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); |
369 | | - // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); |
| 373 | + // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); |
370 | 374 |
|
371 | 375 | let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build"); |
372 | 376 | cargo.arg("--manifest-path") |
373 | 377 | .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool))); |
374 | 378 | build.run(&mut cargo); |
375 | 379 | } |
| 380 | + |
| 381 | +/// Updates the mtime of a stamp file if necessary, only changing it if it's |
| 382 | +/// older than some other file in the same directory. |
| 383 | +/// |
| 384 | +/// We don't know what file Cargo is going to output (because there's a hash in |
| 385 | +/// the file name) but we know where it's going to put it. We use this helper to |
| 386 | +/// detect changes to that output file by looking at the modification time for |
| 387 | +/// all files in a directory and updating the stamp if any are newer. |
| 388 | +fn update_mtime(path: &Path) { |
| 389 | + let mut max = None; |
| 390 | + if let Ok(entries) = path.parent().unwrap().read_dir() { |
| 391 | + for entry in entries.map(|e| t!(e)) { |
| 392 | + if t!(entry.file_type()).is_file() { |
| 393 | + let meta = t!(entry.metadata()); |
| 394 | + let time = FileTime::from_last_modification_time(&meta); |
| 395 | + max = cmp::max(max, Some(time)); |
| 396 | + } |
| 397 | + } |
| 398 | + } |
| 399 | + |
| 400 | + if !max.is_none() && max <= Some(mtime(path)) { |
| 401 | + return |
| 402 | + } |
| 403 | + t!(File::create(path)); |
| 404 | +} |
0 commit comments