Description: Support linking against system clang libs
 Note: the above PR only covers the compiler_builtins crate, rustc itself also
 needs patching as per below once that is accepted.
Forwarded: https://github.com/rust-lang-nursery/compiler-builtins/pull/296
--- a/vendor/compiler_builtins/Cargo.toml
+++ b/vendor/compiler_builtins/Cargo.toml
@@ -43,7 +43,13 @@
 optional = true
 
 [features]
-c = ["cc"]
+c-vendor = ["cc"]
+
+# Link against system clang_rt.* libraries.
+# LLVM_CONFIG or CLANG (more reliable) must be set.
+c-system = []
+
+c = ["c-vendor"]
 compiler-builtins = []
 default = ["compiler-builtins"]
 mangled-names = []
--- a/vendor/compiler_builtins/build.rs
+++ b/vendor/compiler_builtins/build.rs
@@ -37,7 +37,7 @@
     // mangling names though we assume that we're also in test mode so we don't
     // build anything and we rely on the upstream implementation of compiler-rt
     // functions
-    if !cfg!(feature = "mangled-names") && cfg!(feature = "c") {
+    if !cfg!(feature = "mangled-names") && cfg!(any(feature = "c-vendor", feature = "c-system")) {
         // Don't use a C compiler for these targets:
         //
         // * wasm32 - clang 8 for wasm is somewhat hard to come by and it's
@@ -47,8 +47,10 @@
         //   compiler nor is cc-rs ready for compilation to riscv (at this
         //   time). This can probably be removed in the future
         if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") {
-            #[cfg(feature = "c")]
-            c::compile(&llvm_target);
+            #[cfg(feature = "c-vendor")]
+            c_vendor::compile(&llvm_target);
+            #[cfg(feature = "c-system")]
+            c_system::compile(&llvm_target);
         }
     }
 
@@ -70,17 +72,14 @@
     }
 }
 
-#[cfg(feature = "c")]
-mod c {
-    extern crate cc;
-
+#[cfg(any(feature = "c-vendor", feature = "c-system"))]
+mod sources {
     use std::collections::BTreeMap;
     use std::env;
-    use std::path::PathBuf;
 
-    struct Sources {
+    pub struct Sources {
         // SYMBOL -> PATH TO SOURCE
-        map: BTreeMap<&'static str, &'static str>,
+        pub map: BTreeMap<&'static str, &'static str>,
     }
 
     impl Sources {
@@ -117,39 +116,11 @@
         }
     }
 
-    /// Compile intrinsics from the compiler-rt C source code
-    pub fn compile(llvm_target: &[&str]) {
+    pub fn get_sources(llvm_target: &[&str]) -> Sources {
         let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
         let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
         let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
         let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
-        let cfg = &mut cc::Build::new();
-
-        cfg.warnings(false);
-
-        if target_env == "msvc" {
-            // Don't pull in extra libraries on MSVC
-            cfg.flag("/Zl");
-
-            // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
-            cfg.define("__func__", Some("__FUNCTION__"));
-        } else {
-            // Turn off various features of gcc and such, mostly copying
-            // compiler-rt's build system already
-            cfg.flag("-fno-builtin");
-            cfg.flag("-fvisibility=hidden");
-            cfg.flag("-ffreestanding");
-            // Avoid the following warning appearing once **per file**:
-            // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument]
-            //
-            // Note that compiler-rt's build system also checks
-            //
-            // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)`
-            //
-            // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19.
-            cfg.flag_if_supported("-fomit-frame-pointer");
-            cfg.define("VISIBILITY_HIDDEN", None);
-        }
 
         let mut sources = Sources::new();
         sources.extend(&[
@@ -411,6 +382,48 @@
             sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]);
         }
 
+        sources
+    }
+}
+
+#[cfg(feature = "c-vendor")]
+mod c_vendor {
+    extern crate cc;
+
+    use std::env;
+    use std::path::PathBuf;
+    use sources;
+
+    /// Compile intrinsics from the compiler-rt C source code
+    pub fn compile(llvm_target: &[&str]) {
+        let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
+        let cfg = &mut cc::Build::new();
+        cfg.warnings(false);
+
+        if target_env == "msvc" {
+            // Don't pull in extra libraries on MSVC
+            cfg.flag("/Zl");
+
+            // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP
+            cfg.define("__func__", Some("__FUNCTION__"));
+        } else {
+            // Turn off various features of gcc and such, mostly copying
+            // compiler-rt's build system already
+            cfg.flag("-fno-builtin");
+            cfg.flag("-fvisibility=hidden");
+            cfg.flag("-ffreestanding");
+            // Avoid the following warning appearing once **per file**:
+            // clang: warning: optimization flag '-fomit-frame-pointer' is not supported for target 'armv7' [-Wignored-optimization-argument]
+            //
+            // Note that compiler-rt's build system also checks
+            //
+            // `check_cxx_compiler_flag(-fomit-frame-pointer COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG)`
+            //
+            // in https://github.com/rust-lang/compiler-rt/blob/c8fbcb3/cmake/config-ix.cmake#L19.
+            cfg.flag_if_supported("-fomit-frame-pointer");
+            cfg.define("VISIBILITY_HIDDEN", None);
+        }
+
         // When compiling the C code we require the user to tell us where the
         // source code is, and this is largely done so when we're compiling as
         // part of rust-lang/rust we can use the same llvm-project repository as
@@ -423,6 +436,7 @@
             panic!("RUST_COMPILER_RT_ROOT={} does not exist", root.display());
         }
 
+        let sources = sources::get_sources(llvm_target);
         let src_dir = root.join("lib/builtins");
         for (sym, src) in sources.map.iter() {
             let src = src_dir.join(src);
@@ -434,3 +448,103 @@
         cfg.compile("libcompiler-rt.a");
     }
 }
+
+#[cfg(feature = "c-system")]
+mod c_system {
+    use std::env;
+    use std::process::{Command, Output};
+    use std::str;
+    use std::path::Path;
+    use sources;
+
+    fn success_output(err: &str, cmd: &mut Command) -> Output {
+        let output = cmd.output().expect(err);
+        let status = output.status;
+        if !status.success() {
+            panic!("{}: {:?}", err, status.code());
+        }
+        output
+    }
+
+    // This can be obtained by adding the line:
+    //   message(STATUS "All builtin supported architectures: ${ALL_BUILTIN_SUPPORTED_ARCH}")
+    // to the bottom of compiler-rt/cmake/builtin-config-ix.cmake, then running
+    // cmake and looking at the output.
+    const ALL_SUPPORTED_ARCHES : &'static str = "i386;x86_64;arm;armhf;armv6m;armv7m;armv7em;armv7;armv7s;armv7k;aarch64;hexagon;mips;mipsel;mips64;mips64el;powerpc64;powerpc64le;riscv32;riscv64;wasm32;wasm64";
+
+    // This function recreates the logic of getArchNameForCompilerRTLib,
+    // defined in clang/lib/Driver/ToolChain.cpp.
+    fn get_arch_name_for_compiler_rtlib() -> String {
+        let target = env::var("TARGET").unwrap();
+        let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
+        let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
+        let r = match target_arch.as_str() {
+            "arm" => if target.ends_with("eabihf") && target_os != "windows" {
+                "armhf"
+            } else {
+                "arm"
+            },
+            "x86" => if target_os == "android" {
+                "i686"
+            } else {
+                "i386"
+            },
+            _ => target_arch.as_str(),
+        };
+        r.to_string()
+    }
+
+    /// Link against system clang runtime libraries
+    pub fn compile(llvm_target: &[&str]) {
+        let target = env::var("TARGET").unwrap();
+        let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
+        let compiler_rt_arch = get_arch_name_for_compiler_rtlib();
+
+        if ALL_SUPPORTED_ARCHES.split(";").find(|x| *x == compiler_rt_arch) == None {
+            return;
+        }
+
+        if let Ok(clang) = env::var("CLANG") {
+            let output = success_output(
+                "failed to find clang's compiler-rt",
+                Command::new(clang)
+                    .arg(format!("--target={}", target))
+                    .arg("--rtlib=compiler-rt")
+                    .arg("--print-libgcc-file-name"),
+            );
+            let fullpath = Path::new(str::from_utf8(&output.stdout).unwrap());
+            let libpath = fullpath.parent().unwrap().display();
+            let libname = fullpath
+                .file_stem()
+                .unwrap()
+                .to_str()
+                .unwrap()
+                .trim_start_matches("lib");
+            println!("cargo:rustc-link-search=native={}", libpath);
+            println!("cargo:rustc-link-lib=static={}", libname);
+        } else if let Ok(llvm_config) = env::var("LLVM_CONFIG") {
+            // fallback if clang is not installed
+            let (subpath, libname) = match target_os.as_str() {
+                "linux" => ("linux", format!("clang_rt.builtins-{}", &compiler_rt_arch)),
+                "macos" => ("darwin", "clang_rt.builtins_osx_dynamic".to_string()),
+                _ => panic!("unsupported target os: {}", target_os),
+            };
+            let cmd = format!("ls -1d $({} --libdir)/clang/*/lib/{}", llvm_config, subpath);
+            let output = success_output(
+                "failed to find clang's lib dir",
+                Command::new("sh").args(&["-ec", &cmd]),
+            );
+            for search_dir in str::from_utf8(&output.stdout).unwrap().lines() {
+                println!("cargo:rustc-link-search=native={}", search_dir);
+            }
+            println!("cargo:rustc-link-lib=static={}", libname);
+        } else {
+            panic!("neither CLANG nor LLVM_CONFIG could be read");
+        }
+
+        let sources = sources::get_sources(llvm_target);
+        for (sym, _src) in sources.map.iter() {
+            println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
+        }
+    }
+}
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -213,6 +213,7 @@
                 emscripten: false,
             });
             cargo.env("LLVM_CONFIG", llvm_config);
+            cargo.env("RUSTC_BUILD_SANITIZERS", "1");
         }
 
         cargo.arg("--features").arg(features)
--- a/src/librustc_asan/build.rs
+++ b/src/librustc_asan/build.rs
@@ -4,6 +4,9 @@
 use cmake::Config;
 
 fn main() {
+    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
+        return;
+    }
     if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
         build_helper::restore_library_path();
 
--- a/src/librustc_lsan/build.rs
+++ b/src/librustc_lsan/build.rs
@@ -4,6 +4,9 @@
 use cmake::Config;
 
 fn main() {
+    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
+        return;
+    }
     if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
         build_helper::restore_library_path();
 
--- a/src/librustc_msan/build.rs
+++ b/src/librustc_msan/build.rs
@@ -4,6 +4,9 @@
 use cmake::Config;
 
 fn main() {
+    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
+        return;
+    }
     if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
         build_helper::restore_library_path();
 
--- a/src/librustc_tsan/build.rs
+++ b/src/librustc_tsan/build.rs
@@ -4,6 +4,9 @@
 use cmake::Config;
 
 fn main() {
+    if env::var("RUSTC_BUILD_SANITIZERS") != Ok("1".to_string()) {
+        return;
+    }
     if let Some(llvm_config) = env::var_os("LLVM_CONFIG") {
         build_helper::restore_library_path();
 
