]> git.lizzy.rs Git - rust.git/blob - src/librustc/driver/session.rs
create a sensible comparison trait hierarchy
[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::target_strs;
13 use back;
14 use driver::driver::host_triple;
15 use front;
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::{abi, ast, codemap};
27 use syntax;
28
29 use std::cell::{Cell, RefCell};
30 use std::vec_ng::Vec;
31 use collections::{HashMap,HashSet};
32
33 pub struct Config {
34     os: abi::Os,
35     arch: abi::Architecture,
36     target_strs: target_strs::t,
37     int_type: IntTy,
38     uint_type: UintTy,
39 }
40
41 macro_rules! debugging_opts(
42     ([ $opt:ident ] $cnt:expr ) => (
43         pub static $opt: u64 = 1 << $cnt;
44     );
45     ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
46         pub static $opt: u64 = 1 << $cnt;
47         debugging_opts!([ $($rest),* ] $cnt + 1)
48     )
49 )
50
51 debugging_opts!(
52     [
53         VERBOSE,
54         TIME_PASSES,
55         COUNT_LLVM_INSNS,
56         TIME_LLVM_PASSES,
57         TRANS_STATS,
58         ASM_COMMENTS,
59         NO_VERIFY,
60         BORROWCK_STATS,
61         NO_LANDING_PADS,
62         DEBUG_LLVM,
63         SHOW_SPAN,
64         COUNT_TYPE_SIZES,
65         META_STATS,
66         NO_OPT,
67         GC,
68         PRINT_LINK_ARGS,
69         PRINT_LLVM_PASSES,
70         LTO,
71         AST_JSON,
72         AST_JSON_NOEXPAND
73     ]
74     0
75 )
76
77 pub fn debugging_opts_map() -> ~[(&'static str, &'static str, u64)] {
78     ~[("verbose", "in general, enable more debug printouts", VERBOSE),
79      ("time-passes", "measure time of each rustc pass", TIME_PASSES),
80      ("count-llvm-insns", "count where LLVM \
81                            instrs originate", COUNT_LLVM_INSNS),
82      ("time-llvm-passes", "measure time of each LLVM pass",
83       TIME_LLVM_PASSES),
84      ("trans-stats", "gather trans statistics", TRANS_STATS),
85      ("asm-comments", "generate comments into the assembly (may change behavior)",
86       ASM_COMMENTS),
87      ("no-verify", "skip LLVM verification", NO_VERIFY),
88      ("borrowck-stats", "gather borrowck statistics",  BORROWCK_STATS),
89      ("no-landing-pads", "omit landing pads for unwinding",
90       NO_LANDING_PADS),
91      ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
92      ("show-span", "show spans for compiler debugging", SHOW_SPAN),
93      ("count-type-sizes", "count the sizes of aggregate types",
94       COUNT_TYPE_SIZES),
95      ("meta-stats", "gather metadata statistics", META_STATS),
96      ("no-opt", "do not optimize, even if -O is passed", NO_OPT),
97      ("print-link-args", "Print the arguments passed to the linker",
98       PRINT_LINK_ARGS),
99      ("gc", "Garbage collect shared data (experimental)", GC),
100      ("print-llvm-passes",
101       "Prints the llvm optimization passes being run",
102       PRINT_LLVM_PASSES),
103      ("lto", "Perform LLVM link-time optimizations", LTO),
104      ("ast-json", "Print the AST as JSON and halt", AST_JSON),
105      ("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
106     ]
107 }
108
109 #[deriving(Clone, Eq)]
110 pub enum OptLevel {
111     No, // -O0
112     Less, // -O1
113     Default, // -O2
114     Aggressive // -O3
115 }
116
117 #[deriving(Clone, Eq)]
118 pub enum DebugInfoLevel {
119     NoDebugInfo,
120     LimitedDebugInfo,
121     FullDebugInfo,
122 }
123
124 #[deriving(Clone)]
125 pub struct Options {
126     // The crate config requested for the session, which may be combined
127     // with additional crate configurations during the compile process
128     crate_types: ~[CrateType],
129
130     gc: bool,
131     optimize: OptLevel,
132     debuginfo: DebugInfoLevel,
133     lint_opts: ~[(lint::Lint, lint::level)],
134     output_types: ~[back::link::OutputType],
135     // This was mutable for rustpkg, which updates search paths based on the
136     // parsed code. It remains mutable in case its replacements wants to use
137     // this.
138     addl_lib_search_paths: @RefCell<HashSet<Path>>,
139     maybe_sysroot: Option<@Path>,
140     target_triple: ~str,
141     // User-specified cfg meta items. The compiler itself will add additional
142     // items to the crate config, and during parsing the entire crate config
143     // will be added to the crate AST node.  This should not be used for
144     // anything except building the full crate config prior to parsing.
145     cfg: ast::CrateConfig,
146     test: bool,
147     parse_only: bool,
148     no_trans: bool,
149     no_analysis: bool,
150     debugging_opts: u64,
151     /// Whether to write dependency files. It's (enabled, optional filename).
152     write_dependency_info: (bool, Option<Path>),
153     /// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
154     print_metas: (bool, bool, bool),
155     cg: CodegenOptions,
156 }
157
158 // The type of entry function, so
159 // users can have their own entry
160 // functions that don't start a
161 // scheduler
162 #[deriving(Eq)]
163 pub enum EntryFnType {
164     EntryMain,
165     EntryStart,
166     EntryNone,
167 }
168
169 #[deriving(Eq, Ord, Clone, TotalOrd, TotalEq)]
170 pub enum CrateType {
171     CrateTypeExecutable,
172     CrateTypeDylib,
173     CrateTypeRlib,
174     CrateTypeStaticlib,
175 }
176
177 pub struct Session_ {
178     targ_cfg: @Config,
179     opts: @Options,
180     cstore: @metadata::cstore::CStore,
181     parse_sess: @ParseSess,
182     codemap: @codemap::CodeMap,
183     // For a library crate, this is always none
184     entry_fn: RefCell<Option<(NodeId, codemap::Span)>>,
185     entry_type: Cell<Option<EntryFnType>>,
186     span_diagnostic: @diagnostic::SpanHandler,
187     macro_registrar_fn: RefCell<Option<ast::DefId>>,
188     filesearch: @filesearch::FileSearch,
189     building_library: Cell<bool>,
190     // The name of the root source file of the crate, in the local file system. The path is always
191     // expected to be absolute. `None` means that there is no source file.
192     local_crate_source_file: Option<Path>,
193     working_dir: Path,
194     lints: RefCell<HashMap<ast::NodeId,
195                            ~[(lint::Lint, codemap::Span, ~str)]>>,
196     node_id: Cell<ast::NodeId>,
197     crate_types: @RefCell<~[CrateType]>,
198     features: front::feature_gate::Features
199 }
200
201 pub type Session = @Session_;
202
203 impl Session_ {
204     pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
205         self.span_diagnostic.span_fatal(sp, msg)
206     }
207     pub fn fatal(&self, msg: &str) -> ! {
208         self.span_diagnostic.handler().fatal(msg)
209     }
210     pub fn span_err(&self, sp: Span, msg: &str) {
211         self.span_diagnostic.span_err(sp, msg)
212     }
213     pub fn err(&self, msg: &str) {
214         self.span_diagnostic.handler().err(msg)
215     }
216     pub fn err_count(&self) -> uint {
217         self.span_diagnostic.handler().err_count()
218     }
219     pub fn has_errors(&self) -> bool {
220         self.span_diagnostic.handler().has_errors()
221     }
222     pub fn abort_if_errors(&self) {
223         self.span_diagnostic.handler().abort_if_errors()
224     }
225     pub fn span_warn(&self, sp: Span, msg: &str) {
226         self.span_diagnostic.span_warn(sp, msg)
227     }
228     pub fn warn(&self, msg: &str) {
229         self.span_diagnostic.handler().warn(msg)
230     }
231     pub fn span_note(&self, sp: Span, msg: &str) {
232         self.span_diagnostic.span_note(sp, msg)
233     }
234     pub fn span_end_note(&self, sp: Span, msg: &str) {
235         self.span_diagnostic.span_end_note(sp, msg)
236     }
237     pub fn note(&self, msg: &str) {
238         self.span_diagnostic.handler().note(msg)
239     }
240     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
241         self.span_diagnostic.span_bug(sp, msg)
242     }
243     pub fn bug(&self, msg: &str) -> ! {
244         self.span_diagnostic.handler().bug(msg)
245     }
246     pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
247         self.span_diagnostic.span_unimpl(sp, msg)
248     }
249     pub fn unimpl(&self, msg: &str) -> ! {
250         self.span_diagnostic.handler().unimpl(msg)
251     }
252     pub fn add_lint(&self,
253                     lint: lint::Lint,
254                     id: ast::NodeId,
255                     sp: Span,
256                     msg: ~str) {
257         let mut lints = self.lints.borrow_mut();
258         match lints.get().find_mut(&id) {
259             Some(arr) => { arr.push((lint, sp, msg)); return; }
260             None => {}
261         }
262         lints.get().insert(id, ~[(lint, sp, msg)]);
263     }
264     pub fn next_node_id(&self) -> ast::NodeId {
265         self.reserve_node_ids(1)
266     }
267     pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
268         let v = self.node_id.get();
269
270         match v.checked_add(&count) {
271             Some(next) => { self.node_id.set(next); }
272             None => self.bug("Input too large, ran out of node ids!")
273         }
274
275         v
276     }
277     pub fn diagnostic(&self) -> @diagnostic::SpanHandler {
278         self.span_diagnostic
279     }
280     pub fn debugging_opt(&self, opt: u64) -> bool {
281         (self.opts.debugging_opts & opt) != 0
282     }
283     // This exists to help with refactoring to eliminate impossible
284     // cases later on
285     pub fn impossible_case(&self, sp: Span, msg: &str) -> ! {
286         self.span_bug(sp, format!("impossible case reached: {}", msg));
287     }
288     pub fn verbose(&self) -> bool { self.debugging_opt(VERBOSE) }
289     pub fn time_passes(&self) -> bool { self.debugging_opt(TIME_PASSES) }
290     pub fn count_llvm_insns(&self) -> bool {
291         self.debugging_opt(COUNT_LLVM_INSNS)
292     }
293     pub fn count_type_sizes(&self) -> bool {
294         self.debugging_opt(COUNT_TYPE_SIZES)
295     }
296     pub fn time_llvm_passes(&self) -> bool {
297         self.debugging_opt(TIME_LLVM_PASSES)
298     }
299     pub fn trans_stats(&self) -> bool { self.debugging_opt(TRANS_STATS) }
300     pub fn meta_stats(&self) -> bool { self.debugging_opt(META_STATS) }
301     pub fn asm_comments(&self) -> bool { self.debugging_opt(ASM_COMMENTS) }
302     pub fn no_verify(&self) -> bool { self.debugging_opt(NO_VERIFY) }
303     pub fn borrowck_stats(&self) -> bool { self.debugging_opt(BORROWCK_STATS) }
304     pub fn print_llvm_passes(&self) -> bool {
305         self.debugging_opt(PRINT_LLVM_PASSES)
306     }
307     pub fn lto(&self) -> bool {
308         self.debugging_opt(LTO)
309     }
310     pub fn no_landing_pads(&self) -> bool {
311         self.debugging_opt(NO_LANDING_PADS)
312     }
313     pub fn show_span(&self) -> bool {
314         self.debugging_opt(SHOW_SPAN)
315     }
316 }
317
318 /// Some reasonable defaults
319 pub fn basic_options() -> @Options {
320     @Options {
321         crate_types: ~[],
322         gc: false,
323         optimize: No,
324         debuginfo: NoDebugInfo,
325         lint_opts: ~[],
326         output_types: ~[],
327         addl_lib_search_paths: @RefCell::new(HashSet::new()),
328         maybe_sysroot: None,
329         target_triple: host_triple(),
330         cfg: Vec::new(),
331         test: false,
332         parse_only: false,
333         no_trans: false,
334         no_analysis: false,
335         debugging_opts: 0,
336         write_dependency_info: (false, None),
337         print_metas: (false, false, false),
338         cg: basic_codegen_options(),
339     }
340 }
341
342 /// Declare a macro that will define all CodegenOptions fields and parsers all
343 /// at once. The goal of this macro is to define an interface that can be
344 /// programmatically used by the option parser in order to initialize the struct
345 /// without hardcoding field names all over the place.
346 ///
347 /// The goal is to invoke this macro once with the correct fields, and then this
348 /// macro generates all necessary code. The main gotcha of this macro is the
349 /// cgsetters module which is a bunch of generated code to parse an option into
350 /// its respective field in the struct. There are a few hand-written parsers for
351 /// parsing specific types of values in this module.
352 macro_rules! cgoptions(
353     ($($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
354 (
355     #[deriving(Clone)]
356     pub struct CodegenOptions { $($opt: $t),* }
357
358     pub fn basic_codegen_options() -> CodegenOptions {
359         CodegenOptions { $($opt: $init),* }
360     }
361
362     pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool;
363     pub static CG_OPTIONS: &'static [(&'static str, CodegenSetter,
364                                       &'static str)] =
365         &[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];
366
367     mod cgsetters {
368         use super::CodegenOptions;
369
370         $(
371             pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
372                 $parse(&mut cg.$opt, v)
373             }
374         )*
375
376         fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
377             match v {
378                 Some(..) => false,
379                 None => { *slot = true; true }
380             }
381         }
382
383         fn parse_opt_string(slot: &mut Option<~str>, v: Option<&str>) -> bool {
384             match v {
385                 Some(s) => { *slot = Some(s.to_owned()); true },
386                 None => false,
387             }
388         }
389
390         fn parse_string(slot: &mut ~str, v: Option<&str>) -> bool {
391             match v {
392                 Some(s) => { *slot = s.to_owned(); true },
393                 None => false,
394             }
395         }
396
397         fn parse_list(slot: &mut ~[~str], v: Option<&str>) -> bool {
398             match v {
399                 Some(s) => {
400                     for s in s.words() {
401                         slot.push(s.to_owned());
402                     }
403                     true
404                 },
405                 None => false,
406             }
407         }
408
409     }
410 ) )
411
412 cgoptions!(
413     ar: Option<~str> = (None, parse_opt_string,
414         "tool to assemble archives with"),
415     linker: Option<~str> = (None, parse_opt_string,
416         "system linker to link outputs with"),
417     link_args: ~[~str] = (~[], parse_list,
418         "extra arguments to pass to the linker (space separated)"),
419     target_cpu: ~str = (~"generic", parse_string,
420         "select target processor (llc -mcpu=help for details)"),
421     target_feature: ~str = (~"", parse_string,
422         "target specific attributes (llc -mattr=help for details)"),
423     passes: ~[~str] = (~[], parse_list,
424         "a list of extra LLVM passes to run (space separated)"),
425     llvm_args: ~[~str] = (~[], parse_list,
426         "a list of arguments to pass to llvm (space separated)"),
427     save_temps: bool = (false, parse_bool,
428         "save all temporary output files during compilation"),
429     android_cross_path: Option<~str> = (None, parse_opt_string,
430         "the path to the Android NDK"),
431     no_rpath: bool = (false, parse_bool,
432         "disables setting the rpath in libs/exes"),
433     no_prepopulate_passes: bool = (false, parse_bool,
434         "don't pre-populate the pass manager with a list of passes"),
435     no_vectorize_loops: bool = (false, parse_bool,
436         "don't run the loop vectorization optimization passes"),
437     no_vectorize_slp: bool = (false, parse_bool,
438         "don't run LLVM's SLP vectorization pass"),
439     soft_float: bool = (false, parse_bool,
440         "generate software floating point library calls"),
441     gen_crate_map: bool = (false, parse_bool,
442         "force generation of a toplevel crate map"),
443     prefer_dynamic: bool = (false, parse_bool,
444         "prefer dynamic linking to static linking"),
445     no_integrated_as: bool = (false, parse_bool,
446         "use an external assembler rather than LLVM's integrated one"),
447 )
448
449 // Seems out of place, but it uses session, so I'm putting it here
450 pub fn expect<T:Clone>(sess: Session, opt: Option<T>, msg: || -> ~str) -> T {
451     diagnostic::expect(sess.diagnostic(), opt, msg)
452 }
453
454 pub fn building_library(options: &Options, krate: &ast::Crate) -> bool {
455     if options.test { return false }
456     for output in options.crate_types.iter() {
457         match *output {
458             CrateTypeExecutable => {}
459             CrateTypeStaticlib | CrateTypeDylib | CrateTypeRlib => return true
460         }
461     }
462     match syntax::attr::first_attr_value_str_by_name(krate.attrs.as_slice(),
463                                                      "crate_type") {
464         Some(s) => {
465             s.equiv(&("lib")) ||
466             s.equiv(&("rlib")) ||
467             s.equiv(&("dylib")) ||
468             s.equiv(&("staticlib"))
469         }
470         _ => false
471     }
472 }
473
474 pub fn default_lib_output() -> CrateType {
475     CrateTypeRlib
476 }
477
478 pub fn collect_crate_types(session: &Session,
479                            attrs: &[ast::Attribute]) -> ~[CrateType] {
480     // If we're generating a test executable, then ignore all other output
481     // styles at all other locations
482     if session.opts.test {
483         return ~[CrateTypeExecutable];
484     }
485     let mut base = session.opts.crate_types.clone();
486     let mut iter = attrs.iter().filter_map(|a| {
487         if a.name().equiv(&("crate_type")) {
488             match a.value_str() {
489                 Some(ref n) if n.equiv(&("rlib")) => Some(CrateTypeRlib),
490                 Some(ref n) if n.equiv(&("dylib")) => Some(CrateTypeDylib),
491                 Some(ref n) if n.equiv(&("lib")) => {
492                     Some(default_lib_output())
493                 }
494                 Some(ref n) if n.equiv(&("staticlib")) => {
495                     Some(CrateTypeStaticlib)
496                 }
497                 Some(ref n) if n.equiv(&("bin")) => Some(CrateTypeExecutable),
498                 Some(_) => {
499                     session.add_lint(lint::UnknownCrateType,
500                                      ast::CRATE_NODE_ID,
501                                      a.span,
502                                      ~"invalid `crate_type` value");
503                     None
504                 }
505                 _ => {
506                     session.add_lint(lint::UnknownCrateType, ast::CRATE_NODE_ID,
507                                     a.span, ~"`crate_type` requires a value");
508                     None
509                 }
510             }
511         } else {
512             None
513         }
514     });
515     base.extend(&mut iter);
516     if base.len() == 0 {
517         base.push(CrateTypeExecutable);
518     }
519     base.sort();
520     base.dedup();
521     return base;
522 }
523
524 pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
525     use metadata::loader;
526
527     match os {
528         abi::OsWin32 => loader::OsWin32,
529         abi::OsLinux => loader::OsLinux,
530         abi::OsAndroid => loader::OsAndroid,
531         abi::OsMacos => loader::OsMacos,
532         abi::OsFreebsd => loader::OsFreebsd
533     }
534 }