rustbuild: Support specifying archiver and linker explicitly

This commit is contained in:
Vadim Petrochenkov 2017-10-10 23:06:22 +03:00
parent 2689fd2402
commit 9e0fc5ccd0
29 changed files with 200 additions and 108 deletions

View file

@ -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.

1
src/Cargo.lock generated
View file

@ -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",

View file

@ -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,

View file

@ -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

View file

@ -413,13 +413,15 @@ pub fn rustdoc(&self, host: Interned<String>) -> PathBuf {
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 @@ pub fn cargo(&self,
.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 @@ pub fn cargo(&self,
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);
}
}

View file

@ -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);

View file

@ -725,6 +725,9 @@ fn run(self, builder: &Builder) {
// 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 @@ fn run(self, builder: &Builder) {
.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 @@ fn run(self, builder: &Builder) {
// 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);
}

View file

@ -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 @@ pub fn parse(args: &[String]) -> 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);

View file

@ -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 @@ pub fn new(config: Config) -> 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 @@ fn jobs(&self) -> u32 {
/// 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 @@ fn cc(&self, target: Interned<String>) -> &Path {
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 @@ fn cflags(&self, target: Interned<String>) -> Vec<String> {
/// 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 @@ fn rustc_flags(&self, target: Interned<String>) -> Vec<String> {
// 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()));
}

View file

@ -227,6 +227,13 @@ fn run(self, builder: &Builder) {
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);

View file

@ -561,7 +561,7 @@ fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
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
}

View file

@ -138,27 +138,6 @@ pub fn gnu_target(target: &str) -> String {
}
}
pub fn cc2ar(cc: &Path, target: &str) -> Option<PathBuf> {
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") ||

View file

@ -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::<Vec<_>>()
.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");

View file

@ -246,6 +246,9 @@ pub fn opts() -> Vec<RustcOptGroup> {
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")),

View file

@ -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<String>, libs: SearchPaths, externs: Externs,
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
render_type: RenderType, display_warnings: bool) -> isize {
render_type: RenderType, display_warnings: bool, linker: Option<String>) -> 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<String>, 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);

View file

@ -61,7 +61,8 @@ pub fn run(input: &str,
crate_name: Option<String>,
maybe_sysroot: Option<PathBuf>,
render_type: RenderType,
display_warnings: bool)
display_warnings: bool,
linker: Option<String>)
-> 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<String>, libs
externs: Externs,
should_panic: bool, no_run: bool, as_test_harness: bool,
compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
maybe_sysroot: Option<PathBuf>) {
maybe_sysroot: Option<PathBuf>,
linker: Option<String>) {
// 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<String>, 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<String>,
// to be removed when hoedown will be removed as well
pub render_type: RenderType,
linker: Option<String>,
}
impl Collector {
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
codemap: Option<Rc<CodeMap>>, filename: Option<String>,
render_type: RenderType) -> Collector {
render_type: RenderType, linker: Option<String>) -> Collector {
Collector {
tests: Vec::new(),
old_tests: HashMap::new(),
@ -464,6 +469,7 @@ pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Ext
codemap,
filename,
render_type,
linker,
}
}
@ -510,6 +516,7 @@ pub fn add_test(&mut self, test: String,
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 @@ pub fn add_test(&mut self, test: String,
compile_fail,
error_codes,
&opts,
maybe_sysroot)
maybe_sysroot,
linker)
})
} {
Ok(()) => (),

View file

@ -36,7 +36,6 @@ rustc_tsan = { path = "../librustc_tsan" }
[build-dependencies]
build_helper = { path = "../build_helper" }
cc = "1.0.1"
[features]
backtrace = []

View file

@ -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::<Vec<_>>().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))

View file

@ -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)

View file

@ -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

View file

@ -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"

View file

@ -18,7 +18,6 @@
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<CStore>) {
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<CStore>) {
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);
}

View file

@ -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'

View file

@ -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

View file

@ -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

View file

@ -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 $@ $<

View file

@ -201,6 +201,8 @@ pub struct Config {
pub cc: String,
pub cxx: String,
pub cflags: String,
pub ar: String,
pub linker: Option<String>,
pub llvm_components: String,
pub llvm_cxxflags: String,
pub nodejs: Option<String>,

View file

@ -102,6 +102,8 @@ pub fn parse_config(args: Vec<String> ) -> 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 @@ fn make_absolute(path: PathBuf) -> PathBuf {
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());

View file

@ -1155,6 +1155,9 @@ fn document(&self, out_dir: &Path) -> ProcRes {
.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)
}
@ -2101,6 +2104,10 @@ fn run_rmake_test(&self) {
.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 +2130,8 @@ fn run_rmake_test(&self) {
.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");