1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use back::target_strs;
15 use driver::driver::host_triple;
16 use metadata::filesearch;
20 use syntax::attr::AttrMetaMethods;
21 use syntax::ast::NodeId;
22 use syntax::ast::{IntTy, UintTy};
23 use syntax::codemap::Span;
24 use syntax::diagnostic;
25 use syntax::parse::ParseSess;
26 use syntax::{ast, codemap};
28 use syntax::parse::token;
31 use std::cell::{Cell, RefCell};
32 use std::hashmap::{HashMap,HashSet};
36 arch: abi::Architecture,
37 target_strs: target_strs::t,
42 macro_rules! debugging_opts(
43 ([ $opt:ident ] $cnt:expr ) => (
44 pub static $opt: u64 = 1 << $cnt;
46 ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
47 pub static $opt: u64 = 1 << $cnt;
48 debugging_opts!([ $($rest),* ] $cnt + 1)
74 NO_PREPOPULATE_PASSES,
84 pub fn debugging_opts_map() -> ~[(&'static str, &'static str, u64)] {
85 ~[("verbose", "in general, enable more debug printouts", VERBOSE),
86 ("time-passes", "measure time of each rustc pass", TIME_PASSES),
87 ("count-llvm-insns", "count where LLVM \
88 instrs originate", COUNT_LLVM_INSNS),
89 ("time-llvm-passes", "measure time of each LLVM pass",
91 ("trans-stats", "gather trans statistics", TRANS_STATS),
92 ("asm-comments", "generate comments into the assembly (may change behavior)",
94 ("no-verify", "skip LLVM verification", NO_VERIFY),
95 ("borrowck-stats", "gather borrowck statistics", BORROWCK_STATS),
96 ("no-landing-pads", "omit landing pads for unwinding",
98 ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
99 ("count-type-sizes", "count the sizes of aggregate types",
101 ("meta-stats", "gather metadata statistics", META_STATS),
102 ("no-opt", "do not optimize, even if -O is passed", NO_OPT),
103 ("print-link-args", "Print the arguments passed to the linker",
105 ("gc", "Garbage collect shared data (experimental)", GC),
106 ("extra-debug-info", "Extra debugging info (experimental)",
108 ("debug-info", "Produce debug info (experimental)", DEBUG_INFO),
109 ("print-llvm-passes",
110 "Prints the llvm optimization passes being run",
112 ("no-prepopulate-passes",
113 "Don't pre-populate the pass managers with a list of passes, only use \
114 the passes from --passes",
115 NO_PREPOPULATE_PASSES),
116 ("no-vectorize-loops",
117 "Don't run the loop vectorization optimization passes",
119 ("no-vectorize-slp", "Don't run LLVM's SLP vectorization passes",
121 ("soft-float", "Generate software floating point library calls", USE_SOFTFP),
122 ("gen-crate-map", "Force generation of a toplevel crate map", GEN_CRATE_MAP),
123 ("prefer-dynamic", "Prefer dynamic linking to static linking", PREFER_DYNAMIC),
125 "Use external assembler rather than LLVM's integrated one", NO_INTEGRATED_AS),
126 ("lto", "Perform LLVM link-time optimizations", LTO),
130 #[deriving(Clone, Eq)]
140 // The crate config requested for the session, which may be combined
141 // with additional crate configurations during the compile process
142 outputs: ~[OutputStyle],
146 custom_passes: ~[~str],
149 extra_debuginfo: bool,
150 lint_opts: ~[(lint::Lint, lint::level)],
152 output_type: back::link::OutputType,
153 // This is mutable for rustpkg, which updates search paths based on the
155 addl_lib_search_paths: @RefCell<HashSet<Path>>,
157 linker: Option<~str>,
158 linker_args: ~[~str],
159 maybe_sysroot: Option<@Path>,
162 target_feature: ~str,
163 // User-specified cfg meta items. The compiler itself will add additional
164 // items to the crate config, and during parsing the entire crate config
165 // will be added to the crate AST node. This should not be used for
166 // anything except building the full crate config prior to parsing.
167 cfg: ast::CrateConfig,
175 android_cross_path: Option<~str>,
176 /// Whether to write dependency files. It's (enabled, optional filename).
177 write_dependency_info: (bool, Option<Path>),
178 /// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
179 print_metas: (bool, bool, bool),
182 // The type of entry function, so
183 // users can have their own entry
184 // functions that don't start a
187 pub enum EntryFnType {
193 #[deriving(Eq, Clone, TotalOrd, TotalEq)]
194 pub enum OutputStyle {
201 pub struct Session_ {
204 cstore: @metadata::cstore::CStore,
205 parse_sess: @ParseSess,
206 codemap: @codemap::CodeMap,
207 // For a library crate, this is always none
208 entry_fn: RefCell<Option<(NodeId, codemap::Span)>>,
209 entry_type: Cell<Option<EntryFnType>>,
210 span_diagnostic: @diagnostic::SpanHandler,
211 macro_registrar_fn: RefCell<Option<ast::DefId>>,
212 filesearch: @filesearch::FileSearch,
213 building_library: Cell<bool>,
214 // The name of the root source file of the crate, in the local file system. The path is always
215 // expected to be absolute. `None` means that there is no source file.
216 local_crate_source_file: Option<Path>,
218 lints: RefCell<HashMap<ast::NodeId,
219 ~[(lint::Lint, codemap::Span, ~str)]>>,
220 node_id: Cell<ast::NodeId>,
221 outputs: @RefCell<~[OutputStyle]>,
224 pub type Session = @Session_;
227 pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
228 self.span_diagnostic.span_fatal(sp, msg)
230 pub fn fatal(&self, msg: &str) -> ! {
231 self.span_diagnostic.handler().fatal(msg)
233 pub fn span_err(&self, sp: Span, msg: &str) {
234 self.span_diagnostic.span_err(sp, msg)
236 pub fn err(&self, msg: &str) {
237 self.span_diagnostic.handler().err(msg)
239 pub fn err_count(&self) -> uint {
240 self.span_diagnostic.handler().err_count()
242 pub fn has_errors(&self) -> bool {
243 self.span_diagnostic.handler().has_errors()
245 pub fn abort_if_errors(&self) {
246 self.span_diagnostic.handler().abort_if_errors()
248 pub fn span_warn(&self, sp: Span, msg: &str) {
249 self.span_diagnostic.span_warn(sp, msg)
251 pub fn warn(&self, msg: &str) {
252 self.span_diagnostic.handler().warn(msg)
254 pub fn span_note(&self, sp: Span, msg: &str) {
255 self.span_diagnostic.span_note(sp, msg)
257 pub fn span_end_note(&self, sp: Span, msg: &str) {
258 self.span_diagnostic.span_end_note(sp, msg)
260 pub fn note(&self, msg: &str) {
261 self.span_diagnostic.handler().note(msg)
263 pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
264 self.span_diagnostic.span_bug(sp, msg)
266 pub fn bug(&self, msg: &str) -> ! {
267 self.span_diagnostic.handler().bug(msg)
269 pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
270 self.span_diagnostic.span_unimpl(sp, msg)
272 pub fn unimpl(&self, msg: &str) -> ! {
273 self.span_diagnostic.handler().unimpl(msg)
275 pub fn add_lint(&self,
280 let mut lints = self.lints.borrow_mut();
281 match lints.get().find_mut(&id) {
282 Some(arr) => { arr.push((lint, sp, msg)); return; }
285 lints.get().insert(id, ~[(lint, sp, msg)]);
287 pub fn next_node_id(&self) -> ast::NodeId {
288 self.reserve_node_ids(1)
290 pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
291 let v = self.node_id.get();
293 match v.checked_add(&count) {
294 Some(next) => { self.node_id.set(next); }
295 None => self.bug("Input too large, ran out of node ids!")
300 pub fn diagnostic(&self) -> @diagnostic::SpanHandler {
303 pub fn debugging_opt(&self, opt: u64) -> bool {
304 (self.opts.debugging_opts & opt) != 0
306 // This exists to help with refactoring to eliminate impossible
308 pub fn impossible_case(&self, sp: Span, msg: &str) -> ! {
309 self.span_bug(sp, format!("Impossible case reached: {}", msg));
311 pub fn verbose(&self) -> bool { self.debugging_opt(VERBOSE) }
312 pub fn time_passes(&self) -> bool { self.debugging_opt(TIME_PASSES) }
313 pub fn count_llvm_insns(&self) -> bool {
314 self.debugging_opt(COUNT_LLVM_INSNS)
316 pub fn count_type_sizes(&self) -> bool {
317 self.debugging_opt(COUNT_TYPE_SIZES)
319 pub fn time_llvm_passes(&self) -> bool {
320 self.debugging_opt(TIME_LLVM_PASSES)
322 pub fn trans_stats(&self) -> bool { self.debugging_opt(TRANS_STATS) }
323 pub fn meta_stats(&self) -> bool { self.debugging_opt(META_STATS) }
324 pub fn asm_comments(&self) -> bool { self.debugging_opt(ASM_COMMENTS) }
325 pub fn no_verify(&self) -> bool { self.debugging_opt(NO_VERIFY) }
326 pub fn borrowck_stats(&self) -> bool { self.debugging_opt(BORROWCK_STATS) }
327 pub fn print_llvm_passes(&self) -> bool {
328 self.debugging_opt(PRINT_LLVM_PASSES)
330 pub fn no_prepopulate_passes(&self) -> bool {
331 self.debugging_opt(NO_PREPOPULATE_PASSES)
333 pub fn no_vectorize_loops(&self) -> bool {
334 self.debugging_opt(NO_VECTORIZE_LOOPS)
336 pub fn no_vectorize_slp(&self) -> bool {
337 self.debugging_opt(NO_VECTORIZE_SLP)
339 pub fn gen_crate_map(&self) -> bool {
340 self.debugging_opt(GEN_CRATE_MAP)
342 pub fn prefer_dynamic(&self) -> bool {
343 self.debugging_opt(PREFER_DYNAMIC)
345 pub fn no_integrated_as(&self) -> bool {
346 self.debugging_opt(NO_INTEGRATED_AS)
348 pub fn lto(&self) -> bool {
349 self.debugging_opt(LTO)
351 pub fn no_landing_pads(&self) -> bool {
352 self.debugging_opt(NO_LANDING_PADS)
355 // DEPRECATED. This function results in a lot of allocations when they
356 // are not necessary.
357 pub fn str_of(&self, id: ast::Ident) -> ~str {
358 let string = token::get_ident(id.name);
359 string.get().to_str()
362 // pointless function, now...
363 pub fn ident_of(&self, st: &str) -> ast::Ident {
364 token::str_to_ident(st)
367 // pointless function, now...
368 pub fn intr(&self) -> @syntax::parse::token::IdentInterner {
369 token::get_ident_interner()
373 /// Some reasonable defaults
374 pub fn basic_options() -> @Options {
382 extra_debuginfo: false,
385 output_type: link::OutputTypeExe,
386 addl_lib_search_paths: @RefCell::new(HashSet::new()),
391 target_triple: host_triple(),
392 target_cpu: ~"generic",
402 android_cross_path: None,
403 write_dependency_info: (false, None),
404 print_metas: (false, false, false),
408 // Seems out of place, but it uses session, so I'm putting it here
409 pub fn expect<T:Clone>(sess: Session, opt: Option<T>, msg: || -> ~str) -> T {
410 diagnostic::expect(sess.diagnostic(), opt, msg)
413 pub fn building_library(options: &Options, crate: &ast::Crate) -> bool {
414 if options.test { return false }
415 for output in options.outputs.iter() {
417 OutputExecutable => {}
418 OutputStaticlib | OutputDylib | OutputRlib => return true
421 match syntax::attr::first_attr_value_str_by_name(crate.attrs, "crate_type") {
424 s.equiv(&("rlib")) ||
425 s.equiv(&("dylib")) ||
426 s.equiv(&("staticlib"))
432 pub fn default_lib_output() -> OutputStyle {
436 pub fn collect_outputs(session: &Session,
437 attrs: &[ast::Attribute]) -> ~[OutputStyle] {
438 // If we're generating a test executable, then ignore all other output
439 // styles at all other locations
440 if session.opts.test {
441 return ~[OutputExecutable];
443 let mut base = session.opts.outputs.clone();
444 let mut iter = attrs.iter().filter_map(|a| {
445 if a.name().equiv(&("crate_type")) {
446 match a.value_str() {
447 Some(ref n) if n.equiv(&("rlib")) => Some(OutputRlib),
448 Some(ref n) if n.equiv(&("dylib")) => Some(OutputDylib),
449 Some(ref n) if n.equiv(&("lib")) => {
450 Some(default_lib_output())
452 Some(ref n) if n.equiv(&("staticlib")) => {
453 Some(OutputStaticlib)
455 Some(ref n) if n.equiv(&("bin")) => Some(OutputExecutable),
457 session.add_lint(lint::UnknownCrateType,
460 ~"invalid `crate_type` value");
464 session.add_lint(lint::UnknownCrateType, ast::CRATE_NODE_ID,
465 a.span, ~"`crate_type` requires a value");
473 base.extend(&mut iter);
475 base.push(OutputExecutable);
482 pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
483 use metadata::loader;
486 abi::OsWin32 => loader::OsWin32,
487 abi::OsLinux => loader::OsLinux,
488 abi::OsAndroid => loader::OsAndroid,
489 abi::OsMacos => loader::OsMacos,
490 abi::OsFreebsd => loader::OsFreebsd