Skip to content

Commit 4b54066

Browse files
committed
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.)
1 parent 0f99aba commit 4b54066

File tree

3 files changed

+99
-35
lines changed

3 files changed

+99
-35
lines changed

src/librustc/back/link.rs

+12-29
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use super::svh::Svh;
1616
use super::write::{OutputTypeBitcode, OutputTypeExe, OutputTypeObject};
1717
use driver::driver::{CrateTranslation, OutputFilenames, Input, FileInput};
1818
use driver::config::NoDebugInfo;
19+
use driver::session::{CcArgumentsFormat, GccArguments};
1920
use driver::session::Session;
2021
use driver::config;
2122
use metadata::common::LinkMeta;
@@ -72,7 +73,6 @@ pub static RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET: uint =
7273
pub static RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET: uint =
7374
RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8;
7475

75-
7676
/*
7777
* Name mangling and its relationship to metadata. This is complex. Read
7878
* carefully.
@@ -380,29 +380,6 @@ pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> Stri
380380
mangle(path.chain(Some(gensym_name(flav)).move_iter()), None)
381381
}
382382

383-
pub fn get_cc_prog(sess: &Session) -> String {
384-
match sess.opts.cg.linker {
385-
Some(ref linker) => return linker.to_string(),
386-
None => {}
387-
}
388-
389-
// In the future, FreeBSD will use clang as default compiler.
390-
// It would be flexible to use cc (system's default C compiler)
391-
// instead of hard-coded gcc.
392-
// For Windows, there is no cc command, so we add a condition to make it use gcc.
393-
match sess.targ_cfg.os {
394-
abi::OsWindows => "gcc",
395-
_ => "cc",
396-
}.to_string()
397-
}
398-
399-
pub fn get_ar_prog(sess: &Session) -> String {
400-
match sess.opts.cg.ar {
401-
Some(ref ar) => (*ar).clone(),
402-
None => "ar".to_string()
403-
}
404-
}
405-
406383
pub fn remove(sess: &Session, path: &Path) {
407384
match fs::unlink(path) {
408385
Ok(..) => {}
@@ -811,11 +788,11 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
811788
let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir");
812789

813790
// The invocations of cc share some flags across platforms
814-
let pname = get_cc_prog(sess);
815-
let mut cmd = Command::new(pname.as_slice());
791+
let (pname, args_fmt) = sess.get_cc_prog();
792+
let mut cmd = Command::new(pname);
816793

817794
cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice());
818-
link_args(&mut cmd, sess, dylib, tmpdir.path(),
795+
link_args(&mut cmd, args_fmt, sess, dylib, tmpdir.path(),
819796
trans, obj_filename, out_filename);
820797

821798
if (sess.opts.debugging_opts & config::PRINT_LINK_ARGS) != 0 {
@@ -867,6 +844,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
867844
}
868845

869846
fn link_args(cmd: &mut Command,
847+
args_fmt: CcArgumentsFormat,
870848
sess: &Session,
871849
dylib: bool,
872850
tmpdir: &Path,
@@ -929,8 +907,13 @@ fn link_args(cmd: &mut Command,
929907
cmd.arg("-nodefaultlibs");
930908
}
931909

932-
// Rust does its' own LTO
933-
cmd.arg("-fno-lto").arg("-fno-use-linker-plugin");
910+
// Rust does its own LTO
911+
cmd.arg("-fno-lto");
912+
913+
// clang fails hard if -fno-use-linker-plugin is passed
914+
if args_fmt == GccArguments {
915+
cmd.arg("-fno-use-linker-plugin");
916+
}
934917

935918
// If we're building a dylib, we don't use --gc-sections because LLVM has
936919
// already done the best it can do, and we also don't want to eliminate the

src/librustc/back/write.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use back::lto;
12-
use back::link::{get_cc_prog, remove};
12+
use back::link::{remove};
1313
use driver::driver::{CrateTranslation, ModuleTranslation, OutputFilenames};
1414
use driver::config::NoDebugInfo;
1515
use driver::session::Session;
@@ -632,8 +632,8 @@ pub fn run_passes(sess: &Session,
632632
None
633633
};
634634

635-
let pname = get_cc_prog(sess);
636-
let mut cmd = Command::new(pname.as_slice());
635+
let pname = sess.get_cc_prog_str();
636+
let mut cmd = Command::new(pname);
637637

638638
cmd.args(sess.targ_cfg.target_strs.cc_args.as_slice());
639639
cmd.arg("-nostdlib");
@@ -828,8 +828,8 @@ fn run_work_multithreaded(sess: &Session,
828828
}
829829

830830
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
831-
let pname = get_cc_prog(sess);
832-
let mut cmd = Command::new(pname.as_slice());
831+
let pname = sess.get_cc_prog_str();
832+
let mut cmd = Command::new(pname);
833833

834834
cmd.arg("-c").arg("-o").arg(outputs.path(OutputTypeObject))
835835
.arg(outputs.temp_path(OutputTypeAssembly));

src/librustc/driver/session.rs

+82-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use metadata::filesearch;
1717
use lint;
1818
use util::nodemap::NodeMap;
1919

20+
use syntax::abi;
2021
use syntax::ast::NodeId;
2122
use syntax::codemap::Span;
2223
use syntax::diagnostic;
@@ -26,8 +27,22 @@ use syntax::parse::token;
2627
use syntax::parse::ParseSess;
2728
use syntax::{ast, codemap};
2829

29-
use std::os;
3030
use std::cell::{Cell, RefCell};
31+
use std::io::Command;
32+
use std::os;
33+
use std::str;
34+
35+
/// The `cc` program used for linking will accept command line
36+
/// arguments according to one of the following formats.
37+
#[deriving(PartialEq, Show)]
38+
pub enum CcArgumentsFormat {
39+
/// GNU compiler collection (GCC) compatible format.
40+
GccArguments,
41+
/// LLVM Clang front-end compatible format.
42+
ClangArguments,
43+
/// Unknown argument format; assume lowest common denominator among above.
44+
UnknownCcArgumentFormat,
45+
}
3146

3247
// Represents the data associated with a compilation
3348
// session for a single crate.
@@ -55,6 +70,11 @@ pub struct Session {
5570
/// The maximum recursion limit for potentially infinitely recursive
5671
/// operations such as auto-dereference and monomorphization.
5772
pub recursion_limit: Cell<uint>,
73+
74+
/// What command line options are acceptable to cc program;
75+
/// locally memoized (i.e. initialized at most once).
76+
/// See `Session::cc_prog` and `Session::cc_args_format`.
77+
memo_cc_args_format: Cell<Option<CcArgumentsFormat>>,
5878
}
5979

6080
impl Session {
@@ -202,6 +222,66 @@ impl Session {
202222
driver::host_triple(),
203223
&self.opts.addl_lib_search_paths)
204224
}
225+
226+
pub fn get_cc_prog_str(&self) -> &str {
227+
match self.opts.cg.linker {
228+
Some(ref linker) => return linker.as_slice(),
229+
None => {}
230+
}
231+
232+
// In the future, FreeBSD will use clang as default compiler.
233+
// It would be flexible to use cc (system's default C compiler)
234+
// instead of hard-coded gcc.
235+
// For Windows, there is no cc command, so we add a condition to make it use gcc.
236+
match self.targ_cfg.os {
237+
abi::OsWindows => "gcc",
238+
_ => "cc",
239+
}
240+
}
241+
242+
pub fn get_ar_prog_str(&self) -> &str {
243+
match self.opts.cg.ar {
244+
Some(ref ar) => ar.as_slice(),
245+
None => "ar"
246+
}
247+
}
248+
249+
pub fn get_cc_args_format(&self) -> CcArgumentsFormat {
250+
match self.memo_cc_args_format.get() {
251+
Some(args_format) => return args_format,
252+
None => {}
253+
}
254+
255+
// Extract the args format: invoke `cc --version`, then search
256+
// for identfying substrings.
257+
let prog_str = self.get_cc_prog_str();
258+
let mut command = Command::new(prog_str);
259+
let presult = match command.arg("--version").output() {
260+
Ok(p) => p,
261+
Err(e) => fail!("failed to execute process: {}", e),
262+
};
263+
264+
let output = str::from_utf8_lossy(presult.output.as_slice());
265+
let output = output.as_slice();
266+
let args_fmt = if output.contains("clang") {
267+
ClangArguments
268+
} else if output.contains("GCC") ||
269+
output.contains("Free Software Foundation") {
270+
GccArguments
271+
} else {
272+
UnknownCcArgumentFormat
273+
};
274+
275+
// Memoize the args format.
276+
self.memo_cc_args_format.set(Some(args_fmt));
277+
278+
args_fmt
279+
}
280+
281+
pub fn get_cc_prog(&self) -> (&str, CcArgumentsFormat) {
282+
(self.get_cc_prog_str(), self.get_cc_args_format())
283+
}
284+
205285
}
206286

207287
pub fn build_session(sopts: config::Options,
@@ -256,6 +336,7 @@ pub fn build_session_(sopts: config::Options,
256336
crate_metadata: RefCell::new(Vec::new()),
257337
features: front::feature_gate::Features::new(),
258338
recursion_limit: Cell::new(64),
339+
memo_cc_args_format: Cell::new(None),
259340
};
260341

261342
sess.lint_store.borrow_mut().register_builtin(Some(&sess));

0 commit comments

Comments
 (0)