]> git.lizzy.rs Git - rust.git/blob - src/librustc/driver/config.rs
Get rid of the android-cross-path flag to rustc.
[rust.git] / src / librustc / driver / config.rs
1 // Copyright 2014 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 //! Contains infrastructure for configuring the compiler, including parsing
12 //! command line options.
13
14 use driver::early_error;
15 use driver::driver;
16 use driver::session::Session;
17
18 use back;
19 use back::link;
20 use back::target_strs;
21 use back::{arm, x86, x86_64, mips};
22 use metadata;
23 use middle::lint;
24
25 use syntax::abi;
26 use syntax::ast;
27 use syntax::ast::{IntTy, UintTy};
28 use syntax::attr;
29 use syntax::attr::AttrMetaMethods;
30 use syntax::parse;
31 use syntax::parse::token::InternedString;
32
33 use collections::HashSet;
34 use getopts::{optopt, optmulti, optflag, optflagopt};
35 use getopts;
36 use lib::llvm::llvm;
37 use std::cell::{RefCell};
38
39
40 pub struct Config {
41     pub os: abi::Os,
42     pub arch: abi::Architecture,
43     pub target_strs: target_strs::t,
44     pub int_type: IntTy,
45     pub uint_type: UintTy,
46 }
47
48 #[deriving(Clone, Eq)]
49 pub enum OptLevel {
50     No, // -O0
51     Less, // -O1
52     Default, // -O2
53     Aggressive // -O3
54 }
55
56 #[deriving(Clone, Eq)]
57 pub enum DebugInfoLevel {
58     NoDebugInfo,
59     LimitedDebugInfo,
60     FullDebugInfo,
61 }
62
63 #[deriving(Clone)]
64 pub struct Options {
65     // The crate config requested for the session, which may be combined
66     // with additional crate configurations during the compile process
67     pub crate_types: Vec<CrateType>,
68
69     pub gc: bool,
70     pub optimize: OptLevel,
71     pub debuginfo: DebugInfoLevel,
72     pub lint_opts: Vec<(lint::Lint, lint::level)> ,
73     pub output_types: Vec<back::link::OutputType> ,
74     // This was mutable for rustpkg, which updates search paths based on the
75     // parsed code. It remains mutable in case its replacements wants to use
76     // this.
77     pub addl_lib_search_paths: RefCell<HashSet<Path>>,
78     pub maybe_sysroot: Option<Path>,
79     pub target_triple: StrBuf,
80     // User-specified cfg meta items. The compiler itself will add additional
81     // items to the crate config, and during parsing the entire crate config
82     // will be added to the crate AST node.  This should not be used for
83     // anything except building the full crate config prior to parsing.
84     pub cfg: ast::CrateConfig,
85     pub test: bool,
86     pub parse_only: bool,
87     pub no_trans: bool,
88     pub no_analysis: bool,
89     pub debugging_opts: u64,
90     /// Whether to write dependency files. It's (enabled, optional filename).
91     pub write_dependency_info: (bool, Option<Path>),
92     /// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
93     pub print_metas: (bool, bool, bool),
94     pub cg: CodegenOptions,
95 }
96
97 /// Some reasonable defaults
98 pub fn basic_options() -> Options {
99     Options {
100         crate_types: Vec::new(),
101         gc: false,
102         optimize: No,
103         debuginfo: NoDebugInfo,
104         lint_opts: Vec::new(),
105         output_types: Vec::new(),
106         addl_lib_search_paths: RefCell::new(HashSet::new()),
107         maybe_sysroot: None,
108         target_triple: driver::host_triple().to_strbuf(),
109         cfg: Vec::new(),
110         test: false,
111         parse_only: false,
112         no_trans: false,
113         no_analysis: false,
114         debugging_opts: 0,
115         write_dependency_info: (false, None),
116         print_metas: (false, false, false),
117         cg: basic_codegen_options(),
118     }
119 }
120
121 // The type of entry function, so
122 // users can have their own entry
123 // functions that don't start a
124 // scheduler
125 #[deriving(Eq)]
126 pub enum EntryFnType {
127     EntryMain,
128     EntryStart,
129     EntryNone,
130 }
131
132 #[deriving(Eq, Ord, Clone, TotalOrd, TotalEq, Hash)]
133 pub enum CrateType {
134     CrateTypeExecutable,
135     CrateTypeDylib,
136     CrateTypeRlib,
137     CrateTypeStaticlib,
138 }
139
140 macro_rules! debugging_opts(
141     ([ $opt:ident ] $cnt:expr ) => (
142         pub static $opt: u64 = 1 << $cnt;
143     );
144     ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
145         pub static $opt: u64 = 1 << $cnt;
146         debugging_opts!([ $($rest),* ] $cnt + 1)
147     )
148 )
149
150 debugging_opts!(
151     [
152         VERBOSE,
153         TIME_PASSES,
154         COUNT_LLVM_INSNS,
155         TIME_LLVM_PASSES,
156         TRANS_STATS,
157         ASM_COMMENTS,
158         NO_VERIFY,
159         BORROWCK_STATS,
160         NO_LANDING_PADS,
161         DEBUG_LLVM,
162         SHOW_SPAN,
163         COUNT_TYPE_SIZES,
164         META_STATS,
165         NO_OPT,
166         GC,
167         PRINT_LINK_ARGS,
168         PRINT_LLVM_PASSES,
169         LTO,
170         AST_JSON,
171         AST_JSON_NOEXPAND,
172         LS
173     ]
174     0
175 )
176
177 pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
178     vec!(("verbose", "in general, enable more debug printouts", VERBOSE),
179      ("time-passes", "measure time of each rustc pass", TIME_PASSES),
180      ("count-llvm-insns", "count where LLVM \
181                            instrs originate", COUNT_LLVM_INSNS),
182      ("time-llvm-passes", "measure time of each LLVM pass",
183       TIME_LLVM_PASSES),
184      ("trans-stats", "gather trans statistics", TRANS_STATS),
185      ("asm-comments", "generate comments into the assembly (may change behavior)",
186       ASM_COMMENTS),
187      ("no-verify", "skip LLVM verification", NO_VERIFY),
188      ("borrowck-stats", "gather borrowck statistics",  BORROWCK_STATS),
189      ("no-landing-pads", "omit landing pads for unwinding",
190       NO_LANDING_PADS),
191      ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
192      ("show-span", "show spans for compiler debugging", SHOW_SPAN),
193      ("count-type-sizes", "count the sizes of aggregate types",
194       COUNT_TYPE_SIZES),
195      ("meta-stats", "gather metadata statistics", META_STATS),
196      ("no-opt", "do not optimize, even if -O is passed", NO_OPT),
197      ("print-link-args", "Print the arguments passed to the linker",
198       PRINT_LINK_ARGS),
199      ("gc", "Garbage collect shared data (experimental)", GC),
200      ("print-llvm-passes",
201       "Prints the llvm optimization passes being run",
202       PRINT_LLVM_PASSES),
203      ("lto", "Perform LLVM link-time optimizations", LTO),
204      ("ast-json", "Print the AST as JSON and halt", AST_JSON),
205      ("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
206      ("ls", "List the symbols defined by a library crate", LS))
207 }
208
209 /// Declare a macro that will define all CodegenOptions fields and parsers all
210 /// at once. The goal of this macro is to define an interface that can be
211 /// programmatically used by the option parser in order to initialize the struct
212 /// without hardcoding field names all over the place.
213 ///
214 /// The goal is to invoke this macro once with the correct fields, and then this
215 /// macro generates all necessary code. The main gotcha of this macro is the
216 /// cgsetters module which is a bunch of generated code to parse an option into
217 /// its respective field in the struct. There are a few hand-written parsers for
218 /// parsing specific types of values in this module.
219 macro_rules! cgoptions(
220     ($($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
221 (
222     #[deriving(Clone)]
223     pub struct CodegenOptions { $(pub $opt: $t),* }
224
225     pub fn basic_codegen_options() -> CodegenOptions {
226         CodegenOptions { $($opt: $init),* }
227     }
228
229     pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool;
230     pub static CG_OPTIONS: &'static [(&'static str, CodegenSetter,
231                                       &'static str)] =
232         &[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];
233
234     mod cgsetters {
235         use super::CodegenOptions;
236
237         $(
238             pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
239                 $parse(&mut cg.$opt, v)
240             }
241         )*
242
243         fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
244             match v {
245                 Some(..) => false,
246                 None => { *slot = true; true }
247             }
248         }
249
250         fn parse_opt_string(slot: &mut Option<StrBuf>, v: Option<&str>) -> bool {
251             match v {
252                 Some(s) => { *slot = Some(s.to_strbuf()); true },
253                 None => false,
254             }
255         }
256
257         fn parse_string(slot: &mut StrBuf, v: Option<&str>) -> bool {
258             match v {
259                 Some(s) => { *slot = s.to_strbuf(); true },
260                 None => false,
261             }
262         }
263
264         fn parse_list(slot: &mut Vec<StrBuf>, v: Option<&str>)
265                       -> bool {
266             match v {
267                 Some(s) => {
268                     for s in s.words() {
269                         slot.push(s.to_strbuf());
270                     }
271                     true
272                 },
273                 None => false,
274             }
275         }
276
277     }
278 ) )
279
280 cgoptions!(
281     ar: Option<StrBuf> = (None, parse_opt_string,
282         "tool to assemble archives with"),
283     linker: Option<StrBuf> = (None, parse_opt_string,
284         "system linker to link outputs with"),
285     link_args: Vec<StrBuf> = (Vec::new(), parse_list,
286         "extra arguments to pass to the linker (space separated)"),
287     target_cpu: StrBuf = ("generic".to_strbuf(), parse_string,
288         "select target processor (llc -mcpu=help for details)"),
289     target_feature: StrBuf = ("".to_strbuf(), parse_string,
290         "target specific attributes (llc -mattr=help for details)"),
291     passes: Vec<StrBuf> = (Vec::new(), parse_list,
292         "a list of extra LLVM passes to run (space separated)"),
293     llvm_args: Vec<StrBuf> = (Vec::new(), parse_list,
294         "a list of arguments to pass to llvm (space separated)"),
295     save_temps: bool = (false, parse_bool,
296         "save all temporary output files during compilation"),
297     no_rpath: bool = (false, parse_bool,
298         "disables setting the rpath in libs/exes"),
299     no_prepopulate_passes: bool = (false, parse_bool,
300         "don't pre-populate the pass manager with a list of passes"),
301     no_vectorize_loops: bool = (false, parse_bool,
302         "don't run the loop vectorization optimization passes"),
303     no_vectorize_slp: bool = (false, parse_bool,
304         "don't run LLVM's SLP vectorization pass"),
305     soft_float: bool = (false, parse_bool,
306         "generate software floating point library calls"),
307     prefer_dynamic: bool = (false, parse_bool,
308         "prefer dynamic linking to static linking"),
309     no_integrated_as: bool = (false, parse_bool,
310         "use an external assembler rather than LLVM's integrated one"),
311     relocation_model: StrBuf = ("pic".to_strbuf(), parse_string,
312          "choose the relocation model to use (llc -relocation-model for details)"),
313 )
314
315 pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
316 {
317     let mut cg = basic_codegen_options();
318     for option in matches.opt_strs("C").move_iter() {
319         let mut iter = option.splitn('=', 1);
320         let key = iter.next().unwrap();
321         let value = iter.next();
322         let option_to_lookup = key.replace("-", "_");
323         let mut found = false;
324         for &(candidate, setter, _) in CG_OPTIONS.iter() {
325             if option_to_lookup.as_slice() != candidate { continue }
326             if !setter(&mut cg, value) {
327                 match value {
328                     Some(..) => early_error(format!("codegen option `{}` takes \
329                                                      no value", key)),
330                     None => early_error(format!("codegen option `{0}` requires \
331                                                  a value (-C {0}=<value>)",
332                                                 key))
333                 }
334             }
335             found = true;
336             break;
337         }
338         if !found {
339             early_error(format!("unknown codegen option: `{}`", key));
340         }
341     }
342     return cg;
343 }
344
345 pub fn default_lib_output() -> CrateType {
346     CrateTypeRlib
347 }
348
349 pub fn cfg_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
350     use metadata::loader;
351
352     match os {
353         abi::OsWin32 => loader::OsWin32,
354         abi::OsLinux => loader::OsLinux,
355         abi::OsAndroid => loader::OsAndroid,
356         abi::OsMacos => loader::OsMacos,
357         abi::OsFreebsd => loader::OsFreebsd
358     }
359 }
360
361 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
362     let tos = match sess.targ_cfg.os {
363         abi::OsWin32 =>   InternedString::new("win32"),
364         abi::OsMacos =>   InternedString::new("macos"),
365         abi::OsLinux =>   InternedString::new("linux"),
366         abi::OsAndroid => InternedString::new("android"),
367         abi::OsFreebsd => InternedString::new("freebsd"),
368     };
369
370     // ARM is bi-endian, however using NDK seems to default
371     // to little-endian unless a flag is provided.
372     let (end,arch,wordsz) = match sess.targ_cfg.arch {
373         abi::X86 =>    ("little", "x86",    "32"),
374         abi::X86_64 => ("little", "x86_64", "64"),
375         abi::Arm =>    ("little", "arm",    "32"),
376         abi::Mips =>   ("big",    "mips",   "32")
377     };
378
379     let fam = match sess.targ_cfg.os {
380         abi::OsWin32 => InternedString::new("windows"),
381         _ => InternedString::new("unix")
382     };
383
384     let mk = attr::mk_name_value_item_str;
385     return vec!(// Target bindings.
386          attr::mk_word_item(fam.clone()),
387          mk(InternedString::new("target_os"), tos),
388          mk(InternedString::new("target_family"), fam),
389          mk(InternedString::new("target_arch"), InternedString::new(arch)),
390          mk(InternedString::new("target_endian"), InternedString::new(end)),
391          mk(InternedString::new("target_word_size"),
392             InternedString::new(wordsz))
393     );
394 }
395
396 pub fn append_configuration(cfg: &mut ast::CrateConfig,
397                             name: InternedString) {
398     if !cfg.iter().any(|mi| mi.name() == name) {
399         cfg.push(attr::mk_word_item(name))
400     }
401 }
402
403 pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
404     // Combine the configuration requested by the session (command line) with
405     // some default and generated configuration items
406     let default_cfg = default_configuration(sess);
407     let mut user_cfg = sess.opts.cfg.clone();
408     // If the user wants a test runner, then add the test cfg
409     if sess.opts.test {
410         append_configuration(&mut user_cfg, InternedString::new("test"))
411     }
412     // If the user requested GC, then add the GC cfg
413     append_configuration(&mut user_cfg, if sess.opts.gc {
414         InternedString::new("gc")
415     } else {
416         InternedString::new("nogc")
417     });
418     user_cfg.move_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
419 }
420
421 pub fn get_os(triple: &str) -> Option<abi::Os> {
422     for &(name, os) in os_names.iter() {
423         if triple.contains(name) { return Some(os) }
424     }
425     None
426 }
427 static os_names : &'static [(&'static str, abi::Os)] = &'static [
428     ("mingw32", abi::OsWin32),
429     ("win32",   abi::OsWin32),
430     ("darwin",  abi::OsMacos),
431     ("android", abi::OsAndroid),
432     ("linux",   abi::OsLinux),
433     ("freebsd", abi::OsFreebsd)];
434
435 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
436     for &(arch, abi) in architecture_abis.iter() {
437         if triple.contains(arch) { return Some(abi) }
438     }
439     None
440 }
441 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
442     ("i386",   abi::X86),
443     ("i486",   abi::X86),
444     ("i586",   abi::X86),
445     ("i686",   abi::X86),
446     ("i786",   abi::X86),
447
448     ("x86_64", abi::X86_64),
449
450     ("arm",    abi::Arm),
451     ("xscale", abi::Arm),
452     ("thumb",  abi::Arm),
453
454     ("mips",   abi::Mips)];
455
456 pub fn build_target_config(sopts: &Options) -> Config {
457     let os = match get_os(sopts.target_triple.as_slice()) {
458       Some(os) => os,
459       None => early_error("unknown operating system")
460     };
461     let arch = match get_arch(sopts.target_triple.as_slice()) {
462       Some(arch) => arch,
463       None => {
464           early_error("unknown architecture: " +
465                       sopts.target_triple.as_slice())
466       }
467     };
468     let (int_type, uint_type) = match arch {
469       abi::X86 => (ast::TyI32, ast::TyU32),
470       abi::X86_64 => (ast::TyI64, ast::TyU64),
471       abi::Arm => (ast::TyI32, ast::TyU32),
472       abi::Mips => (ast::TyI32, ast::TyU32)
473     };
474     let target_triple = sopts.target_triple.clone();
475     let target_strs = match arch {
476       abi::X86 => x86::get_target_strs(target_triple, os),
477       abi::X86_64 => x86_64::get_target_strs(target_triple, os),
478       abi::Arm => arm::get_target_strs(target_triple, os),
479       abi::Mips => mips::get_target_strs(target_triple, os)
480     };
481     Config {
482         os: os,
483         arch: arch,
484         target_strs: target_strs,
485         int_type: int_type,
486         uint_type: uint_type,
487     }
488 }
489
490 // rustc command line options
491 pub fn optgroups() -> Vec<getopts::OptGroup> {
492     vec!(
493         optflag("h", "help", "Display this message"),
494         optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
495         optmulti("L", "",   "Add a directory to the library search path", "PATH"),
496         optmulti("", "crate-type", "Comma separated list of types of crates
497                                     for the compiler to emit",
498                  "[bin|lib|rlib|dylib|staticlib]"),
499         optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
500                  "[asm|bc|ir|obj|link]"),
501         optflag("", "crate-id", "Output the crate id and exit"),
502         optflag("", "crate-name", "Output the crate name and exit"),
503         optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
504               continued and exit"),
505         optflag("g",  "",  "Equivalent to --debuginfo=2"),
506         optopt("",  "debuginfo",  "Emit DWARF debug info to the objects created:
507              0 = no debug info,
508              1 = line-tables only (for stacktraces and breakpoints),
509              2 = full debug info with variable and type information (same as -g)", "LEVEL"),
510         optflag("", "no-trans", "Run all passes except translation; no output"),
511         optflag("", "no-analysis",
512               "Parse and expand the source, but run no analysis and produce no output"),
513         optflag("O", "", "Equivalent to --opt-level=2"),
514         optopt("o", "", "Write output to <filename>", "FILENAME"),
515         optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
516         optopt( "",  "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
517         optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
518         optflagopt("", "pretty",
519                  "Pretty-print the input instead of compiling;
520                   valid types are: normal (un-annotated source),
521                   expanded (crates expanded),
522                   typed (crates expanded, with type annotations),
523                   or identified (fully parenthesized,
524                   AST nodes and blocks with IDs)", "TYPE"),
525         optflagopt("", "dep-info",
526                  "Output dependency info to <filename> after compiling, \
527                   in a format suitable for use by Makefiles", "FILENAME"),
528         optopt("", "sysroot", "Override the system root", "PATH"),
529         optflag("", "test", "Build a test harness"),
530         optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
531                             to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
532                             for details)", "TRIPLE"),
533         optmulti("W", "warn", "Set lint warnings", "OPT"),
534         optmulti("A", "allow", "Set lint allowed", "OPT"),
535         optmulti("D", "deny", "Set lint denied", "OPT"),
536         optmulti("F", "forbid", "Set lint forbidden", "OPT"),
537         optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
538         optmulti("Z", "", "Set internal debugging options", "FLAG"),
539         optflag( "v", "version", "Print version info and exit")
540     )
541 }
542
543
544 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
545 fn parse_cfgspecs(cfgspecs: Vec<StrBuf> ) -> ast::CrateConfig {
546     cfgspecs.move_iter().map(|s| {
547         parse::parse_meta_from_source_str("cfgspec".to_strbuf(),
548                                           s.to_strbuf(),
549                                           Vec::new(),
550                                           &parse::new_parse_sess())
551     }).collect::<ast::CrateConfig>()
552 }
553
554 pub fn build_session_options(matches: &getopts::Matches) -> Options {
555     let mut crate_types: Vec<CrateType> = Vec::new();
556     let unparsed_crate_types = matches.opt_strs("crate-type");
557     for unparsed_crate_type in unparsed_crate_types.iter() {
558         for part in unparsed_crate_type.split(',') {
559             let new_part = match part {
560                 "lib"       => default_lib_output(),
561                 "rlib"      => CrateTypeRlib,
562                 "staticlib" => CrateTypeStaticlib,
563                 "dylib"     => CrateTypeDylib,
564                 "bin"       => CrateTypeExecutable,
565                 _ => early_error(format!("unknown crate type: `{}`", part))
566             };
567             crate_types.push(new_part)
568         }
569     }
570
571     let parse_only = matches.opt_present("parse-only");
572     let no_trans = matches.opt_present("no-trans");
573     let no_analysis = matches.opt_present("no-analysis");
574
575     let lint_levels = [lint::allow, lint::warn,
576                        lint::deny, lint::forbid];
577     let mut lint_opts = Vec::new();
578     let lint_dict = lint::get_lint_dict();
579     for level in lint_levels.iter() {
580         let level_name = lint::level_to_str(*level);
581
582         let level_short = level_name.slice_chars(0, 1);
583         let level_short = level_short.to_ascii().to_upper().into_str();
584         let flags = matches.opt_strs(level_short).move_iter().collect::<Vec<_>>().append(
585                                    matches.opt_strs(level_name).as_slice());
586         for lint_name in flags.iter() {
587             let lint_name = lint_name.replace("-", "_");
588             match lint_dict.find_equiv(&lint_name) {
589               None => {
590                 early_error(format!("unknown {} flag: {}",
591                                     level_name, lint_name));
592               }
593               Some(lint) => {
594                 lint_opts.push((lint.lint, *level));
595               }
596             }
597         }
598     }
599
600     let mut debugging_opts = 0;
601     let debug_flags = matches.opt_strs("Z");
602     let debug_map = debugging_opts_map();
603     for debug_flag in debug_flags.iter() {
604         let mut this_bit = 0;
605         for tuple in debug_map.iter() {
606             let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
607             if *name == *debug_flag { this_bit = bit; break; }
608         }
609         if this_bit == 0 {
610             early_error(format!("unknown debug flag: {}", *debug_flag))
611         }
612         debugging_opts |= this_bit;
613     }
614
615     if debugging_opts & DEBUG_LLVM != 0 {
616         unsafe { llvm::LLVMSetDebug(1); }
617     }
618
619     let mut output_types = Vec::new();
620     if !parse_only && !no_trans {
621         let unparsed_output_types = matches.opt_strs("emit");
622         for unparsed_output_type in unparsed_output_types.iter() {
623             for part in unparsed_output_type.split(',') {
624                 let output_type = match part.as_slice() {
625                     "asm"  => link::OutputTypeAssembly,
626                     "ir"   => link::OutputTypeLlvmAssembly,
627                     "bc"   => link::OutputTypeBitcode,
628                     "obj"  => link::OutputTypeObject,
629                     "link" => link::OutputTypeExe,
630                     _ => early_error(format!("unknown emission type: `{}`", part))
631                 };
632                 output_types.push(output_type)
633             }
634         }
635     };
636     output_types.as_mut_slice().sort();
637     output_types.dedup();
638     if output_types.len() == 0 {
639         output_types.push(link::OutputTypeExe);
640     }
641
642     let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
643     let target = match matches.opt_str("target") {
644         Some(supplied_target) => supplied_target.to_strbuf(),
645         None => driver::host_triple().to_strbuf(),
646     };
647     let opt_level = {
648         if (debugging_opts & NO_OPT) != 0 {
649             No
650         } else if matches.opt_present("O") {
651             if matches.opt_present("opt-level") {
652                 early_error("-O and --opt-level both provided");
653             }
654             Default
655         } else if matches.opt_present("opt-level") {
656             match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
657                 None      |
658                 Some("0") => No,
659                 Some("1") => Less,
660                 Some("2") => Default,
661                 Some("3") => Aggressive,
662                 Some(arg) => {
663                     early_error(format!("optimization level needs to be between 0-3 \
664                                         (instead was `{}`)", arg));
665                 }
666             }
667         } else {
668             No
669         }
670     };
671     let gc = debugging_opts & GC != 0;
672     let debuginfo = if matches.opt_present("g") {
673         if matches.opt_present("debuginfo") {
674             early_error("-g and --debuginfo both provided");
675         }
676         FullDebugInfo
677     } else if matches.opt_present("debuginfo") {
678         match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
679             Some("0") => NoDebugInfo,
680             Some("1") => LimitedDebugInfo,
681             None      |
682             Some("2") => FullDebugInfo,
683             Some(arg) => {
684                 early_error(format!("optimization level needs to be between 0-3 \
685                                     (instead was `{}`)", arg));
686             }
687         }
688     } else {
689         NoDebugInfo
690     };
691
692     let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
693         Path::new(s.as_slice())
694     }).collect();
695
696     let cfg = parse_cfgspecs(matches.opt_strs("cfg")
697                                     .move_iter()
698                                     .map(|x| x.to_strbuf())
699                                     .collect());
700     let test = matches.opt_present("test");
701     let write_dependency_info = (matches.opt_present("dep-info"),
702                                  matches.opt_str("dep-info")
703                                         .map(|p| Path::new(p)));
704
705     let print_metas = (matches.opt_present("crate-id"),
706                        matches.opt_present("crate-name"),
707                        matches.opt_present("crate-file-name"));
708     let cg = build_codegen_options(matches);
709
710     Options {
711         crate_types: crate_types,
712         gc: gc,
713         optimize: opt_level,
714         debuginfo: debuginfo,
715         lint_opts: lint_opts,
716         output_types: output_types,
717         addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
718         maybe_sysroot: sysroot_opt,
719         target_triple: target,
720         cfg: cfg,
721         test: test,
722         parse_only: parse_only,
723         no_trans: no_trans,
724         no_analysis: no_analysis,
725         debugging_opts: debugging_opts,
726         write_dependency_info: write_dependency_info,
727         print_metas: print_metas,
728         cg: cg,
729     }
730 }
731
732
733 #[cfg(test)]
734 mod test {
735
736     use driver::config::{build_configuration, optgroups, build_session_options};
737     use driver::session::build_session;
738
739     use getopts::getopts;
740     use syntax::attr;
741     use syntax::attr::AttrMetaMethods;
742
743     // When the user supplies --test we should implicitly supply --cfg test
744     #[test]
745     fn test_switch_implies_cfg_test() {
746         let matches =
747             &match getopts(["--test".to_owned()], optgroups().as_slice()) {
748               Ok(m) => m,
749               Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
750             };
751         let sessopts = build_session_options(matches);
752         let sess = build_session(sessopts, None);
753         let cfg = build_configuration(&sess);
754         assert!((attr::contains_name(cfg.as_slice(), "test")));
755     }
756
757     // When the user supplies --test and --cfg test, don't implicitly add
758     // another --cfg test
759     #[test]
760     fn test_switch_implies_cfg_test_unless_cfg_test() {
761         let matches =
762             &match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
763                            optgroups().as_slice()) {
764               Ok(m) => m,
765               Err(f) => {
766                 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
767                        f.to_err_msg());
768               }
769             };
770         let sessopts = build_session_options(matches);
771         let sess = build_session(sessopts, None);
772         let cfg = build_configuration(&sess);
773         let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
774         assert!(test_items.next().is_some());
775         assert!(test_items.next().is_none());
776     }
777 }