diff --git a/config.toml.example b/config.toml.example index a2f64e6b70588..f50543e18a764 100644 --- a/config.toml.example +++ b/config.toml.example @@ -300,7 +300,7 @@ # ============================================================================= [target.x86_64-unknown-linux-gnu] -# C compiler to be used to compiler C code and link Rust code. Note that the +# C compiler to be used to compiler C code. Note that the # default value is platform specific, and if not specified it may also depend on # what platform is crossing to what platform. #cc = "cc" @@ -309,6 +309,15 @@ # This is only used for host targets. #cxx = "c++" +# Archiver to be used to assemble static libraries compiled from C/C++ code. +# Note: an absolute path should be used, otherwise LLVM build will break. +#ar = "ar" + +# Linker to be used to link Rust code. Note that the +# default value is platform specific, and if not specified it may also depend on +# what platform is crossing to what platform. +#linker = "cc" + # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specifed we don't compile LLVM at all for this # target. diff --git a/src/Cargo.lock b/src/Cargo.lock index aa5e262e85ff1..2b95be27ffea7 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1994,7 +1994,6 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index e91acb21dac99..aeeda85e924ef 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -120,10 +120,9 @@ fn main() { cmd.arg("-L").arg(&root); } - // Pass down extra flags, commonly used to configure `-Clinker` when - // cross compiling. - if let Ok(s) = env::var("RUSTC_FLAGS") { - cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::>()); + // Override linker if necessary. + if let Ok(target_linker) = env::var("RUSTC_TARGET_LINKER") { + cmd.arg(format!("-Clinker={}", target_linker)); } // Pass down incremental directory, if any. @@ -252,6 +251,11 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } + } else { + // Override linker if necessary. + if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { + cmd.arg(format!("-Clinker={}", host_linker)); + } } let color = match env::var("RUSTC_COLOR") { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index d18512b257d6a..4e975adc9721c 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -47,6 +47,9 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } + if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { + cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + } // Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick // it up so we can make rustdoc print this into the docs diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 1d63e112ca6fb..6480b5a619c03 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -413,13 +413,15 @@ impl<'a> Builder<'a> { pub fn rustdoc_cmd(&self, host: Interned) -> Command { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); let compiler = self.compiler(self.top_stage, host); - cmd - .env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) - .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(host)) - .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + cmd.env("RUSTC_STAGE", compiler.stage.to_string()) + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) + .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) + .env("RUSTDOC_REAL", self.rustdoc(host)) + .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + if let Some(linker) = self.build.linker(host) { + cmd.env("RUSTC_TARGET_LINKER", linker); + } cmd } @@ -482,8 +484,14 @@ impl<'a> Builder<'a> { } else { PathBuf::from("/path/to/nowhere/rustdoc/not/required") }) - .env("TEST_MIRI", self.config.test_miri.to_string()) - .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + .env("TEST_MIRI", self.config.test_miri.to_string()); + + if let Some(host_linker) = self.build.linker(compiler.host) { + cargo.env("RUSTC_HOST_LINKER", host_linker); + } + if let Some(target_linker) = self.build.linker(target) { + cargo.env("RUSTC_TARGET_LINKER", target_linker); + } if mode != Mode::Tool { // Tools don't get debuginfo right now, e.g. cargo and rls don't @@ -557,17 +565,35 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); - // Specify some various options for build scripts used throughout - // the build. + // Throughout the build Cargo can execute a number of build scripts + // compiling C/C++ code and we need to pass compilers, archivers, flags, etc + // obtained previously to those build scripts. + // Build scripts use either the `cc` crate or `configure/make` so we pass + // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here if !target.contains("msvc") { - cargo.env(format!("CC_{}", target), self.cc(target)) - .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None - .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); + let cc = self.cc(target); + cargo.env(format!("CC_{}", target), cc) + .env("CC", cc); + + let cflags = self.cflags(target).join(" "); + cargo.env(format!("CFLAGS_{}", target), cflags.clone()) + .env("CFLAGS", cflags.clone()); + + if let Some(ar) = self.ar(target) { + let ranlib = format!("{} s", ar.display()); + cargo.env(format!("AR_{}", target), ar) + .env("AR", ar) + .env(format!("RANLIB_{}", target), ranlib.clone()) + .env("RANLIB", ranlib); + } if let Ok(cxx) = self.cxx(target) { - cargo.env(format!("CXX_{}", target), cxx); + cargo.env(format!("CXX_{}", target), cxx) + .env("CXX", cxx) + .env(format!("CXXFLAGS_{}", target), cflags.clone()) + .env("CXXFLAGS", cflags); } } diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 08df65c761182..6e3e3c920291d 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -31,20 +31,51 @@ //! ever be probed for. Instead the compilers found here will be used for //! everything. +use std::collections::HashSet; +use std::{env, iter}; +use std::path::{Path, PathBuf}; use std::process::Command; -use std::iter; -use build_helper::{cc2ar, output}; +use build_helper::output; use cc; use Build; use config::Target; use cache::Interned; +// The `cc` crate doesn't provide a way to obtain a path to the detected archiver, +// so use some simplified logic here. First we respect the environment variable `AR`, then +// try to infer the archiver path from the C compiler path. +// In the future this logic should be replaced by calling into the `cc` crate. +fn cc2ar(cc: &Path, target: &str) -> Option { + if let Some(ar) = env::var_os("AR") { + Some(PathBuf::from(ar)) + } else if target.contains("msvc") { + None + } else if target.contains("musl") { + Some(PathBuf::from("ar")) + } else if target.contains("openbsd") { + Some(PathBuf::from("ar")) + } else { + let parent = cc.parent().unwrap(); + let file = cc.file_name().unwrap().to_str().unwrap(); + for suffix in &["gcc", "cc", "clang"] { + if let Some(idx) = file.rfind(suffix) { + let mut file = file[..idx].to_owned(); + file.push_str("ar"); + return Some(parent.join(&file)); + } + } + Some(parent.join(file)) + } +} + pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) { + let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) + .collect::>(); + for target in targets.into_iter() { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false) .target(&target).host(&build.build); @@ -57,16 +88,23 @@ pub fn find(build: &mut Build) { } let compiler = cfg.get_compiler(); - let ar = cc2ar(compiler.path(), &target); + let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { + ar + } else { + cc2ar(compiler.path(), &target) + }; + build.verbose(&format!("CC_{} = {:?}", &target, compiler.path())); - if let Some(ref ar) = ar { + build.cc.insert(target, compiler); + if let Some(ar) = ar { build.verbose(&format!("AR_{} = {:?}", &target, ar)); + build.ar.insert(target, ar); } - build.cc.insert(target, (compiler, ar)); } // For all host triples we need to find a C++ compiler as well - for host in build.hosts.iter().cloned().chain(iter::once(build.build)) { + let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::>(); + for host in hosts.into_iter() { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true) .target(&host).host(&build.build); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index fb32ab0cb862d..d9ee63eef8cdd 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -747,12 +747,14 @@ impl Step for Compiletest { flags.push("-g".to_string()); } - let mut hostflags = build.rustc_flags(compiler.host); - hostflags.extend(flags.clone()); + if let Some(linker) = build.linker(target) { + cmd.arg("--linker").arg(linker); + } + + let hostflags = flags.clone(); cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); - let mut targetflags = build.rustc_flags(target); - targetflags.extend(flags); + let mut targetflags = flags.clone(); targetflags.push(format!("-Lnative={}", build.test_helpers_out(target).display())); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); @@ -806,6 +808,9 @@ impl Step for Compiletest { .arg("--cflags").arg(build.cflags(target).join(" ")) .arg("--llvm-components").arg(llvm_components.trim()) .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + if let Some(ar) = build.ar(target) { + cmd.arg("--ar").arg(ar); + } } } if suite == "run-make" && !build.config.llvm_enabled { @@ -831,7 +836,7 @@ impl Step for Compiletest { // Note that if we encounter `PATH` we make sure to append to our own `PATH` // rather than stomp over it. if target.contains("msvc") { - for &(ref k, ref v) in build.cc[&target].0.env() { + for &(ref k, ref v) in build.cc[&target].env() { if k != "PATH" { cmd.env(k, v); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5fb5eb3b7f1a5..69e0f58f1cd06 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -143,6 +143,8 @@ pub struct Target { pub jemalloc: Option, pub cc: Option, pub cxx: Option, + pub ar: Option, + pub linker: Option, pub ndk: Option, pub crt_static: Option, pub musl_root: Option, @@ -282,6 +284,8 @@ struct TomlTarget { jemalloc: Option, cc: Option, cxx: Option, + ar: Option, + linker: Option, android_ndk: Option, crt_static: Option, musl_root: Option, @@ -484,8 +488,10 @@ impl Config { if let Some(ref s) = cfg.android_ndk { target.ndk = Some(env::current_dir().unwrap().join(s)); } - target.cxx = cfg.cxx.clone().map(PathBuf::from); target.cc = cfg.cc.clone().map(PathBuf::from); + target.cxx = cfg.cxx.clone().map(PathBuf::from); + target.ar = cfg.ar.clone().map(PathBuf::from); + target.linker = cfg.linker.clone().map(PathBuf::from); target.crt_static = cfg.crt_static.clone(); target.musl_root = cfg.musl_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2d721f455785a..6ac919d3fbdda 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -240,10 +240,11 @@ pub struct Build { lldb_python_dir: Option, // Runtime state filled in later on - // target -> (cc, ar) - cc: HashMap, (cc::Tool, Option)>, - // host -> (cc, ar) + // C/C++ compilers and archiver for all targets + cc: HashMap, cc::Tool>, cxx: HashMap, cc::Tool>, + ar: HashMap, PathBuf>, + // Misc crates: HashMap, Crate>, is_sudo: bool, ci_env: CiEnv, @@ -324,6 +325,7 @@ impl Build { rls_info, cc: HashMap::new(), cxx: HashMap::new(), + ar: HashMap::new(), crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, @@ -612,7 +614,7 @@ impl Build { /// Returns the path to the C compiler for the target specified. fn cc(&self, target: Interned) -> &Path { - self.cc[&target].0.path() + self.cc[&target].path() } /// Returns a list of flags to pass to the C compiler for the target @@ -620,7 +622,7 @@ impl Build { fn cflags(&self, target: Interned) -> Vec { // Filter out -O and /O (the optimization flags) that we picked up from // cc-rs because the build scripts will determine that for themselves. - let mut base = self.cc[&target].0.args().iter() + let mut base = self.cc[&target].args().iter() .map(|s| s.to_string_lossy().into_owned()) .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) .collect::>(); @@ -644,7 +646,7 @@ impl Build { /// Returns the path to the `ar` archive utility for the target specified. fn ar(&self, target: Interned) -> Option<&Path> { - self.cc[&target].1.as_ref().map(|p| &**p) + self.ar.get(&target).map(|p| &**p) } /// Returns the path to the C++ compiler for the target specified. @@ -657,21 +659,17 @@ impl Build { } } - /// Returns flags to pass to the compiler to generate code for `target`. - fn rustc_flags(&self, target: Interned) -> Vec { - // New flags should be added here with great caution! - // - // It's quite unfortunate to **require** flags to generate code for a - // target, so it should only be passed here if absolutely necessary! - // Most default configuration should be done through target specs rather - // than an entry here. - - let mut base = Vec::new(); - if target != self.config.build && !target.contains("msvc") && - !target.contains("emscripten") { - base.push(format!("-Clinker={}", self.cc(target).display())); + /// Returns the path to the linker for the given target if it needs to be overriden. + fn linker(&self, target: Interned) -> Option<&Path> { + if let Some(linker) = self.config.target_config.get(&target) + .and_then(|c| c.linker.as_ref()) { + Some(linker) + } else if target != self.config.build && + !target.contains("msvc") && !target.contains("emscripten") { + Some(self.cc(target)) + } else { + None } - base } /// Returns if this target should statically link the C runtime, if specified diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 2c8e5004041da..941ea96bbec23 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -227,6 +227,13 @@ impl Step for Llvm { cfg.build_arg("-j").build_arg(build.jobs().to_string()); cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); + if let Some(ar) = build.ar(target) { + if ar.is_absolute() { + // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it + // tries to resolve this path in the LLVM build directory. + cfg.define("CMAKE_AR", sanitize_cc(ar)); + } + } }; configure_compilers(&mut cfg); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index e95a5e0743637..662c56d728dfe 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -561,7 +561,7 @@ impl<'a> Builder<'a> { if compiler.host.contains("msvc") { let curpaths = env::var_os("PATH").unwrap_or_default(); let curpaths = env::split_paths(&curpaths).collect::>(); - for &(ref k, ref v) in self.cc[&compiler.host].0.env() { + for &(ref k, ref v) in self.cc[&compiler.host].env() { if k != "PATH" { continue } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index e81dab70b43e7..97723e260f6cb 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -138,27 +138,6 @@ pub fn gnu_target(target: &str) -> String { } } -pub fn cc2ar(cc: &Path, target: &str) -> Option { - if target.contains("msvc") { - None - } else if target.contains("musl") { - Some(PathBuf::from("ar")) - } else if target.contains("openbsd") { - Some(PathBuf::from("ar")) - } else { - let parent = cc.parent().unwrap(); - let file = cc.file_name().unwrap().to_str().unwrap(); - for suffix in &["gcc", "cc", "clang"] { - if let Some(idx) = file.rfind(suffix) { - let mut file = file[..idx].to_owned(); - file.push_str("ar"); - return Some(parent.join(&file)); - } - } - Some(parent.join(file)) - } -} - pub fn make(host: &str) -> PathBuf { if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd") || host.contains("netbsd") || diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 7dd85ddcc7965..65e035d4ffdef 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -63,15 +63,6 @@ fn main() { _ => return, }; - let compiler = cc::Build::new().get_compiler(); - // only msvc returns None for ar so unwrap is okay - let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); - let cflags = compiler.args() - .iter() - .map(|s| s.to_str().unwrap()) - .collect::>() - .join(" "); - let mut cmd = Command::new("sh"); cmd.arg(native.src_dir.join("configure") .to_str() @@ -79,8 +70,6 @@ fn main() { .replace("C:\\", "/c/") .replace("\\", "/")) .current_dir(&native.out_dir) - .env("CC", compiler.path()) - .env("EXTRA_CFLAGS", cflags.clone()) // jemalloc generates Makefile deps using GCC's "-MM" flag. This means // that GCC will run the preprocessor, and only the preprocessor, over // jemalloc's source files. If we don't specify CPPFLAGS, then at least @@ -89,9 +78,7 @@ fn main() { // passed to GCC, and then GCC won't define the // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to // select an atomic operation implementation. - .env("CPPFLAGS", cflags.clone()) - .env("AR", &ar) - .env("RANLIB", format!("{} s", ar.display())); + .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default()); if target.contains("ios") { cmd.arg("--disable-tls"); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f8bf00ad73fcc..890e1169c0591 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -246,6 +246,9 @@ pub fn opts() -> Vec { unstable("crate-version", |o| { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") }), + unstable("linker", |o| { + o.optopt("", "linker", "linker used for building executable test code", "PATH") + }), ] } @@ -357,15 +360,16 @@ pub fn main_args(args: &[String]) -> isize { let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let display_warnings = matches.opt_present("display-warnings"); + let linker = matches.opt_str("linker"); match (should_test, markdown_input) { (true, true) => { return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type, - display_warnings) + display_warnings, linker) } (true, false) => { return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot, - render_type, display_warnings) + render_type, display_warnings, linker) } (false, true) => return markdown::render(input, output.unwrap_or(PathBuf::from("doc")), diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 484285e91f6e9..fe6bd985bb618 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -142,7 +142,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, mut test_args: Vec, maybe_sysroot: Option, - render_type: RenderType, display_warnings: bool) -> isize { + render_type: RenderType, display_warnings: bool, linker: Option) -> isize { let input_str = match load_string(input) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -154,7 +154,7 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, Some(input.to_owned()), - render_type); + render_type, linker); if render_type == RenderType::Pulldown { old_find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 4b2980bc3a695..8b2c8d2da395a 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -61,7 +61,8 @@ pub fn run(input: &str, crate_name: Option, maybe_sysroot: Option, render_type: RenderType, - display_warnings: bool) + display_warnings: bool, + linker: Option) -> isize { let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); @@ -121,7 +122,8 @@ pub fn run(input: &str, maybe_sysroot, Some(codemap), None, - render_type); + render_type, + linker); { let map = hir::map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); @@ -180,7 +182,8 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option) { + maybe_sysroot: Option, + linker: Option) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let test = make_test(test, Some(cratename), as_test_harness, opts); @@ -201,6 +204,7 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs externs, cg: config::CodegenOptions { prefer_dynamic: true, + linker, .. config::basic_codegen_options() }, test: as_test_harness, @@ -442,13 +446,14 @@ pub struct Collector { filename: Option, // to be removed when hoedown will be removed as well pub render_type: RenderType, + linker: Option, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, codemap: Option>, filename: Option, - render_type: RenderType) -> Collector { + render_type: RenderType, linker: Option) -> Collector { Collector { tests: Vec::new(), old_tests: HashMap::new(), @@ -464,6 +469,7 @@ impl Collector { codemap, filename, render_type, + linker, } } @@ -510,6 +516,7 @@ impl Collector { let cratename = self.cratename.to_string(); let opts = self.opts.clone(); let maybe_sysroot = self.maybe_sysroot.clone(); + let linker = self.linker.clone(); debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { @@ -538,7 +545,8 @@ impl Collector { compile_fail, error_codes, &opts, - maybe_sysroot) + maybe_sysroot, + linker) }) } { Ok(()) => (), diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index c95287390b4f0..866c0038a7fd9 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -36,7 +36,6 @@ rustc_tsan = { path = "../librustc_tsan" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0.1" [features] backtrace = [] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 7ca762c801a81..0e6214ea04fc0 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -11,7 +11,6 @@ #![deny(warnings)] extern crate build_helper; -extern crate cc; use std::env; use std::process::Command; @@ -77,12 +76,6 @@ fn main() { fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; - let compiler = cc::Build::new().get_compiler(); - // only msvc returns None for ar so unwrap is okay - let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); - let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) - .collect::>().join(" "); - cflags.push_str(" -fvisibility=hidden"); run(Command::new("sh") .current_dir(&native.out_dir) .arg(native.src_dir.join("configure").to_str().unwrap() @@ -94,10 +87,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { .arg("--disable-host-shared") .arg(format!("--host={}", build_helper::gnu_target(target))) .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CC", compiler.path()) - .env("AR", &ar) - .env("RANLIB", format!("{} s", ar.display())) - .env("CFLAGS", cflags), + .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"), BuildExpectation::None); run(Command::new(build_helper::make(host)) diff --git a/src/test/run-make/archive-duplicate-names/Makefile b/src/test/run-make/archive-duplicate-names/Makefile index 5202e6dea541e..93711c41d79f8 100644 --- a/src/test/run-make/archive-duplicate-names/Makefile +++ b/src/test/run-make/archive-duplicate-names/Makefile @@ -5,7 +5,7 @@ all: mkdir $(TMPDIR)/b $(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c) $(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c) - ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o + $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o $(RUSTC) foo.rs $(RUSTC) bar.rs $(call RUN,bar) diff --git a/src/test/run-make/compiler-rt-works-on-mingw/Makefile b/src/test/run-make/compiler-rt-works-on-mingw/Makefile index 4ec54f73e67a5..06d1bb6698ece 100644 --- a/src/test/run-make/compiler-rt-works-on-mingw/Makefile +++ b/src/test/run-make/compiler-rt-works-on-mingw/Makefile @@ -3,8 +3,8 @@ ifneq (,$(findstring MINGW,$(UNAME))) ifndef IS_MSVC all: - g++ foo.cpp -c -o $(TMPDIR)/foo.o - ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o + $(CXX) foo.cpp -c -o $(TMPDIR)/foo.o + $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o $(RUSTC) foo.rs -lfoo -lstdc++ $(call RUN,foo) else diff --git a/src/test/run-make/invalid-library/Makefile b/src/test/run-make/invalid-library/Makefile index 0dbe655b77dfd..5c9cc9935099f 100644 --- a/src/test/run-make/invalid-library/Makefile +++ b/src/test/run-make/invalid-library/Makefile @@ -2,5 +2,5 @@ all: touch $(TMPDIR)/rust.metadata.bin - ar crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin + $(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin $(RUSTC) foo.rs 2>&1 | grep "can't find crate for" diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 461df49b468f9..4db027aaeef71 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -18,7 +18,6 @@ extern crate rustc_errors; extern crate rustc_trans; extern crate syntax; -use rustc::dep_graph::DepGraph; use rustc::session::{build_session, Session}; use rustc::session::config::{basic_options, build_configuration, Input, OutputType, OutputTypes}; @@ -56,6 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { let mut opts = basic_options(); opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); + if let Ok(linker) = std::env::var("RUSTC_LINKER") { + opts.cg.linker = Some(linker); + } let descriptions = Registry::new(&rustc::DIAGNOSTICS); let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader))); @@ -67,8 +69,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let (sess, cstore) = basic_sess(sysroot); - let cfg = build_configuration(&sess, HashSet::new()); let control = CompileController::basic(); let input = Input::Str { name: anon_src(), input: code }; - compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); + let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); } diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/issue-22131/Makefile index 64af91b487b32..cb4f146273348 100644 --- a/src/test/run-make/issue-22131/Makefile +++ b/src/test/run-make/issue-22131/Makefile @@ -2,6 +2,6 @@ all: foo.rs $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs - $(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \ + $(RUSTDOC) --test --cfg 'feature="bar"' \ -L $(TMPDIR) foo.rs |\ grep -q 'foo.rs - foo (line 11) ... ok' diff --git a/src/test/run-make/rustdoc-output-path/Makefile b/src/test/run-make/rustdoc-output-path/Makefile index 4e570718a62f9..8ce1c699526cd 100644 --- a/src/test/run-make/rustdoc-output-path/Makefile +++ b/src/test/run-make/rustdoc-output-path/Makefile @@ -1,4 +1,4 @@ -include ../tools.mk all: - $(HOST_RPATH_ENV) '$(RUSTDOC)' -o "$(TMPDIR)/foo/bar/doc" foo.rs + $(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs diff --git a/src/test/run-make/staticlib-blank-lib/Makefile b/src/test/run-make/staticlib-blank-lib/Makefile index 5878eec66bad4..92a278825c242 100644 --- a/src/test/run-make/staticlib-blank-lib/Makefile +++ b/src/test/run-make/staticlib-blank-lib/Makefile @@ -1,6 +1,6 @@ -include ../tools.mk all: - ar crus $(TMPDIR)/libfoo.a foo.rs - ar d $(TMPDIR)/libfoo.a foo.rs + $(AR) crus $(TMPDIR)/libfoo.a foo.rs + $(AR) d $(TMPDIR)/libfoo.a foo.rs $(RUSTC) foo.rs diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 27f235d54d46b..c5d5626bf7269 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -7,7 +7,13 @@ TARGET_RPATH_ENV = \ RUSTC_ORIGINAL := $(RUSTC) BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)' +BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) +RUSTDOC := $(BARE_RUSTDOC) +ifdef RUSTC_LINKER +RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) +RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options +endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py @@ -102,13 +108,13 @@ REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1)) REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1)) %.a: %.o - ar crus $@ $< + $(AR) crus $@ $< ifdef IS_MSVC %.lib: lib%.o $(MSVC_LIB) -out:`cygpath -w $@` $< else %.lib: lib%.o - ar crus $@ $< + $(AR) crus $@ $< endif %.dylib: %.o $(CC) -dynamiclib -Wl,-dylib -o $@ $< diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index cee7e52c7f3c6..aa98f818f4040 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -201,6 +201,8 @@ pub struct Config { pub cc: String, pub cxx: String, pub cflags: String, + pub ar: String, + pub linker: Option, pub llvm_components: String, pub llvm_cxxflags: String, pub nodejs: Option, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 306497da9e3f9..1701c8a3e43ee 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -102,6 +102,8 @@ pub fn parse_config(args: Vec ) -> Config { .reqopt("", "cc", "path to a C compiler", "PATH") .reqopt("", "cxx", "path to a C++ compiler", "PATH") .reqopt("", "cflags", "flags for the C compiler", "FLAGS") + .optopt("", "ar", "path to an archiver", "PATH") + .optopt("", "linker", "path to a linker", "PATH") .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") .reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS") .optopt("", "nodejs", "the name of nodejs", "PATH") @@ -198,6 +200,8 @@ pub fn parse_config(args: Vec ) -> Config { cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), cflags: matches.opt_str("cflags").unwrap(), + ar: matches.opt_str("ar").unwrap_or("ar".into()), + linker: matches.opt_str("linker"), llvm_components: matches.opt_str("llvm-components").unwrap(), llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(), nodejs: matches.opt_str("nodejs"), @@ -234,6 +238,8 @@ pub fn log_config(config: &Config) { logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); logv(c, format!("adb_device_status: {}", config.adb_device_status)); + logv(c, format!("ar: {}", config.ar)); + logv(c, format!("linker: {:?}", config.linker)); logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("quiet: {}", config.quiet)); logv(c, "\n".to_string()); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 60acc20e692a2..d61077643f1fe 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1155,6 +1155,9 @@ actual:\n\ .arg("-o").arg(out_dir) .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if let Some(ref linker) = self.config.linker { + rustdoc.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + } self.compose_and_run_compiler(rustdoc, None) } @@ -1441,6 +1444,9 @@ actual:\n\ } else { rustc.args(self.split_maybe_args(&self.config.target_rustcflags)); } + if let Some(ref linker) = self.config.linker { + rustc.arg(format!("-Clinker={}", linker)); + } rustc.args(&self.props.compile_flags); @@ -2101,6 +2107,10 @@ actual:\n\ .env("LLVM_COMPONENTS", &self.config.llvm_components) .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags); + if let Some(ref linker) = self.config.linker { + cmd.env("RUSTC_LINKER", linker); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); @@ -2123,7 +2133,8 @@ actual:\n\ .env("CXX", &self.config.cxx); } else { cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)); + .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)) + .env("AR", &self.config.ar); if self.config.target.contains("windows") { cmd.env("IS_WINDOWS", "1");