]> git.lizzy.rs Git - rust.git/blob - src/librustc/driver/driver.rs
rustc: Add --target-cpu flag to select a more specific processor instead of the defau...
[rust.git] / src / librustc / driver / driver.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::link;
13 use back::{arm, x86, x86_64, mips};
14 use driver::session::{Aggressive};
15 use driver::session::{Session, Session_, No, Less, Default};
16 use driver::session;
17 use front;
18 use lib::llvm::llvm;
19 use lib::llvm::{ContextRef, ModuleRef};
20 use metadata::common::LinkMeta;
21 use metadata::{creader, cstore, filesearch};
22 use metadata;
23 use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
24 use middle;
25 use util::common::time;
26 use util::ppaux;
27
28 use std::hashmap::{HashMap,HashSet};
29 use std::int;
30 use std::io;
31 use std::os;
32 use std::vec;
33 use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
34 use extra::getopts::{opt_present};
35 use extra::getopts;
36 use syntax::ast;
37 use syntax::abi;
38 use syntax::attr;
39 use syntax::attr::{AttrMetaMethods};
40 use syntax::codemap;
41 use syntax::diagnostic;
42 use syntax::parse;
43 use syntax::parse::token;
44 use syntax::print::{pp, pprust};
45 use syntax;
46
47 pub enum pp_mode {
48     ppm_normal,
49     ppm_expanded,
50     ppm_typed,
51     ppm_identified,
52     ppm_expanded_identified
53 }
54
55 /**
56  * The name used for source code that doesn't originate in a file
57  * (e.g. source from stdin or a string)
58  */
59 pub fn anon_src() -> @str { @"<anon>" }
60
61 pub fn source_name(input: &input) -> @str {
62     match *input {
63       file_input(ref ifile) => ifile.to_str().to_managed(),
64       str_input(_) => anon_src()
65     }
66 }
67
68 pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
69    ast::CrateConfig {
70     let (libc, tos) = match sess.targ_cfg.os {
71         session::os_win32 =>   (@"msvcrt.dll", @"win32"),
72         session::os_macos =>   (@"libc.dylib", @"macos"),
73         session::os_linux =>   (@"libc.so.6",  @"linux"),
74         session::os_android => (@"libc.so",    @"android"),
75         session::os_freebsd => (@"libc.so.7",  @"freebsd")
76     };
77
78     // ARM is bi-endian, however using NDK seems to default
79     // to little-endian unless a flag is provided.
80     let (end,arch,wordsz) = match sess.targ_cfg.arch {
81         abi::X86 =>    (@"little", @"x86",    @"32"),
82         abi::X86_64 => (@"little", @"x86_64", @"64"),
83         abi::Arm =>    (@"little", @"arm",    @"32"),
84         abi::Mips =>   (@"big",    @"mips",   @"32")
85     };
86
87     let mk = attr::mk_name_value_item_str;
88     return ~[ // Target bindings.
89          attr::mk_word_item(os::FAMILY.to_managed()),
90          mk(@"target_os", tos),
91          mk(@"target_family", os::FAMILY.to_managed()),
92          mk(@"target_arch", arch),
93          mk(@"target_endian", end),
94          mk(@"target_word_size", wordsz),
95          mk(@"target_libc", libc),
96          // Build bindings.
97          mk(@"build_compiler", argv0),
98          mk(@"build_input", source_name(input))];
99 }
100
101 pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
102     if !cfg.iter().any(|mi| mi.name() == name) {
103         cfg.push(attr::mk_word_item(name))
104     }
105 }
106
107 pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
108    ast::CrateConfig {
109     // Combine the configuration requested by the session (command line) with
110     // some default and generated configuration items
111     let default_cfg = default_configuration(sess, argv0, input);
112     let mut user_cfg = sess.opts.cfg.clone();
113     // If the user wants a test runner, then add the test cfg
114     if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
115     // If the user requested GC, then add the GC cfg
116     append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
117     return vec::append(user_cfg, default_cfg);
118 }
119
120 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
121 fn parse_cfgspecs(cfgspecs: ~[~str],
122                   demitter: diagnostic::Emitter) -> ast::CrateConfig {
123     do cfgspecs.consume_iter().transform |s| {
124         let sess = parse::new_parse_sess(Some(demitter));
125         parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
126     }.collect::<ast::CrateConfig>()
127 }
128
129 pub enum input {
130     /// Load source from file
131     file_input(Path),
132     /// The string is the source
133     // FIXME (#2319): Don't really want to box the source string
134     str_input(@str)
135 }
136
137 pub fn phase_1_parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
138     -> @ast::Crate {
139     time(sess.time_passes(), ~"parsing", || {
140         match *input {
141             file_input(ref file) => {
142                 parse::parse_crate_from_file(&(*file), cfg.clone(), sess.parse_sess)
143             }
144             str_input(src) => {
145                 parse::parse_crate_from_source_str(
146                     anon_src(), src, cfg.clone(), sess.parse_sess)
147             }
148         }
149     })
150 }
151
152 // For continuing compilation after a parsed crate has been
153 // modified
154
155 /// Run the "early phases" of the compiler: initial `cfg` processing,
156 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
157 /// harness if one is to be provided and injection of a dependency on the
158 /// standard library and prelude.
159 pub fn phase_2_configure_and_expand(sess: Session,
160                                     cfg: ast::CrateConfig,
161                                     mut crate: @ast::Crate) -> @ast::Crate {
162     let time_passes = sess.time_passes();
163
164     *sess.building_library = session::building_library(sess.opts.crate_type,
165                                                        crate, sess.opts.test);
166
167
168     // strip before expansion to allow macros to depend on
169     // configuration variables e.g/ in
170     //
171     //   #[macro_escape] #[cfg(foo)]
172     //   mod bar { macro_rules! baz!(() => {{}}) }
173     //
174     // baz! should not use this definition unless foo is enabled.
175     crate = time(time_passes, ~"std macros injection", ||
176                  syntax::ext::expand::inject_std_macros(sess.parse_sess,
177                                                         cfg.clone(),
178                                                         crate));
179
180     crate = time(time_passes, ~"configuration 1", ||
181                  front::config::strip_unconfigured_items(crate));
182
183     crate = time(time_passes, ~"expansion", ||
184                  syntax::ext::expand::expand_crate(sess.parse_sess, cfg.clone(),
185                                                    crate));
186
187     // strip again, in case expansion added anything with a #[cfg].
188     crate = time(time_passes, ~"configuration 2", ||
189                  front::config::strip_unconfigured_items(crate));
190
191     crate = time(time_passes, ~"maybe building test harness", ||
192                  front::test::modify_for_testing(sess, crate));
193
194     crate = time(time_passes, ~"std injection", ||
195                  front::std_inject::maybe_inject_libstd_ref(sess, crate));
196
197     return crate;
198 }
199
200 pub struct CrateAnalysis {
201     exp_map2: middle::resolve::ExportMap2,
202     ty_cx: ty::ctxt,
203     maps: astencode::Maps,
204     reachable: @mut HashSet<ast::NodeId>
205 }
206
207 /// Run the resolution, typechecking, region checking and other
208 /// miscellaneous analysis passes on the crate. Return various
209 /// structures carrying the results of the analysis.
210 pub fn phase_3_run_analysis_passes(sess: Session,
211                                    crate: @ast::Crate) -> CrateAnalysis {
212
213     let time_passes = sess.time_passes();
214     let ast_map = time(time_passes, ~"ast indexing", ||
215                        syntax::ast_map::map_crate(sess.diagnostic(), crate));
216
217     time(time_passes, ~"external crate/lib resolution", ||
218          creader::read_crates(sess.diagnostic(), crate, sess.cstore,
219                               sess.filesearch,
220                               session::sess_os_to_meta_os(sess.targ_cfg.os),
221                               sess.opts.is_static,
222                               token::get_ident_interner()));
223
224     let lang_items = time(time_passes, ~"language item collection", ||
225                           middle::lang_items::collect_language_items(crate, sess));
226
227     let middle::resolve::CrateMap {
228         def_map: def_map,
229         exp_map2: exp_map2,
230         trait_map: trait_map
231     } =
232         time(time_passes, ~"resolution", ||
233              middle::resolve::resolve_crate(sess, lang_items, crate));
234
235     time(time_passes, ~"looking for entry point",
236          || middle::entry::find_entry_point(sess, crate, ast_map));
237
238     let freevars = time(time_passes, ~"freevar finding", ||
239                         freevars::annotate_freevars(def_map, crate));
240
241     let region_map = time(time_passes, ~"region resolution", ||
242                           middle::region::resolve_crate(sess, def_map, crate));
243
244     let rp_set = time(time_passes, ~"region parameterization inference", ||
245                       middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
246
247     let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
248                             region_map, rp_set, lang_items);
249
250     // passes are timed inside typeck
251     let (method_map, vtable_map) = typeck::check_crate(
252         ty_cx, trait_map, crate);
253
254     // These next two const passes can probably be merged
255     time(time_passes, ~"const marking", ||
256          middle::const_eval::process_crate(crate, ty_cx));
257
258     time(time_passes, ~"const checking", ||
259          middle::check_const::check_crate(sess, crate, ast_map, def_map,
260                                           method_map, ty_cx));
261
262     time(time_passes, ~"privacy checking", ||
263          middle::privacy::check_crate(ty_cx, &method_map, crate));
264
265     time(time_passes, ~"effect checking", ||
266          middle::effect::check_crate(ty_cx, method_map, crate));
267
268     time(time_passes, ~"loop checking", ||
269          middle::check_loop::check_crate(ty_cx, crate));
270
271     let middle::moves::MoveMaps {moves_map, moved_variables_set,
272                                  capture_map} =
273         time(time_passes, ~"compute moves", ||
274              middle::moves::compute_moves(ty_cx, method_map, crate));
275
276     time(time_passes, ~"match checking", ||
277          middle::check_match::check_crate(ty_cx, method_map,
278                                           moves_map, crate));
279
280     time(time_passes, ~"liveness checking", ||
281          middle::liveness::check_crate(ty_cx, method_map,
282                                        capture_map, crate));
283
284     let (root_map, write_guard_map) =
285         time(time_passes, ~"borrow checking", ||
286              middle::borrowck::check_crate(ty_cx, method_map,
287                                            moves_map, moved_variables_set,
288                                            capture_map, crate));
289
290     time(time_passes, ~"kind checking", ||
291          kind::check_crate(ty_cx, method_map, crate));
292
293     let reachable_map =
294         time(time_passes, ~"reachability checking", ||
295              reachable::find_reachable(ty_cx, method_map, crate));
296
297     time(time_passes, ~"lint checking", ||
298          lint::check_crate(ty_cx, crate));
299
300     CrateAnalysis {
301         exp_map2: exp_map2,
302         ty_cx: ty_cx,
303         maps: astencode::Maps {
304             root_map: root_map,
305             method_map: method_map,
306             vtable_map: vtable_map,
307             write_guard_map: write_guard_map,
308             capture_map: capture_map
309         },
310         reachable: reachable_map
311     }
312 }
313
314 pub struct CrateTranslation {
315     context: ContextRef,
316     module: ModuleRef,
317     link: LinkMeta
318 }
319
320 /// Run the translation phase to LLVM, after which the AST and analysis can
321 /// be discarded.
322 pub fn phase_4_translate_to_llvm(sess: Session,
323                                  crate: @ast::Crate,
324                                  analysis: &CrateAnalysis,
325                                  outputs: &OutputFilenames) -> CrateTranslation {
326     time(sess.time_passes(), ~"translation", ||
327          trans::base::trans_crate(sess, crate, analysis,
328                                   &outputs.obj_filename))
329 }
330
331 /// Run LLVM itself, producing a bitcode file, assembly file or object file
332 /// as a side effect.
333 pub fn phase_5_run_llvm_passes(sess: Session,
334                                trans: &CrateTranslation,
335                                outputs: &OutputFilenames) {
336
337     // NB: Android hack
338     if sess.targ_cfg.os == session::os_android &&
339         (sess.opts.output_type == link::output_type_object ||
340          sess.opts.output_type == link::output_type_exe) {
341         let output_type = link::output_type_assembly;
342         let obj_filename = outputs.obj_filename.with_filetype("s");
343
344         time(sess.time_passes(), ~"LLVM passes", ||
345             link::write::run_passes(sess,
346                                     trans.context,
347                                     trans.module,
348                                     output_type,
349                                     &obj_filename));
350
351         link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
352     } else {
353         time(sess.time_passes(), ~"LLVM passes", ||
354             link::write::run_passes(sess,
355                                     trans.context,
356                                     trans.module,
357                                     sess.opts.output_type,
358                                     &outputs.obj_filename));
359     }
360 }
361
362 /// Run the linker on any artifacts that resulted from the LLVM run.
363 /// This should produce either a finished executable or library.
364 pub fn phase_6_link_output(sess: Session,
365                            trans: &CrateTranslation,
366                            outputs: &OutputFilenames) {
367     time(sess.time_passes(), ~"linking", ||
368          link::link_binary(sess,
369                            &outputs.obj_filename,
370                            &outputs.out_filename,
371                            trans.link));
372 }
373
374 pub fn stop_after_phase_3(sess: Session) -> bool {
375    if sess.opts.no_trans {
376         debug!("invoked with --no-trans, returning early from compile_input");
377         return true;
378     }
379     return false;
380 }
381
382 pub fn stop_after_phase_1(sess: Session) -> bool {
383     if sess.opts.parse_only {
384         debug!("invoked with --parse-only, returning early from compile_input");
385         return true;
386     }
387     return false;
388 }
389
390 pub fn stop_after_phase_5(sess: Session) -> bool {
391     if sess.opts.output_type != link::output_type_exe {
392         debug!("not building executable, returning early from compile_input");
393         return true;
394     }
395
396     if sess.opts.is_static && *sess.building_library {
397         debug!("building static library, returning early from compile_input");
398         return true;
399     }
400
401     if sess.opts.jit {
402         debug!("running JIT, returning early from compile_input");
403         return true;
404     }
405     return false;
406 }
407
408 #[fixed_stack_segment]
409 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
410                      outdir: &Option<Path>, output: &Option<Path>) {
411     // We need nested scopes here, because the intermediate results can keep
412     // large chunks of memory alive and we want to free them as soon as
413     // possible to keep the peak memory usage low
414     let (outputs, trans) = {
415         let expanded_crate = {
416             let crate = phase_1_parse_input(sess, cfg.clone(), input);
417             if stop_after_phase_1(sess) { return; }
418             phase_2_configure_and_expand(sess, cfg, crate)
419         };
420         let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
421         if stop_after_phase_3(sess) { return; }
422         let outputs = build_output_filenames(input, outdir, output, [], sess);
423         let trans = phase_4_translate_to_llvm(sess, expanded_crate,
424                                               &analysis, outputs);
425         (outputs, trans)
426     };
427     phase_5_run_llvm_passes(sess, &trans, outputs);
428     if stop_after_phase_5(sess) { return; }
429     phase_6_link_output(sess, &trans, outputs);
430 }
431
432 pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
433                           ppm: pp_mode) {
434
435     fn ann_paren_for_expr(node: pprust::ann_node) {
436         match node {
437           pprust::node_expr(s, _) => pprust::popen(s),
438           _ => ()
439         }
440     }
441     fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
442         match node {
443           pprust::node_expr(s, expr) => {
444             pp::space(s.s);
445             pp::word(s.s, "as");
446             pp::space(s.s);
447             pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
448             pprust::pclose(s);
449           }
450           _ => ()
451         }
452     }
453     fn ann_identified_post(node: pprust::ann_node) {
454         match node {
455           pprust::node_item(s, item) => {
456             pp::space(s.s);
457             pprust::synth_comment(s, int::to_str(item.id));
458           }
459           pprust::node_block(s, ref blk) => {
460             pp::space(s.s);
461             pprust::synth_comment(
462                 s, ~"block " + int::to_str(blk.id));
463           }
464           pprust::node_expr(s, expr) => {
465             pp::space(s.s);
466             pprust::synth_comment(s, int::to_str(expr.id));
467             pprust::pclose(s);
468           }
469           pprust::node_pat(s, pat) => {
470             pp::space(s.s);
471             pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
472           }
473         }
474     }
475
476     let crate = phase_1_parse_input(sess, cfg.clone(), input);
477
478     let (crate, is_expanded) = match ppm {
479         ppm_expanded | ppm_expanded_identified | ppm_typed => {
480             (phase_2_configure_and_expand(sess, cfg, crate), true)
481         }
482         _ => (crate, false)
483     };
484
485     let annotation = match ppm {
486         ppm_identified | ppm_expanded_identified => {
487             pprust::pp_ann {
488                 pre: ann_paren_for_expr,
489                 post: ann_identified_post
490             }
491         }
492         ppm_typed => {
493             let analysis = phase_3_run_analysis_passes(sess, crate);
494             pprust::pp_ann {
495                 pre: ann_paren_for_expr,
496                 post: |a| ann_typed_post(analysis.ty_cx, a)
497             }
498         }
499         _ => pprust::no_ann()
500     };
501
502     let src = sess.codemap.get_filemap(source_name(input)).src;
503     do io::with_str_reader(src) |rdr| {
504         pprust::print_crate(sess.codemap, token::get_ident_interner(),
505                             sess.span_diagnostic, crate,
506                             source_name(input),
507                             rdr, io::stdout(),
508                             annotation, is_expanded);
509     }
510 }
511
512 pub fn get_os(triple: &str) -> Option<session::os> {
513     for &(name, os) in os_names.iter() {
514         if triple.contains(name) { return Some(os) }
515     }
516     None
517 }
518 static os_names : &'static [(&'static str, session::os)] = &'static [
519     ("mingw32", session::os_win32),
520     ("win32",   session::os_win32),
521     ("darwin",  session::os_macos),
522     ("android", session::os_android),
523     ("linux",   session::os_linux),
524     ("freebsd", session::os_freebsd)];
525
526 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
527     for &(arch, abi) in architecture_abis.iter() {
528         if triple.contains(arch) { return Some(abi) }
529     }
530     None
531 }
532 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
533     ("i386",   abi::X86),
534     ("i486",   abi::X86),
535     ("i586",   abi::X86),
536     ("i686",   abi::X86),
537     ("i786",   abi::X86),
538
539     ("x86_64", abi::X86_64),
540
541     ("arm",    abi::Arm),
542     ("xscale", abi::Arm),
543
544     ("mips",   abi::Mips)];
545
546 pub fn build_target_config(sopts: @session::options,
547                            demitter: diagnostic::Emitter)
548                         -> @session::config {
549     let os = match get_os(sopts.target_triple) {
550       Some(os) => os,
551       None => early_error(demitter, ~"unknown operating system")
552     };
553     let arch = match get_arch(sopts.target_triple) {
554       Some(arch) => arch,
555       None => early_error(demitter,
556                           ~"unknown architecture: " + sopts.target_triple)
557     };
558     let (int_type, uint_type, float_type) = match arch {
559       abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
560       abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
561       abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
562       abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
563     };
564     let target_strs = match arch {
565       abi::X86 => x86::get_target_strs(os),
566       abi::X86_64 => x86_64::get_target_strs(os),
567       abi::Arm => arm::get_target_strs(os),
568       abi::Mips => mips::get_target_strs(os)
569     };
570     let target_cfg = @session::config {
571         os: os,
572         arch: arch,
573         target_strs: target_strs,
574         int_type: int_type,
575         uint_type: uint_type,
576         float_type: float_type
577     };
578     return target_cfg;
579 }
580
581 #[cfg(stage0)]
582 pub fn host_triple() -> ~str {
583     // Get the host triple out of the build environment. This ensures that our
584     // idea of the host triple is the same as for the set of libraries we've
585     // actually built.  We can't just take LLVM's host triple because they
586     // normalize all ix86 architectures to i386.
587     //
588     // Instead of grabbing the host triple (for the current host), we grab (at
589     // compile time) the target triple that this rustc is built with and
590     // calling that (at runtime) the host triple.
591     let ht = env!("CFG_COMPILER_TRIPLE");
592     return if ht != "" {
593             ht.to_owned()
594         } else {
595             fail!("rustc built without CFG_COMPILER_TRIPLE")
596         };
597 }
598
599 #[cfg(not(stage0))]
600 pub fn host_triple() -> ~str {
601     // Get the host triple out of the build environment. This ensures that our
602     // idea of the host triple is the same as for the set of libraries we've
603     // actually built.  We can't just take LLVM's host triple because they
604     // normalize all ix86 architectures to i386.
605     //
606     // Instead of grabbing the host triple (for the current host), we grab (at
607     // compile time) the target triple that this rustc is built with and
608     // calling that (at runtime) the host triple.
609     (env!("CFG_COMPILER_TRIPLE")).to_owned()
610 }
611
612 pub fn build_session_options(binary: @str,
613                              matches: &getopts::Matches,
614                              demitter: diagnostic::Emitter)
615                           -> @session::options {
616     let crate_type = if opt_present(matches, "lib") {
617         session::lib_crate
618     } else if opt_present(matches, "bin") {
619         session::bin_crate
620     } else {
621         session::unknown_crate
622     };
623     let parse_only = opt_present(matches, "parse-only");
624     let no_trans = opt_present(matches, "no-trans");
625
626     let lint_levels = [lint::allow, lint::warn,
627                        lint::deny, lint::forbid];
628     let mut lint_opts = ~[];
629     let lint_dict = lint::get_lint_dict();
630     for level in lint_levels.iter() {
631         let level_name = lint::level_to_str(*level);
632
633         // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
634         // to_ascii_consume and to_str_consume to not do a unnecessary copy.
635         let level_short = level_name.slice_chars(0, 1);
636         let level_short = level_short.to_ascii().to_upper().to_str_ascii();
637         let flags = vec::append(getopts::opt_strs(matches, level_short),
638                                 getopts::opt_strs(matches, level_name));
639         for lint_name in flags.iter() {
640             let lint_name = lint_name.replace("-", "_");
641             match lint_dict.find_equiv(&lint_name) {
642               None => {
643                 early_error(demitter, fmt!("unknown %s flag: %s",
644                                            level_name, lint_name));
645               }
646               Some(lint) => {
647                 lint_opts.push((lint.lint, *level));
648               }
649             }
650         }
651     }
652
653     let mut debugging_opts = 0u;
654     let debug_flags = getopts::opt_strs(matches, "Z");
655     let debug_map = session::debugging_opts_map();
656     for debug_flag in debug_flags.iter() {
657         let mut this_bit = 0u;
658         for tuple in debug_map.iter() {
659             let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
660             if name == debug_flag { this_bit = bit; break; }
661         }
662         if this_bit == 0u {
663             early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
664         }
665         debugging_opts |= this_bit;
666     }
667     if debugging_opts & session::debug_llvm != 0 {
668         unsafe {
669             llvm::LLVMSetDebug(1);
670         }
671     }
672
673     let output_type =
674         if parse_only || no_trans {
675             link::output_type_none
676         } else if opt_present(matches, "S") &&
677                   opt_present(matches, "emit-llvm") {
678             link::output_type_llvm_assembly
679         } else if opt_present(matches, "S") {
680             link::output_type_assembly
681         } else if opt_present(matches, "c") {
682             link::output_type_object
683         } else if opt_present(matches, "emit-llvm") {
684             link::output_type_bitcode
685         } else { link::output_type_exe };
686     let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
687     let target = getopts::opt_maybe_str(matches, "target").unwrap_or_default(host_triple());
688     let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or_default(~"generic");
689     let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or_default(~"");
690     let save_temps = getopts::opt_present(matches, "save-temps");
691     let opt_level = {
692         if (debugging_opts & session::no_opt) != 0 {
693             No
694         } else if opt_present(matches, "O") {
695             if opt_present(matches, "opt-level") {
696                 early_error(demitter, ~"-O and --opt-level both provided");
697             }
698             Default
699         } else if opt_present(matches, "opt-level") {
700             match getopts::opt_str(matches, "opt-level") {
701               ~"0" => No,
702               ~"1" => Less,
703               ~"2" => Default,
704               ~"3" => Aggressive,
705               _ => {
706                 early_error(demitter, ~"optimization level needs to be between 0-3")
707               }
708             }
709         } else { No }
710     };
711     let gc = debugging_opts & session::gc != 0;
712     let jit = debugging_opts & session::jit != 0;
713     let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
714     let debuginfo = debugging_opts & session::debug_info != 0 ||
715         extra_debuginfo;
716     let statik = debugging_opts & session::statik != 0;
717
718     let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
719     let linker = getopts::opt_maybe_str(matches, "linker");
720     let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
721         a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
722     });
723
724     let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
725     let test = opt_present(matches, "test");
726     let android_cross_path = getopts::opt_maybe_str(
727         matches, "android-cross-path");
728
729     let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
730         None => ~[],
731         Some(s) => {
732             s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
733                 s.trim().to_owned()
734             }).collect()
735         }
736     };
737
738     let sopts = @session::options {
739         crate_type: crate_type,
740         is_static: statik,
741         gc: gc,
742         optimize: opt_level,
743         custom_passes: custom_passes,
744         debuginfo: debuginfo,
745         extra_debuginfo: extra_debuginfo,
746         lint_opts: lint_opts,
747         save_temps: save_temps,
748         jit: jit,
749         output_type: output_type,
750         addl_lib_search_paths: @mut addl_lib_search_paths,
751         linker: linker,
752         linker_args: linker_args,
753         maybe_sysroot: sysroot_opt,
754         target_triple: target,
755         target_cpu: target_cpu,
756         target_feature: target_feature,
757         cfg: cfg,
758         binary: binary,
759         test: test,
760         parse_only: parse_only,
761         no_trans: no_trans,
762         debugging_opts: debugging_opts,
763         android_cross_path: android_cross_path
764     };
765     return sopts;
766 }
767
768 pub fn build_session(sopts: @session::options,
769                      demitter: diagnostic::Emitter) -> Session {
770     let codemap = @codemap::CodeMap::new();
771     let diagnostic_handler =
772         diagnostic::mk_handler(Some(demitter));
773     let span_diagnostic_handler =
774         diagnostic::mk_span_handler(diagnostic_handler, codemap);
775     build_session_(sopts, codemap, demitter, span_diagnostic_handler)
776 }
777
778 pub fn build_session_(sopts: @session::options,
779                       cm: @codemap::CodeMap,
780                       demitter: diagnostic::Emitter,
781                       span_diagnostic_handler: @diagnostic::span_handler)
782                    -> Session {
783     let target_cfg = build_target_config(sopts, demitter);
784     let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
785                                                     cm);
786     let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
787     let filesearch = filesearch::mk_filesearch(
788         &sopts.maybe_sysroot,
789         sopts.target_triple,
790         sopts.addl_lib_search_paths);
791     @Session_ {
792         targ_cfg: target_cfg,
793         opts: sopts,
794         cstore: cstore,
795         parse_sess: p_s,
796         codemap: cm,
797         // For a library crate, this is always none
798         entry_fn: @mut None,
799         entry_type: @mut None,
800         span_diagnostic: span_diagnostic_handler,
801         filesearch: filesearch,
802         building_library: @mut false,
803         working_dir: os::getcwd(),
804         lints: @mut HashMap::new(),
805     }
806 }
807
808 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
809     match name {
810       &"normal" => ppm_normal,
811       &"expanded" => ppm_expanded,
812       &"typed" => ppm_typed,
813       &"expanded,identified" => ppm_expanded_identified,
814       &"identified" => ppm_identified,
815       _ => {
816         sess.fatal("argument to `pretty` must be one of `normal`, \
817                     `expanded`, `typed`, `identified`, \
818                     or `expanded,identified`");
819       }
820     }
821 }
822
823 // rustc command line options
824 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
825  ~[
826   optflag("",  "bin", "Compile an executable crate (default)"),
827   optflag("c", "",    "Compile and assemble, but do not link"),
828   optmulti("", "cfg", "Configure the compilation
829                           environment", "SPEC"),
830   optflag("",  "emit-llvm",
831                         "Produce an LLVM assembly file if used with -S option;
832                          produce an LLVM bitcode file otherwise"),
833   optflag("h", "help","Display this message"),
834   optmulti("L", "",   "Add a directory to the library search path",
835                               "PATH"),
836   optflag("",  "lib", "Compile a library crate"),
837   optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
838   optmulti("",  "link-args", "FLAGS is a space-separated list of flags
839                             passed to the linker", "FLAGS"),
840   optflag("",  "ls",  "List the symbols defined by a library crate"),
841   optflag("", "no-trans",
842                         "Run all passes except translation; no output"),
843   optflag("O", "",    "Equivalent to --opt-level=2"),
844   optopt("o", "",     "Write output to <filename>", "FILENAME"),
845   optopt("", "opt-level",
846                         "Optimize with possible levels 0-3", "LEVEL"),
847   optopt("", "passes", "Comma or space separated list of pass names to use. \
848                         Overrides the default passes for optimization levels,\n\
849                         a value of \"list\" will list the available passes.", "NAMES"),
850   optopt( "",  "out-dir",
851                         "Write output to compiler-chosen filename
852                           in <dir>", "DIR"),
853   optflag("", "parse-only",
854                         "Parse only; do not compile, assemble, or link"),
855   optflagopt("", "pretty",
856                         "Pretty-print the input instead of compiling;
857                           valid types are: normal (un-annotated source),
858                           expanded (crates expanded),
859                           typed (crates expanded, with type annotations),
860                           or identified (fully parenthesized,
861                           AST nodes and blocks with IDs)", "TYPE"),
862   optflag("S", "",    "Compile only; do not assemble or link"),
863   optflag("", "save-temps",
864                         "Write intermediate files (.bc, .opt.bc, .o)
865                           in addition to normal output"),
866   optopt("", "sysroot",
867                         "Override the system root", "PATH"),
868   optflag("", "test", "Build a test harness"),
869   optopt("", "target",
870                         "Target triple cpu-manufacturer-kernel[-os]
871                           to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
872                           for details)", "TRIPLE"),
873   optopt("", "target-cpu",
874                         "Select target processor (llc -mcpu=help
875                           for details)", "CPU"),
876   optopt("", "target-feature",
877                         "Target specific attributes (llc -mattr=help
878                           for details)", "FEATURE"),
879   optopt("", "android-cross-path",
880          "The path to the Android NDK", "PATH"),
881   optflagopt("W", "warn",
882                         "Set lint warnings", "OPT"),
883   optmulti("A", "allow",
884                         "Set lint allowed", "OPT"),
885   optmulti("D", "deny",
886                         "Set lint denied", "OPT"),
887   optmulti("F", "forbid",
888                         "Set lint forbidden", "OPT"),
889   optmulti("Z", "",   "Set internal debugging options", "FLAG"),
890   optflag( "v", "version",
891                         "Print version info and exit"),
892  ]
893 }
894
895 pub struct OutputFilenames {
896     out_filename: Path,
897     obj_filename: Path
898 }
899
900 pub fn build_output_filenames(input: &input,
901                               odir: &Option<Path>,
902                               ofile: &Option<Path>,
903                               attrs: &[ast::Attribute],
904                               sess: Session)
905                            -> ~OutputFilenames {
906     let obj_path;
907     let out_path;
908     let sopts = sess.opts;
909     let stop_after_codegen =
910         sopts.output_type != link::output_type_exe ||
911             sopts.is_static && *sess.building_library;
912
913     let obj_suffix =
914         match sopts.output_type {
915           link::output_type_none => ~"none",
916           link::output_type_bitcode => ~"bc",
917           link::output_type_assembly => ~"s",
918           link::output_type_llvm_assembly => ~"ll",
919           // Object and exe output both use the '.o' extension here
920           link::output_type_object | link::output_type_exe => ~"o"
921         };
922
923     match *ofile {
924       None => {
925           // "-" as input file will cause the parser to read from stdin so we
926           // have to make up a name
927           // We want to toss everything after the final '.'
928           let dirpath = match *odir {
929               Some(ref d) => (*d).clone(),
930               None => match *input {
931                   str_input(_) => os::getcwd(),
932                   file_input(ref ifile) => (*ifile).dir_path()
933               }
934           };
935
936           let mut stem = match *input {
937               file_input(ref ifile) => (*ifile).filestem().unwrap().to_managed(),
938               str_input(_) => @"rust_out"
939           };
940
941           // If a linkage name meta is present, we use it as the link name
942           let linkage_metas = attr::find_linkage_metas(attrs);
943           if !linkage_metas.is_empty() {
944               // But if a linkage meta is present, that overrides
945               let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
946               match maybe_name.chain(|m| m.value_str()) {
947                   Some(s) => stem = s,
948                   _ => ()
949               }
950               // If the name is missing, we just default to the filename
951               // version
952           }
953
954           if *sess.building_library {
955               out_path = dirpath.push(os::dll_filename(stem));
956               obj_path = dirpath.push(stem).with_filetype(obj_suffix);
957           } else {
958               out_path = dirpath.push(stem);
959               obj_path = dirpath.push(stem).with_filetype(obj_suffix);
960           }
961       }
962
963       Some(ref out_file) => {
964         out_path = (*out_file).clone();
965         obj_path = if stop_after_codegen {
966             (*out_file).clone()
967         } else {
968             (*out_file).with_filetype(obj_suffix)
969         };
970
971         if *sess.building_library {
972             sess.warn("ignoring specified output filename for library.");
973         }
974
975         if *odir != None {
976             sess.warn("ignoring --out-dir flag due to -o flag.");
977         }
978       }
979     }
980
981     ~OutputFilenames {
982         out_filename: out_path,
983         obj_filename: obj_path
984     }
985 }
986
987 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
988     emitter(None, msg, diagnostic::fatal);
989     fail!();
990 }
991
992 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
993     metadata::loader::list_file_metadata(
994         token::get_ident_interner(),
995         session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
996 }
997
998 #[cfg(test)]
999 mod test {
1000
1001     use driver::driver::{build_configuration, build_session};
1002     use driver::driver::{build_session_options, optgroups, str_input};
1003
1004     use extra::getopts::groups::getopts;
1005     use extra::getopts;
1006     use syntax::attr;
1007     use syntax::diagnostic;
1008
1009     // When the user supplies --test we should implicitly supply --cfg test
1010     #[test]
1011     fn test_switch_implies_cfg_test() {
1012         let matches =
1013             &match getopts([~"--test"], optgroups()) {
1014               Ok(m) => m,
1015               Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
1016             };
1017         let sessopts = build_session_options(
1018             @"rustc", matches, diagnostic::emit);
1019         let sess = build_session(sessopts, diagnostic::emit);
1020         let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1021         assert!((attr::contains_name(cfg, "test")));
1022     }
1023
1024     // When the user supplies --test and --cfg test, don't implicitly add
1025     // another --cfg test
1026     #[test]
1027     fn test_switch_implies_cfg_test_unless_cfg_test() {
1028         let matches =
1029             &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1030               Ok(m) => m,
1031               Err(f) => {
1032                 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1033               }
1034             };
1035         let sessopts = build_session_options(
1036             @"rustc", matches, diagnostic::emit);
1037         let sess = build_session(sessopts, diagnostic::emit);
1038         let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1039         let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1040         assert!(test_items.next().is_some());
1041         assert!(test_items.next().is_none());
1042     }
1043 }