diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 18aa66f0e9398..c6641bd139c20 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -16,6 +16,7 @@ use super::svh::Svh; use super::write::{OutputTypeBitcode, OutputTypeExe, OutputTypeObject}; use driver::driver::{CrateTranslation, OutputFilenames, Input, FileInput}; use driver::config::NoDebugInfo; +use driver::session::{CcArgumentsFormat, GccArguments}; use driver::session::Session; use driver::config; use metadata::common::LinkMeta; @@ -72,7 +73,6 @@ pub static RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET: uint = pub static RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET: uint = RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8; - /* * Name mangling and its relationship to metadata. This is complex. Read * carefully. @@ -380,29 +380,6 @@ pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> Stri mangle(path.chain(Some(gensym_name(flav)).move_iter()), None) } -pub fn get_cc_prog(sess: &Session) -> String { - match sess.opts.cg.linker { - Some(ref linker) => return linker.to_string(), - None => {} - } - - // In the future, FreeBSD will use clang as default compiler. - // It would be flexible to use cc (system's default C compiler) - // instead of hard-coded gcc. - // For Windows, there is no cc command, so we add a condition to make it use gcc. - match sess.targ_cfg.os { - abi::OsWindows => "gcc", - _ => "cc", - }.to_string() -} - -pub fn get_ar_prog(sess: &Session) -> String { - match sess.opts.cg.ar { - Some(ref ar) => (*ar).clone(), - None => "ar".to_string() - } -} - pub fn remove(sess: &Session, path: &Path) { match fs::unlink(path) { Ok(..) => {} @@ -811,11 +788,11 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir"); // The invocations of cc share some flags across platforms - let pname = get_cc_prog(sess); - let mut cmd = Command::new(pname.as_slice()); + let (pname, args_fmt) = sess.get_cc_prog(); + let mut cmd = Command::new(pname); cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice()); - link_args(&mut cmd, sess, dylib, tmpdir.path(), + link_args(&mut cmd, args_fmt, sess, dylib, tmpdir.path(), trans, obj_filename, out_filename); if (sess.opts.debugging_opts & config::PRINT_LINK_ARGS) != 0 { @@ -867,6 +844,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool, } fn link_args(cmd: &mut Command, + args_fmt: CcArgumentsFormat, sess: &Session, dylib: bool, tmpdir: &Path, @@ -929,8 +907,13 @@ fn link_args(cmd: &mut Command, cmd.arg("-nodefaultlibs"); } - // Rust does its' own LTO - cmd.arg("-fno-lto").arg("-fno-use-linker-plugin"); + // Rust does its own LTO + cmd.arg("-fno-lto"); + + // clang fails hard if -fno-use-linker-plugin is passed + if args_fmt == GccArguments { + cmd.arg("-fno-use-linker-plugin"); + } // If we're building a dylib, we don't use --gc-sections because LLVM has // already done the best it can do, and we also don't want to eliminate the diff --git a/src/librustc/back/write.rs b/src/librustc/back/write.rs index 627d455f06e11..0e411a847d0f8 100644 --- a/src/librustc/back/write.rs +++ b/src/librustc/back/write.rs @@ -9,7 +9,7 @@ // except according to those terms. use back::lto; -use back::link::{get_cc_prog, remove}; +use back::link::{remove}; use driver::driver::{CrateTranslation, ModuleTranslation, OutputFilenames}; use driver::config::NoDebugInfo; use driver::session::Session; @@ -632,8 +632,8 @@ pub fn run_passes(sess: &Session, None }; - let pname = get_cc_prog(sess); - let mut cmd = Command::new(pname.as_slice()); + let pname = sess.get_cc_prog_str(); + let mut cmd = Command::new(pname); cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice()); cmd.arg("-nostdlib"); @@ -828,8 +828,8 @@ fn run_work_multithreaded(sess: &Session, } pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { - let pname = get_cc_prog(sess); - let mut cmd = Command::new(pname.as_slice()); + let pname = sess.get_cc_prog_str(); + let mut cmd = Command::new(pname); cmd.arg("-c").arg("-o").arg(outputs.path(OutputTypeObject)) .arg(outputs.temp_path(OutputTypeAssembly)); diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 6f020184b336d..5777da7a3b660 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -17,6 +17,7 @@ use metadata::filesearch; use lint; use util::nodemap::NodeMap; +use syntax::abi; use syntax::ast::NodeId; use syntax::codemap::Span; use syntax::diagnostic; @@ -26,8 +27,22 @@ use syntax::parse::token; use syntax::parse::ParseSess; use syntax::{ast, codemap}; -use std::os; use std::cell::{Cell, RefCell}; +use std::io::Command; +use std::os; +use std::str; + +/// The `cc` program used for linking will accept command line +/// arguments according to one of the following formats. +#[deriving(PartialEq, Show)] +pub enum CcArgumentsFormat { + /// GNU compiler collection (GCC) compatible format. + GccArguments, + /// LLVM Clang front-end compatible format. + ClangArguments, + /// Unknown argument format; assume lowest common denominator among above. + UnknownCcArgumentFormat, +} // Represents the data associated with a compilation // session for a single crate. @@ -55,6 +70,11 @@ pub struct Session { /// The maximum recursion limit for potentially infinitely recursive /// operations such as auto-dereference and monomorphization. pub recursion_limit: Cell, + + /// What command line options are acceptable to cc program; + /// locally memoized (i.e. initialized at most once). + /// See `Session::cc_prog` and `Session::cc_args_format`. + memo_cc_args_format: Cell>, } impl Session { @@ -202,6 +222,66 @@ impl Session { driver::host_triple(), &self.opts.addl_lib_search_paths) } + + pub fn get_cc_prog_str(&self) -> &str { + match self.opts.cg.linker { + Some(ref linker) => return linker.as_slice(), + None => {} + } + + // In the future, FreeBSD will use clang as default compiler. + // It would be flexible to use cc (system's default C compiler) + // instead of hard-coded gcc. + // For Windows, there is no cc command, so we add a condition to make it use gcc. + match self.targ_cfg.os { + abi::OsWindows => "gcc", + _ => "cc", + } + } + + pub fn get_ar_prog_str(&self) -> &str { + match self.opts.cg.ar { + Some(ref ar) => ar.as_slice(), + None => "ar" + } + } + + pub fn get_cc_args_format(&self) -> CcArgumentsFormat { + match self.memo_cc_args_format.get() { + Some(args_format) => return args_format, + None => {} + } + + // Extract the args format: invoke `cc --version`, then search + // for identfying substrings. + let prog_str = self.get_cc_prog_str(); + let mut command = Command::new(prog_str); + let presult = match command.arg("--version").output() { + Ok(p) => p, + Err(e) => fail!("failed to execute process: {}", e), + }; + + let output = str::from_utf8_lossy(presult.output.as_slice()); + let output = output.as_slice(); + let args_fmt = if output.contains("clang") { + ClangArguments + } else if output.contains("GCC") || + output.contains("Free Software Foundation") { + GccArguments + } else { + UnknownCcArgumentFormat + }; + + // Memoize the args format. + self.memo_cc_args_format.set(Some(args_fmt)); + + args_fmt + } + + pub fn get_cc_prog(&self) -> (&str, CcArgumentsFormat) { + (self.get_cc_prog_str(), self.get_cc_args_format()) + } + } pub fn build_session(sopts: config::Options, @@ -256,6 +336,7 @@ pub fn build_session_(sopts: config::Options, crate_metadata: RefCell::new(Vec::new()), features: front::feature_gate::Features::new(), recursion_limit: Cell::new(64), + memo_cc_args_format: Cell::new(None), }; sess.lint_store.borrow_mut().register_builtin(Some(&sess));