]> git.lizzy.rs Git - rust.git/blob - src/librustc/driver/session.rs
librustc: De-`@str` `ident()` and `str_of()`
[rust.git] / src / librustc / driver / session.rs
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.
4 //
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.
10
11
12 use back::link;
13 use back::target_strs;
14 use back;
15 use driver::driver::host_triple;
16 use metadata::filesearch;
17 use metadata;
18 use middle::lint;
19
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};
27 use syntax::abi;
28 use syntax::parse::token;
29 use syntax;
30
31 use std::cell::{Cell, RefCell};
32 use std::hashmap::{HashMap,HashSet};
33
34 pub struct Config {
35     os: abi::Os,
36     arch: abi::Architecture,
37     target_strs: target_strs::t,
38     int_type: IntTy,
39     uint_type: UintTy,
40 }
41
42 macro_rules! debugging_opts(
43     ([ $opt:ident ] $cnt:expr ) => (
44         pub static $opt: u64 = 1 << $cnt;
45     );
46     ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
47         pub static $opt: u64 = 1 << $cnt;
48         debugging_opts!([ $($rest),* ] $cnt + 1)
49     )
50 )
51
52 debugging_opts!(
53     [
54         VERBOSE,
55         TIME_PASSES,
56         COUNT_LLVM_INSNS,
57         TIME_LLVM_PASSES,
58         TRANS_STATS,
59         ASM_COMMENTS,
60         NO_VERIFY,
61         BORROWCK_STATS,
62         NO_LANDING_PADS,
63         DEBUG_LLVM,
64         COUNT_TYPE_SIZES,
65         META_STATS,
66         NO_OPT,
67         GC,
68         DEBUG_INFO,
69         EXTRA_DEBUG_INFO,
70         PRINT_LINK_ARGS,
71         PRINT_LLVM_PASSES,
72         NO_VECTORIZE_LOOPS,
73         NO_VECTORIZE_SLP,
74         NO_PREPOPULATE_PASSES,
75         USE_SOFTFP,
76         GEN_CRATE_MAP,
77         PREFER_DYNAMIC,
78         NO_INTEGRATED_AS,
79         LTO
80     ]
81     0
82 )
83
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",
90       TIME_LLVM_PASSES),
91      ("trans-stats", "gather trans statistics", TRANS_STATS),
92      ("asm-comments", "generate comments into the assembly (may change behavior)",
93       ASM_COMMENTS),
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",
97       NO_LANDING_PADS),
98      ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
99      ("count-type-sizes", "count the sizes of aggregate types",
100       COUNT_TYPE_SIZES),
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",
104       PRINT_LINK_ARGS),
105      ("gc", "Garbage collect shared data (experimental)", GC),
106      ("extra-debug-info", "Extra debugging info (experimental)",
107       EXTRA_DEBUG_INFO),
108      ("debug-info", "Produce debug info (experimental)", DEBUG_INFO),
109      ("print-llvm-passes",
110       "Prints the llvm optimization passes being run",
111       PRINT_LLVM_PASSES),
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",
118       NO_VECTORIZE_LOOPS),
119      ("no-vectorize-slp", "Don't run LLVM's SLP vectorization passes",
120       NO_VECTORIZE_SLP),
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),
124      ("no-integrated-as",
125       "Use external assembler rather than LLVM's integrated one", NO_INTEGRATED_AS),
126      ("lto", "Perform LLVM link-time optimizations", LTO),
127     ]
128 }
129
130 #[deriving(Clone, Eq)]
131 pub enum OptLevel {
132     No, // -O0
133     Less, // -O1
134     Default, // -O2
135     Aggressive // -O3
136 }
137
138 #[deriving(Clone)]
139 pub struct Options {
140     // The crate config requested for the session, which may be combined
141     // with additional crate configurations during the compile process
142     outputs: ~[OutputStyle],
143
144     gc: bool,
145     optimize: OptLevel,
146     custom_passes: ~[~str],
147     llvm_args: ~[~str],
148     debuginfo: bool,
149     extra_debuginfo: bool,
150     lint_opts: ~[(lint::Lint, lint::level)],
151     save_temps: bool,
152     output_type: back::link::OutputType,
153     // This is mutable for rustpkg, which updates search paths based on the
154     // parsed code.
155     addl_lib_search_paths: @RefCell<HashSet<Path>>,
156     ar: Option<~str>,
157     linker: Option<~str>,
158     linker_args: ~[~str],
159     maybe_sysroot: Option<@Path>,
160     target_triple: ~str,
161     target_cpu: ~str,
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,
168     binary: ~str,
169     test: bool,
170     parse_only: bool,
171     no_trans: bool,
172     no_analysis: bool,
173     no_rpath: bool,
174     debugging_opts: u64,
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),
180 }
181
182 // The type of entry function, so
183 // users can have their own entry
184 // functions that don't start a
185 // scheduler
186 #[deriving(Eq)]
187 pub enum EntryFnType {
188     EntryMain,
189     EntryStart,
190     EntryNone,
191 }
192
193 #[deriving(Eq, Clone, TotalOrd, TotalEq)]
194 pub enum OutputStyle {
195     OutputExecutable,
196     OutputDylib,
197     OutputRlib,
198     OutputStaticlib,
199 }
200
201 pub struct Session_ {
202     targ_cfg: @Config,
203     opts: @Options,
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>,
217     working_dir: Path,
218     lints: RefCell<HashMap<ast::NodeId,
219                            ~[(lint::Lint, codemap::Span, ~str)]>>,
220     node_id: Cell<ast::NodeId>,
221     outputs: @RefCell<~[OutputStyle]>,
222 }
223
224 pub type Session = @Session_;
225
226 impl Session_ {
227     pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
228         self.span_diagnostic.span_fatal(sp, msg)
229     }
230     pub fn fatal(&self, msg: &str) -> ! {
231         self.span_diagnostic.handler().fatal(msg)
232     }
233     pub fn span_err(&self, sp: Span, msg: &str) {
234         self.span_diagnostic.span_err(sp, msg)
235     }
236     pub fn err(&self, msg: &str) {
237         self.span_diagnostic.handler().err(msg)
238     }
239     pub fn err_count(&self) -> uint {
240         self.span_diagnostic.handler().err_count()
241     }
242     pub fn has_errors(&self) -> bool {
243         self.span_diagnostic.handler().has_errors()
244     }
245     pub fn abort_if_errors(&self) {
246         self.span_diagnostic.handler().abort_if_errors()
247     }
248     pub fn span_warn(&self, sp: Span, msg: &str) {
249         self.span_diagnostic.span_warn(sp, msg)
250     }
251     pub fn warn(&self, msg: &str) {
252         self.span_diagnostic.handler().warn(msg)
253     }
254     pub fn span_note(&self, sp: Span, msg: &str) {
255         self.span_diagnostic.span_note(sp, msg)
256     }
257     pub fn span_end_note(&self, sp: Span, msg: &str) {
258         self.span_diagnostic.span_end_note(sp, msg)
259     }
260     pub fn note(&self, msg: &str) {
261         self.span_diagnostic.handler().note(msg)
262     }
263     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
264         self.span_diagnostic.span_bug(sp, msg)
265     }
266     pub fn bug(&self, msg: &str) -> ! {
267         self.span_diagnostic.handler().bug(msg)
268     }
269     pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
270         self.span_diagnostic.span_unimpl(sp, msg)
271     }
272     pub fn unimpl(&self, msg: &str) -> ! {
273         self.span_diagnostic.handler().unimpl(msg)
274     }
275     pub fn add_lint(&self,
276                     lint: lint::Lint,
277                     id: ast::NodeId,
278                     sp: Span,
279                     msg: ~str) {
280         let mut lints = self.lints.borrow_mut();
281         match lints.get().find_mut(&id) {
282             Some(arr) => { arr.push((lint, sp, msg)); return; }
283             None => {}
284         }
285         lints.get().insert(id, ~[(lint, sp, msg)]);
286     }
287     pub fn next_node_id(&self) -> ast::NodeId {
288         self.reserve_node_ids(1)
289     }
290     pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
291         let v = self.node_id.get();
292
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!")
296         }
297
298         v
299     }
300     pub fn diagnostic(&self) -> @diagnostic::SpanHandler {
301         self.span_diagnostic
302     }
303     pub fn debugging_opt(&self, opt: u64) -> bool {
304         (self.opts.debugging_opts & opt) != 0
305     }
306     // This exists to help with refactoring to eliminate impossible
307     // cases later on
308     pub fn impossible_case(&self, sp: Span, msg: &str) -> ! {
309         self.span_bug(sp, format!("Impossible case reached: {}", msg));
310     }
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)
315     }
316     pub fn count_type_sizes(&self) -> bool {
317         self.debugging_opt(COUNT_TYPE_SIZES)
318     }
319     pub fn time_llvm_passes(&self) -> bool {
320         self.debugging_opt(TIME_LLVM_PASSES)
321     }
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)
329     }
330     pub fn no_prepopulate_passes(&self) -> bool {
331         self.debugging_opt(NO_PREPOPULATE_PASSES)
332     }
333     pub fn no_vectorize_loops(&self) -> bool {
334         self.debugging_opt(NO_VECTORIZE_LOOPS)
335     }
336     pub fn no_vectorize_slp(&self) -> bool {
337         self.debugging_opt(NO_VECTORIZE_SLP)
338     }
339     pub fn gen_crate_map(&self) -> bool {
340         self.debugging_opt(GEN_CRATE_MAP)
341     }
342     pub fn prefer_dynamic(&self) -> bool {
343         self.debugging_opt(PREFER_DYNAMIC)
344     }
345     pub fn no_integrated_as(&self) -> bool {
346         self.debugging_opt(NO_INTEGRATED_AS)
347     }
348     pub fn lto(&self) -> bool {
349         self.debugging_opt(LTO)
350     }
351     pub fn no_landing_pads(&self) -> bool {
352         self.debugging_opt(NO_LANDING_PADS)
353     }
354
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()
360     }
361
362     // pointless function, now...
363     pub fn ident_of(&self, st: &str) -> ast::Ident {
364         token::str_to_ident(st)
365     }
366
367     // pointless function, now...
368     pub fn intr(&self) -> @syntax::parse::token::IdentInterner {
369         token::get_ident_interner()
370     }
371 }
372
373 /// Some reasonable defaults
374 pub fn basic_options() -> @Options {
375     @Options {
376         outputs: ~[],
377         gc: false,
378         optimize: No,
379         custom_passes: ~[],
380         llvm_args: ~[],
381         debuginfo: false,
382         extra_debuginfo: false,
383         lint_opts: ~[],
384         save_temps: false,
385         output_type: link::OutputTypeExe,
386         addl_lib_search_paths: @RefCell::new(HashSet::new()),
387         ar: None,
388         linker: None,
389         linker_args: ~[],
390         maybe_sysroot: None,
391         target_triple: host_triple(),
392         target_cpu: ~"generic",
393         target_feature: ~"",
394         cfg: ~[],
395         binary: ~"rustc",
396         test: false,
397         parse_only: false,
398         no_trans: false,
399         no_analysis: false,
400         no_rpath: false,
401         debugging_opts: 0,
402         android_cross_path: None,
403         write_dependency_info: (false, None),
404         print_metas: (false, false, false),
405     }
406 }
407
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)
411 }
412
413 pub fn building_library(options: &Options, crate: &ast::Crate) -> bool {
414     if options.test { return false }
415     for output in options.outputs.iter() {
416         match *output {
417             OutputExecutable => {}
418             OutputStaticlib | OutputDylib | OutputRlib => return true
419         }
420     }
421     match syntax::attr::first_attr_value_str_by_name(crate.attrs, "crate_type") {
422         Some(s) => {
423             s.equiv(&("lib")) ||
424             s.equiv(&("rlib")) ||
425             s.equiv(&("dylib")) ||
426             s.equiv(&("staticlib"))
427         }
428         _ => false
429     }
430 }
431
432 pub fn default_lib_output() -> OutputStyle {
433     OutputRlib
434 }
435
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];
442     }
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())
451                 }
452                 Some(ref n) if n.equiv(&("staticlib")) => {
453                     Some(OutputStaticlib)
454                 }
455                 Some(ref n) if n.equiv(&("bin")) => Some(OutputExecutable),
456                 Some(_) => {
457                     session.add_lint(lint::UnknownCrateType,
458                                      ast::CRATE_NODE_ID,
459                                      a.span,
460                                      ~"invalid `crate_type` value");
461                     None
462                 }
463                 _ => {
464                     session.add_lint(lint::UnknownCrateType, ast::CRATE_NODE_ID,
465                                     a.span, ~"`crate_type` requires a value");
466                     None
467                 }
468             }
469         } else {
470             None
471         }
472     });
473     base.extend(&mut iter);
474     if base.len() == 0 {
475         base.push(OutputExecutable);
476     }
477     base.sort();
478     base.dedup();
479     return base;
480 }
481
482 pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
483     use metadata::loader;
484
485     match os {
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
491     }
492 }