diff --git a/Cargo.lock b/Cargo.lock index d7d221ee66f2a..2ee9a872d3ee2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,7 +214,6 @@ dependencies = [ name = "bootstrap" version = "0.0.0" dependencies = [ - "build_helper", "cc", "cmake", "filetime", @@ -256,10 +255,6 @@ dependencies = [ "toml", ] -[[package]] -name = "build_helper" -version = "0.1.0" - [[package]] name = "bump-stage0" version = "0.1.0" @@ -3891,7 +3886,6 @@ dependencies = [ name = "rustc_llvm" version = "0.0.0" dependencies = [ - "build_helper", "cc", "libc", ] diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index d8dfcc84e68da..34556df3c6d79 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -11,5 +11,4 @@ emscripten = [] libc = "0.2.73" [build-dependencies] -build_helper = { path = "../../src/build_helper" } cc = "1.0.69" diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 3b6808d693f21..ac758c15cca78 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -1,8 +1,8 @@ use std::env; +use std::ffi::{OsStr, OsString}; +use std::fmt::Display; use std::path::{Path, PathBuf}; -use std::process::Command; - -use build_helper::{output, tracked_env_var_os}; +use std::process::{Command, Stdio}; fn detect_llvm_link() -> (&'static str, &'static str) { // Force the link mode we want, preferring static by default, but @@ -14,13 +14,74 @@ fn detect_llvm_link() -> (&'static str, &'static str) { } } +// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may +// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM +// shared library, which means that when our freshly built llvm-config goes to load it's +// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first +// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from +// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't +// perfect -- we might actually want to see something from Cargo's added library paths -- but +// for now it works. +fn restore_library_path() { + let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR"); + if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") { + env::set_var(&key, &env); + } else { + env::remove_var(&key); + } +} + +/// Reads an environment variable and adds it to dependencies. +/// Supposed to be used for all variables except those set for build scripts by cargo +/// +fn tracked_env_var_os + Display>(key: K) -> Option { + println!("cargo:rerun-if-env-changed={}", key); + env::var_os(key) +} + +fn rerun_if_changed_anything_in_dir(dir: &Path) { + let mut stack = dir + .read_dir() + .unwrap() + .map(|e| e.unwrap()) + .filter(|e| &*e.file_name() != ".git") + .collect::>(); + while let Some(entry) = stack.pop() { + let path = entry.path(); + if entry.file_type().unwrap().is_dir() { + stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); + } else { + println!("cargo:rerun-if-changed={}", path.display()); + } + } +} + +#[track_caller] +fn output(cmd: &mut Command) -> String { + let output = match cmd.stderr(Stdio::inherit()).output() { + Ok(status) => status, + Err(e) => { + println!("\n\nfailed to execute command: {:?}\nerror: {}\n\n", cmd, e); + std::process::exit(1); + } + }; + if !output.status.success() { + panic!( + "command did not execute successfully: {:?}\n\ + expected success, got: {}", + cmd, output.status + ); + } + String::from_utf8(output.stdout).unwrap() +} + fn main() { if tracked_env_var_os("RUST_CHECK").is_some() { // If we're just running `check`, there's no need for LLVM to be built. return; } - build_helper::restore_library_path(); + restore_library_path(); let target = env::var("TARGET").expect("TARGET was not set"); let llvm_config = @@ -160,7 +221,7 @@ fn main() { cfg.debug(false); } - build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); + rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); cfg.file("llvm-wrapper/PassWrapper.cpp") .file("llvm-wrapper/RustWrapper.cpp") .file("llvm-wrapper/ArchiveWrapper.cpp") diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 02efc08cc791f..fe9d6a727ed1e 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -34,7 +34,6 @@ path = "bin/llvm-config-wrapper.rs" test = false [dependencies] -build_helper = { path = "../build_helper" } cmake = "0.1.38" filetime = "0.2" getopts = "0.2.19" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 00aebc21f581a..fc55c8626d99f 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -11,8 +11,6 @@ use std::path::{Component, Path, PathBuf}; use std::process::Command; use std::time::{Duration, Instant}; -use build_helper::{output, t}; - use crate::cache::{Cache, Interned, INTERNER}; use crate::check; use crate::compile; @@ -25,7 +23,7 @@ use crate::native; use crate::run; use crate::test; use crate::tool::{self, SourceType}; -use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir}; +use crate::util::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t}; use crate::EXTRA_CHECK_CFGS; use crate::{Build, CLang, DocTests, GitRepo, Mode}; diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 8c47f625d732b..7ce446876118a 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -26,9 +26,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::{env, iter}; -use build_helper::output; - use crate::config::{Target, TargetSelection}; +use crate::util::output; use crate::{Build, CLang, GitRepo}; // The `cc` crate doesn't provide a way to obtain a path to the detected archiver, diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 6478578c3c402..1932a0017ee25 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -8,8 +8,7 @@ use std::path::Path; use std::process::Command; -use build_helper::output; - +use crate::util::output; use crate::Build; pub enum GitInfo { diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 3b73dc1c7df74..069f3d6acf158 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -9,8 +9,7 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::Path; -use build_helper::t; - +use crate::util::t; use crate::Build; pub fn clean(build: &Build, all: bool) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 9971778034601..9cfd9f92aa7cd 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -16,7 +16,6 @@ use std::path::{Path, PathBuf}; use std::process::{exit, Command, Stdio}; use std::str; -use build_helper::{output, t, up_to_date}; use serde::Deserialize; use crate::builder::Cargo; @@ -26,7 +25,7 @@ use crate::config::{LlvmLibunwind, TargetSelection}; use crate::dist; use crate::native; use crate::tool::SourceType; -use crate::util::{exe, is_debug_info, is_dylib, symlink_dir}; +use crate::util::{exe, is_debug_info, is_dylib, output, symlink_dir, t, up_to_date}; use crate::LLVM_TOOLS; use crate::{CLang, Compiler, DependencyType, GitRepo, Mode}; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 997e811e214df..b17b94f289395 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -17,8 +17,7 @@ use crate::cache::{Interned, INTERNER}; use crate::channel::GitInfo; pub use crate::flags::Subcommand; use crate::flags::{Color, Flags}; -use crate::util::exe; -use build_helper::t; +use crate::util::{exe, t}; use serde::Deserialize; macro_rules! check_ci_llvm { diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 8693e85e4742f..5f92cc2ca6fad 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -14,15 +14,13 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::{output, t}; - use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; use crate::config::TargetSelection; use crate::tarball::{GeneratedTarball, OverlayKind, Tarball}; use crate::tool::{self, Tool}; -use crate::util::{exe, is_dylib, timeit}; +use crate::util::{exe, is_dylib, output, t, timeit}; use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { @@ -635,14 +633,6 @@ impl Step for RustcDev { &[], &tarball.image_dir().join("lib/rustlib/rustc-src/rust"), ); - // This particular crate is used as a build dependency of the above. - copy_src_dirs( - builder, - &builder.src, - &["src/build_helper"], - &[], - &tarball.image_dir().join("lib/rustlib/rustc-src/rust"), - ); for file in src_files { tarball.add_file(builder.src.join(file), "lib/rustlib/rustc-src/rust", 0o644); } diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 23b5ddcd47a0e..be55871b56a28 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -12,15 +12,13 @@ use std::fs; use std::io; use std::path::{Path, PathBuf}; -use crate::Mode; -use build_helper::{t, up_to_date}; - use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; use crate::config::{Config, TargetSelection}; use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; -use crate::util::symlink_dir; +use crate::util::{symlink_dir, t, up_to_date}; +use crate::Mode; macro_rules! submodule_helper { ($path:expr, submodule) => { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 74528f2752f5f..e34b40a93ff47 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -7,12 +7,12 @@ use std::env; use std::path::PathBuf; use std::process; -use build_helper::t; use getopts::Options; use crate::builder::Builder; use crate::config::{Config, TargetSelection}; use crate::setup::Profile; +use crate::util::t; use crate::{Build, DocTests}; pub enum Color { diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 530cc829320d1..10b846e6db208 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -1,7 +1,7 @@ //! Runs rustfmt on the repository. +use crate::util::{output, t}; use crate::Build; -use build_helper::{output, t}; use ignore::WalkBuilder; use std::collections::VecDeque; use std::path::{Path, PathBuf}; diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 06acf1a9a0083..27b9196d9868e 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -8,7 +8,7 @@ use std::fs; use std::path::{Component, PathBuf}; use std::process::Command; -use build_helper::t; +use crate::util::t; use crate::dist::{self, sanitize_sh}; use crate::tarball::GeneratedTarball; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 4089a63f881d1..ccc8516a89abf 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -116,12 +116,13 @@ use std::os::unix::fs::symlink as symlink_file; #[cfg(windows)] use std::os::windows::fs::symlink_file; -use build_helper::{mtime, output, run, run_suppressed, t, try_run, try_run_suppressed}; use filetime::FileTime; use crate::builder::Kind; use crate::config::{LlvmLibunwind, TargetSelection}; -use crate::util::{exe, libdir, CiEnv}; +use crate::util::{ + exe, libdir, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed, CiEnv, +}; mod builder; mod cache; @@ -1301,13 +1302,10 @@ impl Build { } // Don't include optional deps if their features are not // enabled. Ideally this would be computed from `cargo - // metadata --features …`, but that is somewhat slow. Just - // skip `build_helper` since there aren't any operations we - // want to perform on it. In the future, we may want to - // consider just filtering all build and dev dependencies in - // metadata::build. + // metadata --features …`, but that is somewhat slow. In + // the future, we may want to consider just filtering all + // build and dev dependencies in metadata::build. if visited.insert(dep) - && dep != "build_helper" && (dep != "profiler_builtins" || target .map(|t| self.config.profiler_enabled(t)) diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 65e229697dc87..59dc50be47f06 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -1,10 +1,10 @@ use std::path::PathBuf; use std::process::Command; -use build_helper::output; use serde::Deserialize; use crate::cache::INTERNER; +use crate::util::output; use crate::{Build, Crate}; #[derive(Deserialize)] diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a751a6e3ece7f..d27ad9644b56c 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -16,13 +16,10 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::{output, t}; - use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::config::TargetSelection; -use crate::util::{self, exe}; +use crate::util::{self, exe, output, t, up_to_date}; use crate::{CLang, GitRepo}; -use build_helper::up_to_date; pub struct Meta { stamp: HashStamp, diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 11b393857e74c..25abe7a72fdc8 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -1,7 +1,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::dist::distdir; use crate::tool::Tool; -use build_helper::output; +use crate::util::output; use std::process::Command; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index d7db2cef24f2b..8c2899c1ac01e 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -15,10 +15,9 @@ use std::fs; use std::path::PathBuf; use std::process::Command; -use build_helper::output; - use crate::cache::INTERNER; use crate::config::Target; +use crate::util::output; use crate::Build; pub struct Finder { diff --git a/src/bootstrap/tarball.rs b/src/bootstrap/tarball.rs index 9ff5c2327e0f7..c743c5188e754 100644 --- a/src/bootstrap/tarball.rs +++ b/src/bootstrap/tarball.rs @@ -3,9 +3,8 @@ use std::{ process::Command, }; -use build_helper::t; - use crate::builder::Builder; +use crate::util::t; #[derive(Copy, Clone)] pub(crate) enum OverlayKind { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 19d98df3ce902..e4fcb287f1228 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -11,8 +11,6 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use build_helper::{self, output, t}; - use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::Interned; use crate::compile; @@ -22,7 +20,7 @@ use crate::flags::Subcommand; use crate::native; use crate::tool::{self, SourceType, Tool}; use crate::toolstate::ToolState; -use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var}; +use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t}; use crate::Crate as CargoCrate; use crate::{envify, CLang, DocTests, GitRepo, Mode}; @@ -2306,9 +2304,7 @@ impl Step for Distcheck { .current_dir(&dir), ); builder.run( - Command::new(build_helper::make(&builder.config.build.triple)) - .arg("check") - .current_dir(&dir), + Command::new(util::make(&builder.config.build.triple)).arg("check").current_dir(&dir), ); // Now make sure that rust-src has all of libstd's dependencies diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 1317c3f983975..2ae4d830721e8 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -4,14 +4,12 @@ use std::fs; use std::path::{Path, PathBuf}; use std::process::{exit, Command}; -use build_helper::t; - use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::channel::GitInfo; use crate::compile; use crate::config::TargetSelection; use crate::toolstate::ToolState; -use crate::util::{add_dylib_path, exe}; +use crate::util::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 08d0815806207..c7ea254c5b1d7 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -1,5 +1,5 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use build_helper::t; +use crate::util::t; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::env; diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2c78ceb1e5bec..8e770d4d57fa6 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -7,15 +7,38 @@ use std::env; use std::fs; use std::io; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use std::str; -use std::time::Instant; - -use build_helper::t; +use std::time::{Instant, SystemTime, UNIX_EPOCH}; use crate::builder::Builder; use crate::config::{Config, TargetSelection}; +/// A helper macro to `unwrap` a result except also print out details like: +/// +/// * The file/line of the panic +/// * The expression that failed +/// * The error itself +/// +/// This is currently used judiciously throughout the build system rather than +/// using a `Result` with `try!`, but this may change one day... +macro_rules! t { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; + // it can show extra info in the second parameter + ($e:expr, $extra:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra), + } + }; +} +pub(crate) use t; + /// Given an executable called `name`, return the filename for the /// executable for a particular target. pub fn exe(name: &str, target: TargetSelection) -> String { @@ -301,3 +324,119 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef>( _ => None, } } + +pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { + if !try_run(cmd, print_cmd_on_fail) { + std::process::exit(1); + } +} + +pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), + }; + if !status.success() && print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + status.success() +} + +pub fn run_suppressed(cmd: &mut Command) { + if !try_run_suppressed(cmd) { + std::process::exit(1); + } +} + +pub fn try_run_suppressed(cmd: &mut Command) -> bool { + let output = match cmd.output() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), + }; + if !output.status.success() { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n\ + stdout ----\n{}\n\ + stderr ----\n{}\n\n", + cmd, + output.status, + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); + } + output.status.success() +} + +pub fn make(host: &str) -> PathBuf { + if host.contains("dragonfly") + || host.contains("freebsd") + || host.contains("netbsd") + || host.contains("openbsd") + { + PathBuf::from("gmake") + } else { + PathBuf::from("make") + } +} + +#[track_caller] +pub fn output(cmd: &mut Command) -> String { + let output = match cmd.stderr(Stdio::inherit()).output() { + Ok(status) => status, + Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), + }; + if !output.status.success() { + panic!( + "command did not execute successfully: {:?}\n\ + expected success, got: {}", + cmd, output.status + ); + } + String::from_utf8(output.stdout).unwrap() +} + +/// Returns the last-modified time for `path`, or zero if it doesn't exist. +pub fn mtime(path: &Path) -> SystemTime { + fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH) +} + +/// Returns `true` if `dst` is up to date given that the file or files in `src` +/// are used to generate it. +/// +/// Uses last-modified time checks to verify this. +pub fn up_to_date(src: &Path, dst: &Path) -> bool { + if !dst.exists() { + return false; + } + let threshold = mtime(dst); + let meta = match fs::metadata(src) { + Ok(meta) => meta, + Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), + }; + if meta.is_dir() { + dir_up_to_date(src, threshold) + } else { + meta.modified().unwrap_or(UNIX_EPOCH) <= threshold + } +} + +fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { + t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { + let meta = t!(e.metadata()); + if meta.is_dir() { + dir_up_to_date(&e.path(), threshold) + } else { + meta.modified().unwrap_or(UNIX_EPOCH) < threshold + } + }) +} + +fn fail(s: &str) -> ! { + println!("\n\n{}\n\n", s); + std::process::exit(1); +} diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml deleted file mode 100644 index d88df0e08fab3..0000000000000 --- a/src/build_helper/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "build_helper" -version = "0.1.0" -edition = "2021" - -[lib] -path = "lib.rs" diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs deleted file mode 100644 index 24aded547315e..0000000000000 --- a/src/build_helper/lib.rs +++ /dev/null @@ -1,189 +0,0 @@ -use std::ffi::{OsStr, OsString}; -use std::fmt::Display; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::time::{SystemTime, UNIX_EPOCH}; -use std::{env, fs}; - -/// A helper macro to `unwrap` a result except also print out details like: -/// -/// * The file/line of the panic -/// * The expression that failed -/// * The error itself -/// -/// This is currently used judiciously throughout the build system rather than -/// using a `Result` with `try!`, but this may change one day... -#[macro_export] -macro_rules! t { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {}", stringify!($e), e), - } - }; - // it can show extra info in the second parameter - ($e:expr, $extra:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra), - } - }; -} - -/// Reads an environment variable and adds it to dependencies. -/// Supposed to be used for all variables except those set for build scripts by cargo -/// -pub fn tracked_env_var_os + Display>(key: K) -> Option { - println!("cargo:rerun-if-env-changed={}", key); - env::var_os(key) -} - -// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may -// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM -// shared library, which means that when our freshly built llvm-config goes to load it's -// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first -// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from -// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't -// perfect -- we might actually want to see something from Cargo's added library paths -- but -// for now it works. -pub fn restore_library_path() { - let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR"); - if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") { - env::set_var(&key, &env); - } else { - env::remove_var(&key); - } -} - -pub fn run(cmd: &mut Command, print_cmd_on_fail: bool) { - if !try_run(cmd, print_cmd_on_fail) { - std::process::exit(1); - } -} - -pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { - let status = match cmd.status() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), - }; - if !status.success() && print_cmd_on_fail { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n", - cmd, status - ); - } - status.success() -} - -pub fn run_suppressed(cmd: &mut Command) { - if !try_run_suppressed(cmd) { - std::process::exit(1); - } -} - -pub fn try_run_suppressed(cmd: &mut Command) -> bool { - let output = match cmd.output() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), - }; - if !output.status.success() { - println!( - "\n\ncommand did not execute successfully: {:?}\n\ - expected success, got: {}\n\n\ - stdout ----\n{}\n\ - stderr ----\n{}\n\n", - cmd, - output.status, - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ); - } - output.status.success() -} - -pub fn make(host: &str) -> PathBuf { - if host.contains("dragonfly") - || host.contains("freebsd") - || host.contains("netbsd") - || host.contains("openbsd") - { - PathBuf::from("gmake") - } else { - PathBuf::from("make") - } -} - -#[track_caller] -pub fn output(cmd: &mut Command) -> String { - let output = match cmd.stderr(Stdio::inherit()).output() { - Ok(status) => status, - Err(e) => fail(&format!("failed to execute command: {:?}\nerror: {}", cmd, e)), - }; - if !output.status.success() { - panic!( - "command did not execute successfully: {:?}\n\ - expected success, got: {}", - cmd, output.status - ); - } - String::from_utf8(output.stdout).unwrap() -} - -pub fn rerun_if_changed_anything_in_dir(dir: &Path) { - let mut stack = dir - .read_dir() - .unwrap() - .map(|e| e.unwrap()) - .filter(|e| &*e.file_name() != ".git") - .collect::>(); - while let Some(entry) = stack.pop() { - let path = entry.path(); - if entry.file_type().unwrap().is_dir() { - stack.extend(path.read_dir().unwrap().map(|e| e.unwrap())); - } else { - println!("cargo:rerun-if-changed={}", path.display()); - } - } -} - -/// Returns the last-modified time for `path`, or zero if it doesn't exist. -pub fn mtime(path: &Path) -> SystemTime { - fs::metadata(path).and_then(|f| f.modified()).unwrap_or(UNIX_EPOCH) -} - -/// Returns `true` if `dst` is up to date given that the file or files in `src` -/// are used to generate it. -/// -/// Uses last-modified time checks to verify this. -pub fn up_to_date(src: &Path, dst: &Path) -> bool { - if !dst.exists() { - return false; - } - let threshold = mtime(dst); - let meta = match fs::metadata(src) { - Ok(meta) => meta, - Err(e) => panic!("source {:?} failed to get metadata: {}", src, e), - }; - if meta.is_dir() { - dir_up_to_date(src, threshold) - } else { - meta.modified().unwrap_or(UNIX_EPOCH) <= threshold - } -} - -fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { - t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { - let meta = t!(e.metadata()); - if meta.is_dir() { - dir_up_to_date(&e.path(), threshold) - } else { - meta.modified().unwrap_or(UNIX_EPOCH) < threshold - } - }) -} - -fn fail(s: &str) -> ! { - println!("\n\n{}\n\n", s); - std::process::exit(1); -}