From 4b54066184040179e4c6cf9d5fdce91f22b472ba Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Sep 2014 11:07:19 +0200 Subject: [PATCH] Detect and memoize whether cc (the linker) is gcc or clang. The detected categorization is memoized in the Session object. The link.rs backend then uses this information when choosing options to add to the `cc` command line arguments (currently it just affects a single option that will cause a hard error in clang in the future). This is meant to be, in part, a more robust version of PR #17192. As drive-bys: * fix an english grammar mistake in a comment. * replace the use of `String` with `&str` for the program names corresponding `cc` and `ar`, avoiding unnecessary string copies but more importantly making the code overall look nicer. :) Fix #17214. (Addressed review nits from nrc and acrichto.) --- src/librustc/back/link.rs | 41 +++++------------ src/librustc/back/write.rs | 10 ++-- src/librustc/driver/session.rs | 83 +++++++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 35 deletions(-) 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));