diff options
| author | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2017-10-10 23:06:22 +0300 |
|---|---|---|
| committer | Vadim Petrochenkov <vadim.petrochenkov@gmail.com> | 2017-10-15 22:10:07 +0300 |
| commit | 9e0fc5ccd050201e77483b1efb2e6c76f47496f6 (patch) | |
| tree | b11fa90e3a2205b9add4ba0ffc8a3e38725c96e6 /src/bootstrap | |
| parent | 2689fd2402590961dae32f35369a8685c89022fb (diff) | |
| download | rust-9e0fc5ccd050201e77483b1efb2e6c76f47496f6.tar.gz rust-9e0fc5ccd050201e77483b1efb2e6c76f47496f6.zip | |
rustbuild: Support specifying archiver and linker explicitly
Diffstat (limited to 'src/bootstrap')
| -rw-r--r-- | src/bootstrap/bin/rustc.rs | 13 | ||||
| -rw-r--r-- | src/bootstrap/bin/rustdoc.rs | 3 | ||||
| -rw-r--r-- | src/bootstrap/builder.rs | 50 | ||||
| -rw-r--r-- | src/bootstrap/cc_detect.rs | 52 | ||||
| -rw-r--r-- | src/bootstrap/check.rs | 8 | ||||
| -rw-r--r-- | src/bootstrap/config.rs | 8 | ||||
| -rw-r--r-- | src/bootstrap/lib.rs | 23 | ||||
| -rw-r--r-- | src/bootstrap/native.rs | 7 | ||||
| -rw-r--r-- | src/bootstrap/tool.rs | 2 |
9 files changed, 130 insertions, 36 deletions
diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index e91acb21dac..e496ce27f50 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -120,12 +120,6 @@ 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::<Vec<_>>()); - } - // Pass down incremental directory, if any. if let Ok(dir) = env::var("RUSTC_INCREMENTAL") { cmd.arg(format!("-Zincremental={}", dir)); @@ -254,6 +248,13 @@ fn main() { } } + // Pass down extra flags, commonly used to configure `-Clinker`. + // Linker options should be set for build scripts as well, + // can't link a build script executable without a linker! + if let Ok(s) = env::var("RUSTC_FLAGS") { + cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::<Vec<_>>()); + } + let color = match env::var("RUSTC_COLOR") { Ok(s) => usize::from_str(&s).expect("RUSTC_COLOR should be an integer"), Err(_) => 0, diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index d18512b257d..2105797a830 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("RUSTDOC_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 1d63e112ca6..ef4f8f78b0d 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<String>) -> 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("RUSTDOC_LINKER", linker); + } cmd } @@ -485,6 +487,10 @@ impl<'a> Builder<'a> { .env("TEST_MIRI", self.config.test_miri.to_string()) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + if let Some(linker) = self.build.linker(target) { + cargo.env("RUSTDOC_LINKER", linker); + } + if mode != Mode::Tool { // Tools don't get debuginfo right now, e.g. cargo and rls don't // get compiled with debuginfo. @@ -557,17 +563,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 08df65c7611..6e3e3c92029 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<PathBuf> { + 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::<HashSet<_>>(); + 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::<HashSet<_>>(); + 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 fb32ab0cb86..d9b0ff4c7a4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -725,6 +725,9 @@ impl Step for Compiletest { // Avoid depending on rustdoc when we don't need it. if mode == "rustdoc" || mode == "run-make" { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); + if let Some(linker) = build.linker(target) { + cmd.arg("--linker").arg(linker); + } } cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); @@ -806,6 +809,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 +837,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 5fb5eb3b7f1..69e0f58f1cd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -143,6 +143,8 @@ pub struct Target { pub jemalloc: Option<PathBuf>, pub cc: Option<PathBuf>, pub cxx: Option<PathBuf>, + pub ar: Option<PathBuf>, + pub linker: Option<PathBuf>, pub ndk: Option<PathBuf>, pub crt_static: Option<bool>, pub musl_root: Option<PathBuf>, @@ -282,6 +284,8 @@ struct TomlTarget { jemalloc: Option<String>, cc: Option<String>, cxx: Option<String>, + ar: Option<String>, + linker: Option<String>, android_ndk: Option<String>, crt_static: Option<bool>, musl_root: Option<String>, @@ -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 2d721f45578..7c599f91838 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -240,10 +240,11 @@ pub struct Build { lldb_python_dir: Option<String>, // Runtime state filled in later on - // target -> (cc, ar) - cc: HashMap<Interned<String>, (cc::Tool, Option<PathBuf>)>, - // host -> (cc, ar) + // C/C++ compilers and archiver for all targets + cc: HashMap<Interned<String>, cc::Tool>, cxx: HashMap<Interned<String>, cc::Tool>, + ar: HashMap<Interned<String>, PathBuf>, + // Misc crates: HashMap<Interned<String>, 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<String>) -> &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<String>) -> Vec<String> { // 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::<Vec<_>>(); @@ -644,7 +646,11 @@ impl Build { /// Returns the path to the `ar` archive utility for the target specified. fn ar(&self, target: Interned<String>) -> Option<&Path> { - self.cc[&target].1.as_ref().map(|p| &**p) + self.ar.get(&target).map(|p| &**p) + } + + fn linker(&self, target: Interned<String>) -> Option<&Path> { + self.config.target_config.get(&target).and_then(|c| c.linker.as_ref().map(|p| &**p)) } /// Returns the path to the C++ compiler for the target specified. @@ -667,7 +673,10 @@ impl Build { // than an entry here. let mut base = Vec::new(); - if target != self.config.build && !target.contains("msvc") && + if let Some(linker) = self.linker(target) { + // If linker was explictly provided, force it on all the compiled Rust code. + base.push(format!("-Clinker={}", linker.display())); + } else if target != self.config.build && !target.contains("msvc") && !target.contains("emscripten") { base.push(format!("-Clinker={}", self.cc(target).display())); } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 2c8e5004041..941ea96bbec 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 e95a5e07436..662c56d728d 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::<Vec<_>>(); - 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 } |
