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