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