diff --git a/Cargo.lock b/Cargo.lock
index 908bfa355571b..76fcdc1691316 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -19,6 +19,7 @@ dependencies = [
 name = "alloc"
 version = "0.0.0"
 dependencies = [
+ "build_helper",
  "compiler_builtins",
  "core",
  "rand 0.7.3",
@@ -653,6 +654,7 @@ dependencies = [
 name = "core"
 version = "0.0.0"
 dependencies = [
+ "build_helper",
  "rand 0.7.3",
 ]
 
@@ -3694,6 +3696,7 @@ dependencies = [
  "indexmap",
  "jobserver",
  "lazy_static 1.4.0",
+ "libc",
  "log",
  "measureme",
  "parking_lot 0.10.0",
@@ -3713,6 +3716,7 @@ version = "0.0.0"
 dependencies = [
  "env_logger 0.7.1",
  "lazy_static 1.4.0",
+ "libc",
  "log",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -3867,6 +3871,7 @@ dependencies = [
 name = "rustc_interface"
 version = "0.0.0"
 dependencies = [
+ "libc",
  "log",
  "once_cell",
  "rustc-rayon",
@@ -3960,6 +3965,7 @@ name = "rustc_metadata"
 version = "0.0.0"
 dependencies = [
  "flate2",
+ "libc",
  "log",
  "memmap",
  "rustc_ast",
@@ -4197,6 +4203,8 @@ dependencies = [
 name = "rustc_session"
 version = "0.0.0"
 dependencies = [
+ "build_helper",
+ "getopts",
  "log",
  "num_cpus",
  "rustc_ast",
@@ -4689,6 +4697,7 @@ version = "0.0.0"
 dependencies = [
  "alloc",
  "backtrace",
+ "build_helper",
  "cfg-if",
  "compiler_builtins",
  "core",
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index 32ce170a5a1fe..12b2a19d96955 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -461,6 +461,7 @@ impl Step for Rustc {
 
 pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: Interned<String>) {
     cargo
+        .arg("--no-default-features")
         .arg("--features")
         .arg(builder.rustc_features())
         .arg("--manifest-path")
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 8215211ea1c9d..c6eefa316ca9b 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -1174,7 +1174,7 @@ impl Step for Cargo {
         let etc = src.join("src/etc");
         let release_num = builder.release_num("cargo");
         let name = pkgname(builder, "cargo");
-        let version = builder.cargo_info.version(builder, &release_num);
+        let version = builder.cargo_info.version(builder.release(&release_num));
 
         let tmp = tmpdir(builder);
         let image = tmp.join("cargo-image");
@@ -1266,7 +1266,7 @@ impl Step for Rls {
         let src = builder.src.join("src/tools/rls");
         let release_num = builder.release_num("rls");
         let name = pkgname(builder, "rls");
-        let version = builder.rls_info.version(builder, &release_num);
+        let version = builder.rls_info.version(builder.release(&release_num));
 
         let tmp = tmpdir(builder);
         let image = tmp.join("rls-image");
@@ -1356,7 +1356,7 @@ impl Step for Clippy {
         let src = builder.src.join("src/tools/clippy");
         let release_num = builder.release_num("clippy");
         let name = pkgname(builder, "clippy");
-        let version = builder.clippy_info.version(builder, &release_num);
+        let version = builder.clippy_info.version(builder.release(&release_num));
 
         let tmp = tmpdir(builder);
         let image = tmp.join("clippy-image");
@@ -1453,7 +1453,7 @@ impl Step for Miri {
         let src = builder.src.join("src/tools/miri");
         let release_num = builder.release_num("miri");
         let name = pkgname(builder, "miri");
-        let version = builder.miri_info.version(builder, &release_num);
+        let version = builder.miri_info.version(builder.release(&release_num));
 
         let tmp = tmpdir(builder);
         let image = tmp.join("miri-image");
@@ -1549,7 +1549,7 @@ impl Step for Rustfmt {
         let src = builder.src.join("src/tools/rustfmt");
         let release_num = builder.release_num("rustfmt");
         let name = pkgname(builder, "rustfmt");
-        let version = builder.rustfmt_info.version(builder, &release_num);
+        let version = builder.rustfmt_info.version(builder.release(&release_num));
 
         let tmp = tmpdir(builder);
         let image = tmp.join("rustfmt-image");
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 31bbd92cd6205..2bfafc24ac3c2 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -120,7 +120,7 @@ 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 build_helper::{channel, mtime, output, run, run_suppressed, t, try_run, try_run_suppressed};
 use filetime::FileTime;
 
 use crate::util::{exe, libdir, CiEnv};
@@ -128,7 +128,6 @@ use crate::util::{exe, libdir, CiEnv};
 mod builder;
 mod cache;
 mod cc_detect;
-mod channel;
 mod check;
 mod clean;
 mod compile;
@@ -1047,7 +1046,7 @@ impl Build {
     /// Note that this is a descriptive string which includes the commit date,
     /// sha, version, etc.
     fn rust_version(&self) -> String {
-        self.rust_info.version(self, channel::CFG_RELEASE_NUM)
+        self.rust_info.version(self.release(channel::CFG_RELEASE_NUM))
     }
 
     /// Returns the full commit hash.
diff --git a/src/bootstrap/channel.rs b/src/build_helper/channel.rs
similarity index 94%
rename from src/bootstrap/channel.rs
rename to src/build_helper/channel.rs
index be2b0f36d14a7..355bd1cc150aa 100644
--- a/src/bootstrap/channel.rs
+++ b/src/build_helper/channel.rs
@@ -8,17 +8,17 @@
 use std::path::Path;
 use std::process::Command;
 
-use build_helper::output;
-
-use crate::Build;
+use crate::output;
 
 // The version number
 pub const CFG_RELEASE_NUM: &str = "1.44.0";
 
+#[derive(Clone)]
 pub struct GitInfo {
     inner: Option<Info>,
 }
 
+#[derive(Clone)]
 struct Info {
     commit_date: String,
     sha: String,
@@ -72,8 +72,7 @@ impl GitInfo {
         self.inner.as_ref().map(|s| &s.commit_date[..])
     }
 
-    pub fn version(&self, build: &Build, num: &str) -> String {
-        let mut version = build.release(num);
+    pub fn version(&self, mut version: String) -> String {
         if let Some(ref inner) = self.inner {
             version.push_str(" (");
             version.push_str(&inner.short_sha);
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index 43c3c5773ce5b..d2334fb83ed29 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -1,5 +1,13 @@
+pub mod channel;
+
+use std::borrow::Cow;
+use std::error::Error;
+use std::ffi::OsString;
+use std::fs::File;
+use std::io::{BufRead, BufReader};
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
+use std::str;
 use std::time::{SystemTime, UNIX_EPOCH};
 use std::{env, fs};
 
@@ -39,11 +47,12 @@ macro_rules! t {
 pub fn restore_library_path() {
     println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR");
     println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH");
-    let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
-    if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
-        env::set_var(&key, &env);
-    } else {
-        env::remove_var(&key);
+    if let Some(key) = env::var_os("REAL_LIBRARY_PATH_VAR") {
+        if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
+            env::set_var(&key, &env);
+        } else {
+            env::remove_var(&key);
+        }
     }
 }
 
@@ -194,3 +203,347 @@ fn fail(s: &str) -> ! {
     println!("\n\n{}\n\n", s);
     std::process::exit(1);
 }
+
+#[derive(Default)]
+pub struct RustcVersion {
+    pub version: Option<String>,
+    pub release: Option<String>,
+    pub commit_hash: Option<String>,
+    pub commit_date: Option<String>,
+    pub is_stable_or_beta: bool,
+}
+
+fn get_rustc_version() -> Result<RustcVersion, Box<dyn Error>> {
+    let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
+
+    // check whether we are stable/beta and version in a single command for nightly compilers
+    let output = Command::new(&rustc)
+        .arg("-Z")
+        .arg("verbose")
+        .arg("-Vv")
+        .env_remove("RUSTC_BOOTSTRAP")
+        .output()?;
+    let (is_stable_or_beta, version_lines) = if output.status.success() {
+        (false, String::from_utf8(output.stdout)?)
+    } else {
+        let output = Command::new(&rustc).arg("-Vv").output()?;
+        (true, String::from_utf8(output.stdout)?)
+    };
+    let mut version_lines = version_lines.lines();
+    let mut rustc_version = RustcVersion::default();
+    rustc_version.is_stable_or_beta = is_stable_or_beta;
+    rustc_version.version =
+        version_lines.next().and_then(|x| x.splitn(2, " ").skip(1).next().map(|x| x.into()));
+    for line in version_lines {
+        let mut line = line.splitn(2, ": ");
+        let key = line.next();
+        let value = line.next();
+        match key {
+            Some("release") => rustc_version.release = value.map(|x| x.into()),
+            Some("commit-hash") => rustc_version.commit_hash = value.map(|x| x.into()),
+            Some("commit-date") => rustc_version.commit_date = value.map(|x| x.into()),
+            _ => {}
+        };
+    }
+
+    Ok(rustc_version)
+}
+
+fn get_upstream_commit_hash(commit_ref: &str) -> Result<String, Box<dyn Error>> {
+    Ok(String::from_utf8(
+        Command::new("git").arg("merge-base").arg(commit_ref).arg("origin/master").output()?.stdout,
+    )?
+    .trim()
+    .into())
+}
+
+enum Stage0Rustc {
+    Beta { date: String },
+    Stable { release: String },
+}
+
+struct Stage0 {
+    rustc: Result<Stage0Rustc, &'static str>,
+    #[allow(dead_code)]
+    cargo: Option<String>,
+}
+
+fn get_stage0() -> Result<Stage0, Box<dyn Error>> {
+    let mut date = None;
+    let mut rustc = None;
+    let mut cargo = None;
+    for line in BufReader::new(File::open("../stage0.txt")?).lines() {
+        let line = line?;
+        if !line.starts_with("#") {
+            let mut line = line.splitn(2, ": ");
+            if let Some(key) = line.next() {
+                let value = line.next();
+                match key {
+                    "date" => date = value.map(|x| x.into()),
+                    "rustc" => rustc = value.map(|x| x.into()),
+                    "cargo" => cargo = value.map(|x| x.into()),
+                    _ => {}
+                }
+            }
+        }
+    }
+
+    Ok(Stage0 {
+        rustc: match rustc {
+            Some(rustc) if rustc == "beta" => match date {
+                Some(date) => Ok(Stage0Rustc::Beta { date }),
+                _ => Err("src/stage0.txt does not contain a 'date = ...' line".into()),
+            },
+            Some(rustc) => Ok(Stage0Rustc::Stable { release: rustc }),
+            _ => Err("src/stage0.txt does not contain a 'rustc = ...' line".into()),
+        },
+        cargo,
+    })
+}
+
+const BUILD_SUGGESTIONS_HEADER: &'static str = "\
+    This can result in compilation failures and inability to use a built rustc with the installed libstd or viceversa\n\
+    \n\
+    Suggestions for solving this issue if you are working on the Rust codebase:";
+
+const BUILD_SUGGESTIONS_FOOTER: &'static str = "If you are just trying to install Rust from source or build a distributable package, then use `./x.py` instead as described in README.md\n";
+
+const BUILD_SUGGESTIONS_NIGHTLY: &'static str = "\
+    1. Download the latest nightly with `rustup install nightly`\n\
+    2. Get the git commit hash of the nightly with `rustc +nightly -vV|sed -nre 's/^commit-hash: (.*)/\\1/p'`\n\
+    3. Rebase your work onto it with `git rebase --onto $(rustc +nightly -vV|sed -nre 's/^commit-hash: (.*)/\\1/p') origin/master`\n\
+    4. Build again with `cargo +nightly build`";
+
+const BUILD_SUGGESTIONS_BETA: &'static str = "\
+    1. Download the latest beta with `rustup install beta`\n\
+    2. Build again with `cargo +beta build`";
+
+fn build_suggestions_stable(release: &str) -> String {
+    format!(
+        "\
+        1. Download Rust {} with `rustup install {}`\n\
+        2. Build again with `cargo +{} build`",
+        release, release, release
+    )
+}
+
+fn build_suggestions(body: impl AsRef<str>) -> String {
+    format!("{}\n{}\n\n{}", BUILD_SUGGESTIONS_HEADER, body.as_ref(), BUILD_SUGGESTIONS_FOOTER)
+}
+
+#[derive(Default)]
+pub struct RustcInfo {
+    pub version: RustcVersion,
+    pub bootstrap: bool,
+}
+
+fn check_rustc(warn: bool, beta_warning: Option<&str>) -> Option<RustcInfo> {
+    if env::var_os("RUSTC_STAGE").is_some() {
+        // being built by x.py, skip all checks and adjustments
+        None
+    } else {
+        macro_rules! warn {
+            ($($arg:tt)*) => ({
+                if warn {
+                    println!("cargo:warning={}", format!($($arg)*).replace("\n", "\ncargo:warning="));
+                }
+            })
+        }
+
+        let rustc = get_rustc_version();
+        if rustc.as_ref().map(|x| x.is_stable_or_beta).unwrap_or_default()
+            && std::env::var_os("RUSTC_BOOTSTRAP").is_none()
+        {
+            // currently we can't set this automatically without also modifying the dependencies from crates.io that don't set it
+            eprintln!(
+                "ERROR: you must set RUSTC_BOOTSTRAP=1 when using a stable or beta toolchain"
+            );
+            if warn {
+                eprintln!(
+                    "\
+                    You may want to use the latest nightly unless you want to bootstrap libstd\n\
+                    {}",
+                    build_suggestions(BUILD_SUGGESTIONS_NIGHTLY)
+                );
+            };
+            std::process::exit(1);
+        }
+        match rustc {
+            Ok(rustc) => {
+                let rustc_upstream_commit_hash = if let Some(rustc_commit_hash) = &rustc.commit_hash
+                {
+                    get_upstream_commit_hash(&rustc_commit_hash).map_err(|err|
+                        warn!("ERROR: unable to get upstream commit hash that the rustc git commit is based on: {}", err)
+                    ).ok()
+                } else {
+                    warn!("ERROR: rustc -vV output did not include a commit hash");
+                    None
+                };
+                let source_upstream_commit_hash = get_upstream_commit_hash("HEAD").map_err(|err|
+                     warn!("ERROR: unable to get upstream commit hash that the current git tree is based on: {}", err)
+                ).ok();
+                let dev_ok = match (&rustc_upstream_commit_hash, &source_upstream_commit_hash) {
+                    (Some(a), Some(b)) if a == b => true,
+                    _ => false,
+                };
+                let bootstrap = match beta_warning {
+                    _ if dev_ok => false,
+                    Some(beta_warning) if rustc.is_stable_or_beta => {
+                        warn!(
+                            "\
+                            {}\n\
+                            {}",
+                            beta_warning,
+                            build_suggestions(BUILD_SUGGESTIONS_NIGHTLY)
+                        );
+                        false
+                    }
+                    _ => {
+                        let stage0 = get_stage0()
+                            .map_err(|err| warn!("ERROR: unable to parse src/stage0.txt: {}", err))
+                            .ok();
+
+                        let stage0rustc = stage0.and_then(|stage0| stage0.rustc.map_err(|err|
+                            warn!("ERROR: unable to get required rustc version from src/stage0.txt: {}", err)
+                        ).ok());
+
+                        let bootstrap_ok = match (&stage0rustc, &rustc.release, &rustc.commit_date)
+                        {
+                            (
+                                Some(Stage0Rustc::Beta { date }),
+                                Some(rustc_release),
+                                Some(rustc_commit_date),
+                            ) if rustc_release.contains("-beta") => date <= rustc_commit_date,
+                            (Some(Stage0Rustc::Stable { release }), Some(rustc_release), _) => {
+                                release == rustc_release
+                            }
+                            _ => false,
+                        };
+
+                        if bootstrap_ok {
+                            true
+                        } else if rustc.is_stable_or_beta {
+                            if rustc
+                                .release
+                                .as_ref()
+                                .map(|x| x.contains("-beta"))
+                                .unwrap_or_default()
+                            {
+                                match &stage0rustc {
+                                    Some(Stage0Rustc::Stable { release }) => {
+                                        warn!(
+                                            "\
+                                            IMPORTANT: you are building with a beta toolchain, but you must use stable version `{}` as specified in src/stage0.txt\n\
+                                            {}",
+                                            release,
+                                            build_suggestions(build_suggestions_stable(release))
+                                        );
+                                    }
+                                    _ => {
+                                        let date = match stage0rustc {
+                                            Some(Stage0Rustc::Beta { date }) => Some(date),
+                                            _ => None,
+                                        };
+                                        warn!(
+                                            "\
+                                            IMPORTANT: the beta toolchain you are using to build is older than the required build specified in stage0.txt\n\
+                                            The toolchain date is `{}`, but stage0.txt requires a date of `{}` or later\n\
+                                            {}",
+                                            rustc
+                                                .commit_date
+                                                .as_ref()
+                                                .map(|x| x.as_str())
+                                                .unwrap_or("<unknown>"),
+                                            date.as_ref()
+                                                .map(|x| x.as_str())
+                                                .unwrap_or("<unknown>"),
+                                            build_suggestions(BUILD_SUGGESTIONS_BETA)
+                                        )
+                                    }
+                                }
+                            } else {
+                                match &stage0rustc {
+                                    Some(Stage0Rustc::Stable { release }) => warn!(
+                                        "\
+                                            IMPORTANT: the stable toolchain you are using to build is different than the required build specified in stage0.txt\n\
+                                            The toolchain release is `{}`, but stage0.txt requires release `{}`\n\
+                                            {}",
+                                        rustc
+                                            .release
+                                            .as_ref()
+                                            .map(|x| x.as_str())
+                                            .unwrap_or("<unknown>"),
+                                        release,
+                                        build_suggestions(build_suggestions_stable(release))
+                                    ),
+                                    _ => warn!(
+                                        "\
+                                            IMPORTANT: you are building with a stable toolchain, but you must use the most recent nightly, or the most recent beta if you want to bootstrap libstd\n\
+                                            {}",
+                                        build_suggestions(BUILD_SUGGESTIONS_NIGHTLY)
+                                    ),
+                                }
+                            }
+                            true
+                        } else {
+                            warn!(
+                                "\
+                                IMPORTANT: the toolchain you are using to build does not match the upstream git commit hash of your repository!\n\
+                                The toolchain is based upon upstream git commit `{}`, but the repository is based upon upstream git commit `{}`\n\
+                                {}",
+                                rustc_upstream_commit_hash
+                                    .as_ref()
+                                    .map(|x| x.as_str())
+                                    .unwrap_or("<unknown>"),
+                                source_upstream_commit_hash
+                                    .as_ref()
+                                    .map(|x| x.as_str())
+                                    .unwrap_or("<unknown>"),
+                                build_suggestions(BUILD_SUGGESTIONS_NIGHTLY)
+                            );
+                            false
+                        }
+                    }
+                };
+                Some(RustcInfo { version: rustc, bootstrap })
+            }
+            Err(err) => {
+                warn!(
+                    "ERROR: unable to get rustc version: {}\n\
+                    Unable to check if you are using the correct toolchain version to build\n\
+                    {}",
+                    err,
+                    build_suggestions(BUILD_SUGGESTIONS_NIGHTLY)
+                );
+                Some(Default::default())
+            }
+        }
+    }
+}
+
+pub fn build_stdlib(warn: bool) -> Option<RustcInfo> {
+    if let Some(rustc) = check_rustc(warn, None) {
+        if rustc.bootstrap {
+            println!("cargo:rustc-cfg=bootstrap");
+        }
+        Some(rustc)
+    } else {
+        None
+    }
+}
+
+pub fn set_env<'a>(key: &str, value: impl FnOnce() -> Option<Cow<'a, str>>) {
+    if std::env::var_os(key).is_none() {
+        if let Some(value) = value() {
+            println!("cargo:rustc-env={}={}", key, value);
+        }
+    }
+}
+
+const RUSTC_BETA_WARNING: &'static str = "\
+    IMPORTANT: you are trying to build rustc with a stable or beta toolchain, which is not supported.\n\
+    Rustc is only guaranteed to successfully build with a nightly build matching the git commit hash of the repository, since it depends on the libstd with the same git version";
+
+pub fn build_rustc() -> Option<RustcInfo> {
+    check_rustc(true, Some(RUSTC_BETA_WARNING))
+}
diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml
index d1119f7b7c0a7..ccbfd9752d6ea 100644
--- a/src/liballoc/Cargo.toml
+++ b/src/liballoc/Cargo.toml
@@ -18,6 +18,9 @@ compiler_builtins = { version = "0.1.10", features = ['rustc-dep-of-std'] }
 rand = "0.7"
 rand_xorshift = "0.2"
 
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+
 [[test]]
 name = "collectionstests"
 path = "../liballoc/tests/lib.rs"
diff --git a/src/liballoc/build.rs b/src/liballoc/build.rs
new file mode 100644
index 0000000000000..c94c14ddf799c
--- /dev/null
+++ b/src/liballoc/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+    build_helper::build_stdlib(false);
+}
diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml
index ac07ffb14febd..14d433631bff1 100644
--- a/src/libcore/Cargo.toml
+++ b/src/libcore/Cargo.toml
@@ -23,6 +23,9 @@ path = "../libcore/benches/lib.rs"
 [dev-dependencies]
 rand = "0.7"
 
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+
 [features]
 # Make panics and failed asserts immediately abort without formatting any message
 panic_immediate_abort = []
diff --git a/src/libcore/build.rs b/src/libcore/build.rs
new file mode 100644
index 0000000000000..ec5b4eef2a3b8
--- /dev/null
+++ b/src/libcore/build.rs
@@ -0,0 +1,3 @@
+fn main() {
+    build_helper::build_stdlib(true);
+}
diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs
index c990b28933504..f9ebf215b6e8b 100644
--- a/src/libprofiler_builtins/build.rs
+++ b/src/libprofiler_builtins/build.rs
@@ -63,8 +63,12 @@ fn main() {
         cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1"));
     }
 
-    let root = env::var_os("RUST_COMPILER_RT_ROOT").unwrap();
-    let root = Path::new(&root);
+    let root = env::var_os("RUST_COMPILER_RT_ROOT");
+    let root = if let Some(root) = &root {
+        Path::new(root)
+    } else {
+        Path::new("../llvm-project/compiler-rt")
+    };
 
     let src_root = root.join("lib").join("profile");
     for src in profile_sources {
diff --git a/src/librustc_ast/build.rs b/src/librustc_ast/build.rs
deleted file mode 100644
index 9b861f9640904..0000000000000
--- a/src/librustc_ast/build.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-    println!("cargo:rerun-if-env-changed=CFG_DISABLE_UNSTABLE_FEATURES");
-}
diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs
index 76c790f80b86b..534d3668affc4 100644
--- a/src/librustc_ast_passes/feature_gate.rs
+++ b/src/librustc_ast_passes/feature_gate.rs
@@ -6,6 +6,7 @@ use rustc_errors::{struct_span_err, Handler};
 use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
 use rustc_feature::{Features, GateIssue, UnstableFeatures};
 use rustc_session::parse::{feature_err, feature_err_issue, ParseSess};
+use rustc_session::CFG_RELEASE_CHANNEL;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -657,7 +658,7 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: Un
                 attr.span,
                 E0554,
                 "`#![feature]` may not be used on the {} release channel",
-                option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)")
+                CFG_RELEASE_CHANNEL.unwrap_or("(unknown)")
             )
             .emit();
         }
diff --git a/src/librustc_codegen_llvm/build.rs b/src/librustc_codegen_llvm/build.rs
index d1fc624c68927..7b47db3b0c9b5 100644
--- a/src/librustc_codegen_llvm/build.rs
+++ b/src/librustc_codegen_llvm/build.rs
@@ -1,6 +1,4 @@
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-    println!("cargo:rerun-if-env-changed=CFG_PREFIX");
     println!("cargo:rerun-if-env-changed=CFG_LLVM_ROOT");
 }
diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs
index 82cd858932747..f0477d5582c06 100644
--- a/src/librustc_codegen_llvm/debuginfo/metadata.rs
+++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs
@@ -40,6 +40,7 @@ use rustc_middle::ty::Instance;
 use rustc_middle::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{self, DebugInfo};
+use rustc_session::CFG_VERSION;
 use rustc_span::symbol::{Interner, Symbol};
 use rustc_span::{self, SourceFile, SourceFileHash, Span};
 use rustc_target::abi::{Abi, Align, DiscriminantKind, HasDataLayout, Integer, LayoutOf};
@@ -909,8 +910,7 @@ pub fn compile_unit_metadata(
     }
 
     debug!("compile_unit_metadata: {:?}", name_in_debuginfo);
-    let rustc_producer =
-        format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),);
+    let rustc_producer = format!("rustc version {}", CFG_VERSION.expect("CFG_VERSION"),);
     // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
     let producer = format!("clang LLVM ({})", rustc_producer);
 
diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs
index 20e64f0c48851..149ebc2fd6a1d 100644
--- a/src/librustc_codegen_ssa/back/link.rs
+++ b/src/librustc_codegen_ssa/back/link.rs
@@ -10,7 +10,7 @@ use rustc_session::output::{check_file_is_writeable, invalid_output_for_target,
 use rustc_session::search_paths::PathKind;
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
-use rustc_session::{filesearch, Session};
+use rustc_session::{filesearch, Session, CFG_PREFIX, CFG_RELEASE_CHANNEL};
 use rustc_span::symbol::Symbol;
 use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
 
@@ -698,9 +698,7 @@ fn link_sanitizer_runtime(sess: &Session, crate_type: config::CrateType, linker:
     let default_sysroot = filesearch::get_or_default_sysroot();
     let default_tlib =
         filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.triple());
-    let channel = option_env!("CFG_RELEASE_CHANNEL")
-        .map(|channel| format!("-{}", channel))
-        .unwrap_or_default();
+    let channel = CFG_RELEASE_CHANNEL.map(|channel| format!("-{}", channel)).unwrap_or_default();
 
     match sess.opts.target_triple.triple() {
         "x86_64-apple-darwin" => {
@@ -1402,7 +1400,7 @@ fn add_rpath_args(
     if sess.opts.cg.rpath {
         let target_triple = sess.opts.target_triple.triple();
         let mut get_install_prefix_lib_path = || {
-            let install_prefix = option_env!("CFG_PREFIX").expect("CFG_PREFIX");
+            let install_prefix = CFG_PREFIX.expect("CFG_PREFIX");
             let tlib = filesearch::relative_target_lib_path(&sess.sysroot, target_triple);
             let mut path = PathBuf::from(install_prefix);
             path.push(&tlib);
diff --git a/src/librustc_codegen_ssa/build.rs b/src/librustc_codegen_ssa/build.rs
deleted file mode 100644
index ea2af6e192e7c..0000000000000
--- a/src/librustc_codegen_ssa/build.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml
index c5707bd24f7e7..6d7022acc7863 100644
--- a/src/librustc_data_structures/Cargo.toml
+++ b/src/librustc_data_structures/Cargo.toml
@@ -27,6 +27,7 @@ smallvec = { version = "1.0", features = ["union", "may_dangle"] }
 rustc_index = { path = "../librustc_index", package = "rustc_index" }
 bitflags = "1.2.1"
 measureme = "0.7.1"
+libc = "0.2"
 
 [dependencies.parking_lot]
 version = "0.10"
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index ba82e58d7a92e..d0180911567c7 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -26,8 +26,6 @@
 
 #[macro_use]
 extern crate log;
-#[cfg(unix)]
-extern crate libc;
 #[macro_use]
 extern crate cfg_if;
 
diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml
index 652f16c2e0828..cfd103aed3240 100644
--- a/src/librustc_driver/Cargo.toml
+++ b/src/librustc_driver/Cargo.toml
@@ -11,6 +11,7 @@ crate-type = ["dylib"]
 
 [dependencies]
 lazy_static = "1.0"
+libc = "0.2"
 log = "0.4"
 env_logger = { version = "0.7", default-features = false }
 rustc_middle = { path = "../librustc_middle" }
diff --git a/src/librustc_driver/build.rs b/src/librustc_driver/build.rs
deleted file mode 100644
index 414d13445f01e..0000000000000
--- a/src/librustc_driver/build.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-    println!("cargo:rerun-if-env-changed=CFG_VER_DATE");
-    println!("cargo:rerun-if-env-changed=CFG_VER_HASH");
-}
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index acf8f1adbc2e8..13fe2dd15a75c 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -8,9 +8,6 @@
 #![feature(nll)]
 #![recursion_limit = "256"]
 
-pub extern crate getopts;
-#[cfg(unix)]
-extern crate libc;
 #[macro_use]
 extern crate log;
 #[macro_use]
@@ -37,8 +34,11 @@ use rustc_save_analysis::DumpHandler;
 use rustc_serialize::json::{self, ToJson};
 use rustc_session::config::nightly_options;
 use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest};
+use rustc_session::getopts;
 use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, DiagnosticOutput, Session};
+use rustc_session::{
+    config, DiagnosticOutput, Session, CFG_RELEASE, CFG_VERSION, CFG_VER_DATE, CFG_VER_HASH,
+};
 use rustc_session::{early_error, early_warn};
 use rustc_span::source_map::{FileLoader, FileName};
 use rustc_span::symbol::sym;
@@ -750,24 +750,24 @@ impl RustcDefaultCalls {
 
 /// Returns a version string such as "0.12.0-dev".
 fn release_str() -> Option<&'static str> {
-    option_env!("CFG_RELEASE")
+    CFG_RELEASE
 }
 
 /// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
 fn commit_hash_str() -> Option<&'static str> {
-    option_env!("CFG_VER_HASH")
+    CFG_VER_HASH
 }
 
 /// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
 fn commit_date_str() -> Option<&'static str> {
-    option_env!("CFG_VER_DATE")
+    CFG_VER_DATE
 }
 
 /// Prints version information
 pub fn version(binary: &str, matches: &getopts::Matches) {
     let verbose = matches.opt_present("verbose");
 
-    println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version"));
+    println!("{} {}", binary, CFG_VERSION.unwrap_or("unknown version"));
 
     if verbose {
         fn unw(x: Option<&str>) -> &str {
@@ -1198,7 +1198,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
         format!("we would appreciate a bug report: {}", bug_report_url).into(),
         format!(
             "rustc {} running on {}",
-            option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+            CFG_VERSION.unwrap_or("unknown_version"),
             config::host_triple()
         )
         .into(),
diff --git a/src/librustc_incremental/build.rs b/src/librustc_incremental/build.rs
deleted file mode 100644
index d230ba91039ad..0000000000000
--- a/src/librustc_incremental/build.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-}
diff --git a/src/librustc_incremental/persist/file_format.rs b/src/librustc_incremental/persist/file_format.rs
index 048a81b81bab3..46a0526fb9274 100644
--- a/src/librustc_incremental/persist/file_format.rs
+++ b/src/librustc_incremental/persist/file_format.rs
@@ -26,7 +26,7 @@ const HEADER_FORMAT_VERSION: u16 = 0;
 /// A version string that hopefully is always different for compiler versions
 /// with different encodings of incremental compilation artifacts. Contains
 /// the Git commit hash.
-const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
+use rustc_session::CFG_VERSION as RUSTC_VERSION;
 
 pub fn write_file_header(stream: &mut Encoder) {
     stream.emit_raw_bytes(FILE_MAGIC);
diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml
index c9d81e51641a8..8ea866d7cab5c 100644
--- a/src/librustc_interface/Cargo.toml
+++ b/src/librustc_interface/Cargo.toml
@@ -10,6 +10,7 @@ path = "lib.rs"
 doctest = false
 
 [dependencies]
+libc = "0.2"
 log = "0.4"
 rayon = { version = "0.3.0", package = "rustc-rayon" }
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs
index ba1e2216ca805..0650d09003486 100644
--- a/src/librustc_interface/lib.rs
+++ b/src/librustc_interface/lib.rs
@@ -6,9 +6,6 @@
 #![feature(generators)]
 #![recursion_limit = "256"]
 
-#[cfg(unix)]
-extern crate libc;
-
 mod callbacks;
 pub mod interface;
 mod passes;
diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs
index b452ccfe33a52..c75f3b279a258 100644
--- a/src/librustc_interface/tests.rs
+++ b/src/librustc_interface/tests.rs
@@ -1,5 +1,3 @@
-extern crate getopts;
-
 use crate::interface::parse_cfgspecs;
 
 use rustc_data_structures::fx::FxHashSet;
@@ -9,6 +7,7 @@ use rustc_session::config::{build_configuration, build_session_options, to_crate
 use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
 use rustc_session::config::{ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
 use rustc_session::config::{Externs, OutputType, OutputTypes, SymbolManglingVersion};
+use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::{build_session, Session};
diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs
index 02bf1aded3bc3..99ce0b2dd9222 100644
--- a/src/librustc_interface/util.rs
+++ b/src/librustc_interface/util.rs
@@ -261,9 +261,9 @@ pub fn rustc_path<'a>() -> Option<&'a Path> {
     static RUSTC_PATH: once_cell::sync::OnceCell<Option<PathBuf>> =
         once_cell::sync::OnceCell::new();
 
-    const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR");
+    let bin_path = option_env!("RUSTC_INSTALL_BINDIR").unwrap_or("bin");
 
-    RUSTC_PATH.get_or_init(|| get_rustc_path_inner(BIN_PATH)).as_ref().map(|v| &**v)
+    RUSTC_PATH.get_or_init(|| get_rustc_path_inner(bin_path)).as_ref().map(|v| &**v)
 }
 
 fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index fcaeaf2e4b07d..f14fc9fc2eba8 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -24,18 +24,28 @@ fn main() {
     build_helper::restore_library_path();
 
     let target = env::var("TARGET").expect("TARGET was not set");
-    let llvm_config = env::var_os("LLVM_CONFIG").map(PathBuf::from).unwrap_or_else(|| {
-        if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
-            let to_test =
-                dir.parent().unwrap().parent().unwrap().join(&target).join("llvm/bin/llvm-config");
-            if Command::new(&to_test).output().is_ok() {
-                return to_test;
+    let llvm_config =
+        env::var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
+            if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
+                let to_test = dir
+                    .parent()
+                    .unwrap()
+                    .parent()
+                    .unwrap()
+                    .join(&target)
+                    .join("llvm/bin/llvm-config");
+                if Command::new(&to_test).output().is_ok() {
+                    return Some(to_test);
+                }
             }
-        }
-        PathBuf::from("llvm-config")
-    });
+            None
+        });
+
+    if let Some(llvm_config) = &llvm_config {
+        println!("cargo:rerun-if-changed={}", llvm_config.display());
+    }
+    let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));
 
-    println!("cargo:rerun-if-changed={}", llvm_config.display());
     println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
 
     // Test whether we're cross-compiling LLVM. This is a pretty rare case
diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml
index a88ccd52e9111..b03e884cdaf7a 100644
--- a/src/librustc_metadata/Cargo.toml
+++ b/src/librustc_metadata/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
 
 [dependencies]
 flate2 = "1.0"
+libc = "0.2"
 log = "0.4"
 memmap = "0.7"
 smallvec = { version = "1.0", features = ["union", "may_dangle"] }
diff --git a/src/librustc_metadata/build.rs b/src/librustc_metadata/build.rs
deleted file mode 100644
index 7d5c58ecea2a1..0000000000000
--- a/src/librustc_metadata/build.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_VERSION");
-    println!("cargo:rerun-if-env-changed=CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
-}
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index 22a2bf280415c..4659be8c195ad 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -10,7 +10,6 @@
 #![feature(stmt_expr_attributes)]
 #![recursion_limit = "256"]
 
-extern crate libc;
 extern crate proc_macro;
 
 #[macro_use]
diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs
index 29a4254d9eec6..d8266a1a4065a 100644
--- a/src/librustc_metadata/rmeta/decoder.rs
+++ b/src/librustc_metadata/rmeta/decoder.rs
@@ -31,7 +31,7 @@ use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::util::common::record_time;
 use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder};
-use rustc_session::Session;
+use rustc_session::{Session, CFG_VIRTUAL_RUST_SOURCE_BASE_DIR};
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{self, hygiene::MacroKind, BytePos, Pos, Span, DUMMY_SP};
@@ -1463,7 +1463,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
     fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
         // Translate the virtual `/rustc/$hash` prefix back to a real directory
         // that should hold actual sources, where possible.
-        let virtual_rust_source_base_dir = option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR")
+        let virtual_rust_source_base_dir = CFG_VIRTUAL_RUST_SOURCE_BASE_DIR
             .map(Path::new)
             .filter(|_| {
                 // Only spend time on further checks if we have what to translate *to*.
diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs
index 71872d53a56e7..cddc65832223a 100644
--- a/src/librustc_metadata/rmeta/mod.rs
+++ b/src/librustc_metadata/rmeta/mod.rs
@@ -18,6 +18,7 @@ use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::CrateDisambiguator;
+use rustc_session::CFG_VERSION;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::Symbol;
 use rustc_span::{self, Span};
@@ -34,7 +35,7 @@ mod encoder;
 mod table;
 
 crate fn rustc_version() -> String {
-    format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version"))
+    format!("rustc {}", CFG_VERSION.unwrap_or("unknown version"))
 }
 
 /// Metadata encoding version.
diff --git a/src/librustc_middle/build.rs b/src/librustc_middle/build.rs
index af7723aea34e4..6754f963011d1 100644
--- a/src/librustc_middle/build.rs
+++ b/src/librustc_middle/build.rs
@@ -2,8 +2,6 @@ use std::env;
 
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
-    println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE");
-    println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE");
     println!("cargo:rerun-if-env-changed=RUSTC_VERIFY_LLVM_IR");
 
     if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
diff --git a/src/librustc_middle/middle/stability.rs b/src/librustc_middle/middle/stability.rs
index 46525bdedad35..d16e08afdd831 100644
--- a/src/librustc_middle/middle/stability.rs
+++ b/src/librustc_middle/middle/stability.rs
@@ -16,6 +16,7 @@ use rustc_hir::{self, HirId};
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
 use rustc_session::lint::{BuiltinLintDiagnostics, Lint, LintBuffer};
 use rustc_session::parse::feature_err_issue;
+use rustc_session::CFG_RELEASE;
 use rustc_session::{DiagnosticMessageId, Session};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{MultiSpan, Span};
@@ -136,7 +137,7 @@ pub fn deprecation_in_effect(since: &str) -> bool {
         ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
     }
 
-    if let Some(rustc) = option_env!("CFG_RELEASE") {
+    if let Some(rustc) = CFG_RELEASE {
         let since: Vec<u32> = parse_version(since);
         let rustc: Vec<u32> = parse_version(rustc);
         // We simply treat invalid `since` attributes as relating to a previous
diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml
index 3895d0f8061c0..1f53846717a46 100644
--- a/src/librustc_session/Cargo.toml
+++ b/src/librustc_session/Cargo.toml
@@ -9,6 +9,7 @@ name = "rustc_session"
 path = "lib.rs"
 
 [dependencies]
+getopts = "0.2"
 log = "0.4"
 rustc_errors = { path = "../librustc_errors" }
 rustc_feature = { path = "../librustc_feature" }
@@ -20,3 +21,6 @@ rustc_index = { path = "../librustc_index" }
 rustc_fs_util = { path = "../librustc_fs_util" }
 num_cpus = "1.0"
 rustc_ast = { path = "../librustc_ast" }
+
+[build-dependencies]
+build_helper = { path = "../build_helper" }
diff --git a/src/librustc_session/build.rs b/src/librustc_session/build.rs
new file mode 100644
index 0000000000000..c578010b987be
--- /dev/null
+++ b/src/librustc_session/build.rs
@@ -0,0 +1,211 @@
+use build_helper::set_env;
+use std::error::Error;
+use std::ffi::OsString;
+use std::path::Path;
+use std::process::Command;
+
+fn output(cmd: &mut Command) -> Result<String, Box<dyn Error>> {
+    Ok(String::from_utf8(cmd.output()?.stdout)?.trim().into())
+}
+
+fn default_build_triple() -> Result<String, Box<dyn Error>> {
+    let ostype = output(Command::new("uname").arg("-s"));
+    let cputype = output(Command::new("uname").arg("-m"));
+    let (ostype, cputype) = match (ostype, cputype) {
+        (Ok(ostype), Ok(cputype)) => (ostype, cputype),
+        (ostype, cputype) => {
+            if cfg!(windows) {
+                return Ok("x86_64-pc-windows-msvc".into());
+            } else {
+                return ostype.and(cputype);
+            }
+        }
+    };
+
+    let mut cputype = cputype;
+    let ostype = match ostype.as_str() {
+        "Darwin" => "apple-darwin",
+        "DragonFly" => "unknown-dragonfly",
+        "FreeBSD" => "unknown-freebsd",
+        "Haiku" => "unknown-haiku",
+        "NetBSD" => "unknown-netbsd",
+        "OpenBSD" => "unknown-openbsd",
+        "Linux" => match output(Command::new("uname").arg("-o"))?.as_str() {
+            "Android" => "linux-android",
+            _ => "unknown-linux-gnu",
+        },
+        "SunOS" => {
+            cputype = output(Command::new("isainfo").arg("-k"))?;
+            "sun-solaris"
+        }
+        ostype if ostype.starts_with("MINGW") => {
+            cputype = if std::env::var("MSYSTEM").map(|x| x == "MINGW64").unwrap_or_default() {
+                "x86_64"
+            } else {
+                "i686"
+            }
+            .into();
+            "pc-windows-gnu"
+        }
+        ostype if ostype.starts_with("MSYS") => "pc-windows-gnu",
+        ostype if ostype.starts_with("CYGWIN_NT") => {
+            cputype = if ostype.ends_with("WOW64") { "x86_64" } else { "i686" }.into();
+            "pc-windows-gnu"
+        }
+        _ => {
+            return Err(format!("unknown OS type: {}", ostype).into());
+        }
+    };
+
+    if cputype == "powerpc" && ostype == "unknown-freebsd" {
+        cputype = output(Command::new("uname").arg("-p"))?;
+    }
+
+    let mut ostype: String = ostype.into();
+    let mut set_cputype_from_uname_p = false;
+    match cputype.as_str() {
+        "BePC" => "i686",
+        "aarch64" => "aarch64",
+        "amd64" => "x86_64",
+        "arm64" => "aarch64",
+        "i386" => "i686",
+        "i486" => "i686",
+        "i686" => "i686",
+        "i786" => "i686",
+        "powerpc" => "powerpc",
+        "powerpc64" => "powerpc64",
+        "powerpc64le" => "powerpc64le",
+        "ppc" => "powerpc",
+        "ppc64" => "powerpc64",
+        "ppc64le" => "powerpc64le",
+        "s390x" => "s390x",
+        "x64" => "x86_64",
+        "x86" => "i686",
+        "x86-64" => "x86_64",
+        "x86_64" => "x86_64",
+        "xscale" | "arm" => match ostype.as_str() {
+            "linux-android" => {
+                ostype = "linux-androideabi".into();
+                "arm"
+            }
+            "unknown-freebsd" => {
+                ostype = "unknown-freebsd".into();
+                set_cputype_from_uname_p = true;
+                ""
+            }
+            _ => cputype.as_str(),
+        },
+        "armv6l" => {
+            match ostype.as_str() {
+                "linux-android" => {
+                    ostype = "linux-androideabi".into();
+                }
+                _ => {
+                    ostype += "eabihf";
+                }
+            };
+            "arm"
+        }
+        "armv7l" | "armv8l" => {
+            match ostype.as_str() {
+                "linux-android" => {
+                    ostype = "linux-androideabi".into();
+                }
+                _ => {
+                    ostype += "eabihf";
+                }
+            };
+            "armv7"
+        }
+        "mips" => {
+            if cfg!(target_endian = "big") {
+                "mips"
+            } else {
+                "mipsel"
+            }
+        }
+        "mips64" => {
+            ostype += "abi64";
+            if cfg!(target_endian = "big") { "mips64" } else { "mips64el" }
+        }
+        "sparc" => "sparc",
+        "sparcv9" => "sparcv9",
+        "sparc64" => "sparc64",
+        _ => {
+            return Err(format!("unknown cpu type: {}", cputype).into());
+        }
+    };
+    let cputype = if set_cputype_from_uname_p {
+        output(Command::new("uname").arg("-p"))?
+    } else {
+        cputype.into()
+    };
+
+    Ok(format!("{}-{}", cputype, ostype))
+}
+
+fn get_rustc_sysroot() -> Result<String, Box<dyn Error>> {
+    Ok(String::from_utf8(
+        Command::new(std::env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc")))
+            .arg("--print=sysroot")
+            .output()?
+            .stdout,
+    )?
+    .trim()
+    .into())
+}
+
+fn main() {
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-env-changed=CFG_RELEASE");
+    println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
+    println!("cargo:rerun-if-env-changed=CFG_VERSION");
+    println!("cargo:rerun-if-env-changed=CFG_VER_DATE");
+    println!("cargo:rerun-if-env-changed=CFG_VER_HASH");
+    println!("cargo:rerun-if-env-changed=CFG_PREFIX");
+    println!("cargo:rerun-if-env-changed=CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
+    println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE");
+    println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE");
+    println!("cargo:rerun-if-env-changed=RUSTC_STAGE");
+
+    if let Some(rustc) = build_helper::build_rustc() {
+        let mut rust_info_data = None;
+        let rust_info = || build_helper::channel::GitInfo::new(false, Path::new("../.."));
+        let rustc = &rustc;
+        set_env("CFG_RELEASE", || rustc.version.release.as_ref().map(|x| x.into()));
+        set_env("CFG_VERSION", || rustc.version.version.as_ref().map(|x| x.into()));
+        set_env("CFG_RELEASE_CHANNEL", || {
+            rustc
+                .version
+                .release
+                .as_ref()
+                .and_then(|release| release.rsplitn(2, "-").next().map(|x| x.into()))
+        });
+        set_env("CFG_VER_HASH", || {
+            rust_info_data.get_or_insert_with(|| rust_info()).sha().map(|x| x.into())
+        });
+        set_env("CFG_VER_DATE", || {
+            rust_info_data.get_or_insert_with(|| rust_info()).commit_date().map(|x| x.into())
+        });
+    }
+
+    if std::env::var_os("CFG_COMPILER_HOST_TRIPLE").is_none() {
+        println!(
+            "cargo:rustc-env=CFG_COMPILER_HOST_TRIPLE={}",
+            default_build_triple().expect("Unable to determine build triple not found")
+        )
+    };
+
+    if std::env::var_os("RUSTC_STAGE").is_none() {
+        match get_rustc_sysroot() {
+            Ok(sysroot) => println!("cargo:rustc-env=CFG_DEFAULT_SYSROOT={}", sysroot),
+            Err(err) => {
+                println!("\"
+                    cargo:warning=ERROR: unable to get rustc sysroot: {}\n\
+                    cargo:warning=You will need to pass --sysroot= manually to the compiler that will be built",
+                    err
+                );
+            }
+        };
+    }
+}
diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs
index 4e2423bc3b114..070c303ba06a0 100644
--- a/src/librustc_session/config.rs
+++ b/src/librustc_session/config.rs
@@ -540,7 +540,7 @@ pub fn host_triple() -> &'static str {
     // Instead of grabbing the host triple (for the current host), we grab (at
     // compile time) the target triple that this rustc is built with and
     // calling that (at runtime) the host triple.
-    (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
+    option_env!("CFG_COMPILER_HOST_TRIPLE").expect("CFG_COMPILER_HOST_TRIPLE")
 }
 
 impl Default for Options {
diff --git a/src/librustc_session/filesearch.rs b/src/librustc_session/filesearch.rs
index e98746231fb30..37b5e7666b781 100644
--- a/src/librustc_session/filesearch.rs
+++ b/src/librustc_session/filesearch.rs
@@ -125,7 +125,7 @@ pub fn get_or_default_sysroot() -> PathBuf {
         })
     }
 
-    match env::current_exe() {
+    let mut sysroot = match env::current_exe() {
         Ok(exe) => match canonicalize(Some(exe)) {
             Some(mut p) => {
                 p.pop();
@@ -135,7 +135,15 @@ pub fn get_or_default_sysroot() -> PathBuf {
             None => panic!("can't determine value for sysroot"),
         },
         Err(ref e) => panic!(format!("failed to get current_exe: {}", e)),
+    };
+
+    if let Some(default_sysroot) = option_env!("CFG_DEFAULT_SYSROOT") {
+        if !Path::new(&*find_libdir(&sysroot)).exists() {
+            sysroot = PathBuf::from(default_sysroot);
+        }
     }
+
+    sysroot
 }
 
 // The name of the directory rustc expects libraries to be located.
diff --git a/src/librustc_session/lib.rs b/src/librustc_session/lib.rs
index cc4d525d62887..528100a00535c 100644
--- a/src/librustc_session/lib.rs
+++ b/src/librustc_session/lib.rs
@@ -3,7 +3,6 @@
 
 // Use the test crate here so we depend on getopts through it. This allow tools to link to both
 // librustc_session and libtest.
-extern crate getopts;
 extern crate test as _;
 
 pub mod cgu_reuse_tracker;
@@ -23,3 +22,5 @@ mod session;
 pub use session::*;
 
 pub mod output;
+
+pub use getopts;
diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs
index 1c5d19db49cdc..f05f5ccf67e56 100644
--- a/src/librustc_session/session.rs
+++ b/src/librustc_session/session.rs
@@ -32,6 +32,16 @@ use std::path::PathBuf;
 use std::sync::Arc;
 use std::time::Duration;
 
+pub static CFG_VERSION: Option<&str> = option_env!("CFG_VERSION");
+pub static CFG_RELEASE: Option<&str> = option_env!("CFG_RELEASE");
+pub static CFG_RELEASE_CHANNEL: Option<&str> = option_env!("CFG_RELEASE_CHANNEL");
+pub static CFG_VER_HASH: Option<&str> = option_env!("CFG_VER_HASH");
+pub static CFG_VER_DATE: Option<&str> = option_env!("CFG_VER_DATE");
+
+pub static CFG_PREFIX: Option<&str> = option_env!("CFG_PREFIX");
+pub static CFG_VIRTUAL_RUST_SOURCE_BASE_DIR: Option<&str> =
+    option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
+
 pub struct OptimizationFuel {
     /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`.
     remaining: u64,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index eebc34d3db8ea..ab216412f1086 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -128,7 +128,7 @@ use rustc_middle::ty::{
 use rustc_session::config::{self, EntryFnType};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
-use rustc_session::Session;
+use rustc_session::{Session, CFG_VERSION};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{original_sp, DUMMY_SP};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -5806,7 +5806,7 @@ fn fatally_break_rust(sess: &Session) {
     );
     handler.note_without_error(&format!(
         "rustc {} running on {}",
-        option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+        CFG_VERSION.unwrap_or("unknown_version"),
         config::host_triple(),
     ));
 }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 179c5bfacf32e..a5a1e20396caf 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -10,6 +10,7 @@ use rustc_session::config::{
     nightly_options,
 };
 use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
+use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 99860a103d78f..b0d5a8e58e120 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -15,7 +15,6 @@
 #![recursion_limit = "256"]
 
 extern crate env_logger;
-extern crate getopts;
 extern crate rustc_ast;
 extern crate rustc_ast_pretty;
 extern crate rustc_attr;
@@ -51,6 +50,7 @@ use std::panic;
 use std::process;
 
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
+use rustc_session::getopts;
 use rustc_session::{early_error, early_warn};
 
 #[macro_use]
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 3a83f3f569a26..16b746e59e937 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -34,6 +34,9 @@ features = [ "rustc-dep-of-std" ] # enable build support for integrating into li
 [dev-dependencies]
 rand = "0.7"
 
+[build-dependencies]
+build_helper = { path = "../build_helper" }
+
 [target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
 dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
 
@@ -47,7 +50,7 @@ hermit-abi = { version = "0.1.10", features = ['rustc-dep-of-std'] }
 wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
 
 [features]
-default = ["std_detect_file_io", "std_detect_dlsym_getauxval"]
+default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"]
 
 backtrace = [
   "backtrace_rs/dbghelp",          # backtrace/symbolize on MSVC
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 8db7bc12cd308..e6d4ecc9c0952 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -1,6 +1,8 @@
 use std::env;
 
 fn main() {
+    build_helper::build_stdlib(false);
+
     let target = env::var("TARGET").expect("TARGET was not set");
     if target.contains("linux") {
         if target.contains("android") {
diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml
index 5e0f167bb3801..8a887f88d999f 100644
--- a/src/rustc/Cargo.toml
+++ b/src/rustc/Cargo.toml
@@ -21,5 +21,6 @@ optional = true
 features = ['unprefixed_malloc_on_supported_platforms']
 
 [features]
+default = ['llvm']
 jemalloc = ['jemalloc-sys']
 llvm = ['rustc_driver/llvm']