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