]> git.lizzy.rs Git - rust.git/blob - src/librustc/driver/driver.rs
Honor hidden doc attribute of derivable trait methods
[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, CrateTypeExecutable, CrateType,
15                       FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
16 use driver::session::{Session, No, Less, Default};
17 use driver::session;
18 use front;
19 use lib::llvm::llvm;
20 use lib::llvm::{ContextRef, ModuleRef};
21 use metadata::common::LinkMeta;
22 use metadata::{creader, filesearch};
23 use metadata::cstore::CStore;
24 use metadata::creader::Loader;
25 use metadata;
26 use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
27 use middle;
28 use util::common::time;
29 use util::ppaux;
30 use util::nodemap::{NodeMap, NodeSet};
31
32 use serialize::{json, Encodable};
33
34 use std::cell::{Cell, RefCell};
35 use std::io;
36 use std::io::fs;
37 use std::io::MemReader;
38 use std::mem::drop;
39 use std::os;
40 use getopts::{optopt, optmulti, optflag, optflagopt};
41 use getopts;
42 use syntax::ast;
43 use syntax::abi;
44 use syntax::attr;
45 use syntax::attr::{AttrMetaMethods};
46 use syntax::codemap;
47 use syntax::crateid::CrateId;
48 use syntax::diagnostic;
49 use syntax::diagnostic::Emitter;
50 use syntax::ext::base::CrateLoader;
51 use syntax::parse;
52 use syntax::parse::token::InternedString;
53 use syntax::parse::token;
54 use syntax::print::{pp, pprust};
55 use syntax;
56
57 pub enum PpMode {
58     PpmNormal,
59     PpmExpanded,
60     PpmTyped,
61     PpmIdentified,
62     PpmExpandedIdentified
63 }
64
65 /**
66  * The name used for source code that doesn't originate in a file
67  * (e.g. source from stdin or a string)
68  */
69 pub fn anon_src() -> ~str {
70     "<anon>".to_str()
71 }
72
73 pub fn source_name(input: &Input) -> ~str {
74     match *input {
75         // FIXME (#9639): This needs to handle non-utf8 paths
76         FileInput(ref ifile) => ifile.as_str().unwrap().to_str(),
77         StrInput(_) => anon_src()
78     }
79 }
80
81 pub fn default_configuration(sess: &Session) ->
82    ast::CrateConfig {
83     let tos = match sess.targ_cfg.os {
84         abi::OsWin32 =>   InternedString::new("win32"),
85         abi::OsMacos =>   InternedString::new("macos"),
86         abi::OsLinux =>   InternedString::new("linux"),
87         abi::OsAndroid => InternedString::new("android"),
88         abi::OsFreebsd => InternedString::new("freebsd"),
89     };
90
91     // ARM is bi-endian, however using NDK seems to default
92     // to little-endian unless a flag is provided.
93     let (end,arch,wordsz) = match sess.targ_cfg.arch {
94         abi::X86 =>    ("little", "x86",    "32"),
95         abi::X86_64 => ("little", "x86_64", "64"),
96         abi::Arm =>    ("little", "arm",    "32"),
97         abi::Mips =>   ("big",    "mips",   "32")
98     };
99
100     let fam = match sess.targ_cfg.os {
101         abi::OsWin32 => InternedString::new("windows"),
102         _ => InternedString::new("unix")
103     };
104
105     let mk = attr::mk_name_value_item_str;
106     return vec!(// Target bindings.
107          attr::mk_word_item(fam.clone()),
108          mk(InternedString::new("target_os"), tos),
109          mk(InternedString::new("target_family"), fam),
110          mk(InternedString::new("target_arch"), InternedString::new(arch)),
111          mk(InternedString::new("target_endian"), InternedString::new(end)),
112          mk(InternedString::new("target_word_size"),
113             InternedString::new(wordsz))
114     );
115 }
116
117 pub fn append_configuration(cfg: &mut ast::CrateConfig,
118                             name: InternedString) {
119     if !cfg.iter().any(|mi| mi.name() == name) {
120         cfg.push(attr::mk_word_item(name))
121     }
122 }
123
124 pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
125     // Combine the configuration requested by the session (command line) with
126     // some default and generated configuration items
127     let default_cfg = default_configuration(sess);
128     let mut user_cfg = sess.opts.cfg.clone();
129     // If the user wants a test runner, then add the test cfg
130     if sess.opts.test {
131         append_configuration(&mut user_cfg, InternedString::new("test"))
132     }
133     // If the user requested GC, then add the GC cfg
134     append_configuration(&mut user_cfg, if sess.opts.gc {
135         InternedString::new("gc")
136     } else {
137         InternedString::new("nogc")
138     });
139     user_cfg.move_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
140 }
141
142 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
143 fn parse_cfgspecs(cfgspecs: Vec<~str> )
144                   -> ast::CrateConfig {
145     cfgspecs.move_iter().map(|s| {
146         parse::parse_meta_from_source_str("cfgspec".to_str(),
147                                           s,
148                                           Vec::new(),
149                                           &parse::new_parse_sess())
150     }).collect::<ast::CrateConfig>()
151 }
152
153 pub enum Input {
154     /// Load source from file
155     FileInput(Path),
156     /// The string is the source
157     StrInput(~str)
158 }
159
160 impl Input {
161     fn filestem(&self) -> ~str {
162         match *self {
163             FileInput(ref ifile) => ifile.filestem_str().unwrap().to_str(),
164             StrInput(_) => "rust_out".to_owned(),
165         }
166     }
167 }
168
169
170 pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
171     -> ast::Crate {
172     let krate = time(sess.time_passes(), "parsing", (), |_| {
173         match *input {
174             FileInput(ref file) => {
175                 parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
176             }
177             StrInput(ref src) => {
178                 parse::parse_crate_from_source_str(anon_src(),
179                                                    (*src).clone(),
180                                                    cfg.clone(),
181                                                    &sess.parse_sess)
182             }
183         }
184     });
185
186     if sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0 {
187         let mut stdout = io::BufferedWriter::new(io::stdout());
188         let mut json = json::PrettyEncoder::new(&mut stdout);
189         // unwrapping so IoError isn't ignored
190         krate.encode(&mut json).unwrap();
191     }
192
193     if sess.show_span() {
194         front::show_span::run(sess, &krate);
195     }
196
197     krate
198 }
199
200 // For continuing compilation after a parsed crate has been
201 // modified
202
203 /// Run the "early phases" of the compiler: initial `cfg` processing,
204 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
205 /// harness if one is to be provided and injection of a dependency on the
206 /// standard library and prelude.
207 pub fn phase_2_configure_and_expand(sess: &Session,
208                                     loader: &mut CrateLoader,
209                                     mut krate: ast::Crate,
210                                     crate_id: &CrateId)
211                                     -> (ast::Crate, syntax::ast_map::Map) {
212     let time_passes = sess.time_passes();
213
214     sess.building_library.set(session::building_library(&sess.opts, &krate));
215     *sess.crate_types.borrow_mut() = session::collect_crate_types(sess, krate.attrs.as_slice());
216
217     time(time_passes, "gated feature checking", (), |_|
218          front::feature_gate::check_crate(sess, &krate));
219
220     krate = time(time_passes, "crate injection", krate, |krate|
221                  front::std_inject::maybe_inject_crates_ref(sess, krate));
222
223     // strip before expansion to allow macros to depend on
224     // configuration variables e.g/ in
225     //
226     //   #[macro_escape] #[cfg(foo)]
227     //   mod bar { macro_rules! baz!(() => {{}}) }
228     //
229     // baz! should not use this definition unless foo is enabled.
230
231     krate = time(time_passes, "configuration 1", krate, |krate|
232                  front::config::strip_unconfigured_items(krate));
233
234     krate = time(time_passes, "expansion", krate, |krate| {
235         let cfg = syntax::ext::expand::ExpansionConfig {
236             loader: loader,
237             deriving_hash_type_parameter: sess.features.default_type_params.get(),
238             crate_id: crate_id.clone(),
239         };
240         syntax::ext::expand::expand_crate(&sess.parse_sess,
241                                           cfg,
242                                           krate)
243     });
244
245     // strip again, in case expansion added anything with a #[cfg].
246     krate = time(time_passes, "configuration 2", krate, |krate|
247                  front::config::strip_unconfigured_items(krate));
248
249     krate = time(time_passes, "maybe building test harness", krate, |krate|
250                  front::test::modify_for_testing(sess, krate));
251
252     krate = time(time_passes, "prelude injection", krate, |krate|
253                  front::std_inject::maybe_inject_prelude(sess, krate));
254
255     let (krate, map) = time(time_passes, "assinging node ids and indexing ast", krate, |krate|
256          front::assign_node_ids_and_map::assign_node_ids_and_map(sess, krate));
257
258     if sess.opts.debugging_opts & session::AST_JSON != 0 {
259         let mut stdout = io::BufferedWriter::new(io::stdout());
260         let mut json = json::PrettyEncoder::new(&mut stdout);
261         // unwrapping so IoError isn't ignored
262         krate.encode(&mut json).unwrap();
263     }
264
265     (krate, map)
266 }
267
268 pub struct CrateAnalysis {
269     pub exp_map2: middle::resolve::ExportMap2,
270     pub exported_items: middle::privacy::ExportedItems,
271     pub public_items: middle::privacy::PublicItems,
272     pub ty_cx: ty::ctxt,
273     pub maps: astencode::Maps,
274     pub reachable: NodeSet,
275 }
276
277 /// Run the resolution, typechecking, region checking and other
278 /// miscellaneous analysis passes on the crate. Return various
279 /// structures carrying the results of the analysis.
280 pub fn phase_3_run_analysis_passes(sess: Session,
281                                    krate: &ast::Crate,
282                                    ast_map: syntax::ast_map::Map) -> CrateAnalysis {
283
284     let time_passes = sess.time_passes();
285
286     time(time_passes, "external crate/lib resolution", (), |_|
287          creader::read_crates(&sess, krate,
288                               session::sess_os_to_meta_os(sess.targ_cfg.os),
289                               token::get_ident_interner()));
290
291     let lang_items = time(time_passes, "language item collection", (), |_|
292                           middle::lang_items::collect_language_items(krate, &sess));
293
294     let middle::resolve::CrateMap {
295         def_map: def_map,
296         exp_map2: exp_map2,
297         trait_map: trait_map,
298         external_exports: external_exports,
299         last_private_map: last_private_map
300     } =
301         time(time_passes, "resolution", (), |_|
302              middle::resolve::resolve_crate(&sess, &lang_items, krate));
303
304     // Discard MTWT tables that aren't required past resolution.
305     syntax::ext::mtwt::clear_tables();
306
307     let named_region_map = time(time_passes, "lifetime resolution", (),
308                                 |_| middle::resolve_lifetime::krate(&sess, krate));
309
310     time(time_passes, "looking for entry point", (),
311          |_| middle::entry::find_entry_point(&sess, krate, &ast_map));
312
313     sess.macro_registrar_fn.set(
314         time(time_passes, "looking for macro registrar", (), |_|
315             syntax::ext::registrar::find_macro_registrar(
316                 sess.diagnostic(), krate)));
317
318     let freevars = time(time_passes, "freevar finding", (), |_|
319                         freevars::annotate_freevars(&def_map, krate));
320
321     let region_map = time(time_passes, "region resolution", (), |_|
322                           middle::region::resolve_crate(&sess, krate));
323
324     time(time_passes, "loop checking", (), |_|
325          middle::check_loop::check_crate(&sess, krate));
326
327     let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
328                             freevars, region_map, lang_items);
329
330     // passes are timed inside typeck
331     typeck::check_crate(&ty_cx, trait_map, krate);
332
333     time(time_passes, "check static items", (), |_|
334          middle::check_static::check_crate(&ty_cx, krate));
335
336     // These next two const passes can probably be merged
337     time(time_passes, "const marking", (), |_|
338          middle::const_eval::process_crate(krate, &ty_cx));
339
340     time(time_passes, "const checking", (), |_|
341          middle::check_const::check_crate(krate, &ty_cx));
342
343     let maps = (external_exports, last_private_map);
344     let (exported_items, public_items) =
345             time(time_passes, "privacy checking", maps, |(a, b)|
346                  middle::privacy::check_crate(&ty_cx, &exp_map2, a, b, krate));
347
348     time(time_passes, "effect checking", (), |_|
349          middle::effect::check_crate(&ty_cx, krate));
350
351     let middle::moves::MoveMaps {moves_map, moved_variables_set,
352                                  capture_map} =
353         time(time_passes, "compute moves", (), |_|
354              middle::moves::compute_moves(&ty_cx, krate));
355
356     time(time_passes, "match checking", (), |_|
357          middle::check_match::check_crate(&ty_cx, &moves_map, krate));
358
359     time(time_passes, "liveness checking", (), |_|
360          middle::liveness::check_crate(&ty_cx, &capture_map, krate));
361
362     let root_map =
363         time(time_passes, "borrow checking", (), |_|
364              middle::borrowck::check_crate(&ty_cx, &moves_map,
365                                            &moved_variables_set,
366                                            &capture_map, krate));
367
368     drop(moves_map);
369     drop(moved_variables_set);
370
371     time(time_passes, "kind checking", (), |_|
372          kind::check_crate(&ty_cx, krate));
373
374     let reachable_map =
375         time(time_passes, "reachability checking", (), |_|
376              reachable::find_reachable(&ty_cx, &exported_items));
377
378     time(time_passes, "death checking", (), |_| {
379         middle::dead::check_crate(&ty_cx,
380                                   &exported_items,
381                                   &reachable_map,
382                                   krate)
383     });
384
385     time(time_passes, "lint checking", (), |_|
386          lint::check_crate(&ty_cx, &exported_items, krate));
387
388     CrateAnalysis {
389         exp_map2: exp_map2,
390         ty_cx: ty_cx,
391         exported_items: exported_items,
392         public_items: public_items,
393         maps: astencode::Maps {
394             root_map: root_map,
395             capture_map: RefCell::new(capture_map)
396         },
397         reachable: reachable_map
398     }
399 }
400
401 pub struct CrateTranslation {
402     pub context: ContextRef,
403     pub module: ModuleRef,
404     pub metadata_module: ModuleRef,
405     pub link: LinkMeta,
406     pub metadata: Vec<u8>,
407     pub reachable: Vec<~str>,
408 }
409
410 /// Run the translation phase to LLVM, after which the AST and analysis can
411 /// be discarded.
412 pub fn phase_4_translate_to_llvm(krate: ast::Crate,
413                                  analysis: CrateAnalysis,
414                                  outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
415     // Option dance to work around the lack of stack once closures.
416     let time_passes = analysis.ty_cx.sess.time_passes();
417     let mut analysis = Some(analysis);
418     time(time_passes, "translation", krate, |krate|
419          trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
420 }
421
422 /// Run LLVM itself, producing a bitcode file, assembly file or object file
423 /// as a side effect.
424 pub fn phase_5_run_llvm_passes(sess: &Session,
425                                trans: &CrateTranslation,
426                                outputs: &OutputFilenames) {
427     if sess.opts.cg.no_integrated_as {
428         let output_type = link::OutputTypeAssembly;
429
430         time(sess.time_passes(), "LLVM passes", (), |_|
431             link::write::run_passes(sess, trans, [output_type], outputs));
432
433         link::write::run_assembler(sess, outputs);
434
435         // Remove assembly source, unless --save-temps was specified
436         if !sess.opts.cg.save_temps {
437             fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
438         }
439     } else {
440         time(sess.time_passes(), "LLVM passes", (), |_|
441             link::write::run_passes(sess,
442                                     trans,
443                                     sess.opts.output_types.as_slice(),
444                                     outputs));
445     }
446 }
447
448 /// Run the linker on any artifacts that resulted from the LLVM run.
449 /// This should produce either a finished executable or library.
450 pub fn phase_6_link_output(sess: &Session,
451                            trans: &CrateTranslation,
452                            outputs: &OutputFilenames) {
453     time(sess.time_passes(), "linking", (), |_|
454          link::link_binary(sess,
455                            trans,
456                            outputs,
457                            &trans.link.crateid));
458 }
459
460 pub fn stop_after_phase_3(sess: &Session) -> bool {
461    if sess.opts.no_trans {
462         debug!("invoked with --no-trans, returning early from compile_input");
463         return true;
464     }
465     return false;
466 }
467
468 pub fn stop_after_phase_1(sess: &Session) -> bool {
469     if sess.opts.parse_only {
470         debug!("invoked with --parse-only, returning early from compile_input");
471         return true;
472     }
473     if sess.show_span() {
474         return true;
475     }
476     return sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0;
477 }
478
479 pub fn stop_after_phase_2(sess: &Session) -> bool {
480     if sess.opts.no_analysis {
481         debug!("invoked with --no-analysis, returning early from compile_input");
482         return true;
483     }
484     return sess.opts.debugging_opts & session::AST_JSON != 0;
485 }
486
487 pub fn stop_after_phase_5(sess: &Session) -> bool {
488     if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) {
489         debug!("not building executable, returning early from compile_input");
490         return true;
491     }
492     return false;
493 }
494
495 fn write_out_deps(sess: &Session,
496                   input: &Input,
497                   outputs: &OutputFilenames,
498                   krate: &ast::Crate) -> io::IoResult<()> {
499     let id = link::find_crate_id(krate.attrs.as_slice(), outputs.out_filestem);
500
501     let mut out_filenames = Vec::new();
502     for output_type in sess.opts.output_types.iter() {
503         let file = outputs.path(*output_type);
504         match *output_type {
505             link::OutputTypeExe => {
506                 for output in sess.crate_types.borrow().iter() {
507                     let p = link::filename_for_input(sess, *output, &id, &file);
508                     out_filenames.push(p);
509                 }
510             }
511             _ => { out_filenames.push(file); }
512         }
513     }
514
515     // Write out dependency rules to the dep-info file if requested with
516     // --dep-info
517     let deps_filename = match sess.opts.write_dependency_info {
518         // Use filename from --dep-file argument if given
519         (true, Some(ref filename)) => filename.clone(),
520         // Use default filename: crate source filename with extension replaced
521         // by ".d"
522         (true, None) => match *input {
523             FileInput(..) => outputs.with_extension("d"),
524             StrInput(..) => {
525                 sess.warn("can not write --dep-info without a filename \
526                            when compiling stdin.");
527                 return Ok(());
528             },
529         },
530         _ => return Ok(()),
531     };
532
533     // Build a list of files used to compile the output and
534     // write Makefile-compatible dependency rules
535     let files: Vec<~str> = sess.codemap().files.borrow()
536                                .iter().filter_map(|fmap| {
537                                     if fmap.is_real_file() {
538                                         Some(fmap.name.clone())
539                                     } else {
540                                         None
541                                     }
542                                 }).collect();
543     let mut file = try!(io::File::create(&deps_filename));
544     for path in out_filenames.iter() {
545         try!(write!(&mut file as &mut Writer,
546                       "{}: {}\n\n", path.display(), files.connect(" ")));
547     }
548     Ok(())
549 }
550
551 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
552                      outdir: &Option<Path>, output: &Option<Path>) {
553     // We need nested scopes here, because the intermediate results can keep
554     // large chunks of memory alive and we want to free them as soon as
555     // possible to keep the peak memory usage low
556     let (outputs, trans, sess) = {
557         let (outputs, expanded_crate, ast_map) = {
558             let krate = phase_1_parse_input(&sess, cfg, input);
559             if stop_after_phase_1(&sess) { return; }
560             let outputs = build_output_filenames(input,
561                                                  outdir,
562                                                  output,
563                                                  krate.attrs.as_slice(),
564                                                  &sess);
565             let loader = &mut Loader::new(&sess);
566             let id = link::find_crate_id(krate.attrs.as_slice(),
567                                          outputs.out_filestem);
568             let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
569                                                                          krate, &id);
570             (outputs, expanded_crate, ast_map)
571         };
572         write_out_deps(&sess, input, &outputs, &expanded_crate).unwrap();
573
574         if stop_after_phase_2(&sess) { return; }
575
576         let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
577         if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
578         let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
579                                                      analysis, &outputs);
580
581         // Discard interned strings as they are no longer required.
582         token::get_ident_interner().clear();
583
584         (outputs, trans, tcx.sess)
585     };
586     phase_5_run_llvm_passes(&sess, &trans, &outputs);
587     if stop_after_phase_5(&sess) { return; }
588     phase_6_link_output(&sess, &trans, &outputs);
589 }
590
591 struct IdentifiedAnnotation;
592
593 impl pprust::PpAnn for IdentifiedAnnotation {
594     fn pre(&self,
595            s: &mut pprust::State,
596            node: pprust::AnnNode) -> io::IoResult<()> {
597         match node {
598             pprust::NodeExpr(_) => s.popen(),
599             _ => Ok(())
600         }
601     }
602     fn post(&self,
603             s: &mut pprust::State,
604             node: pprust::AnnNode) -> io::IoResult<()> {
605         match node {
606             pprust::NodeItem(item) => {
607                 try!(pp::space(&mut s.s));
608                 s.synth_comment(item.id.to_str())
609             }
610             pprust::NodeBlock(blk) => {
611                 try!(pp::space(&mut s.s));
612                 s.synth_comment("block ".to_owned() + blk.id.to_str())
613             }
614             pprust::NodeExpr(expr) => {
615                 try!(pp::space(&mut s.s));
616                 try!(s.synth_comment(expr.id.to_str()));
617                 s.pclose()
618             }
619             pprust::NodePat(pat) => {
620                 try!(pp::space(&mut s.s));
621                 s.synth_comment("pat ".to_owned() + pat.id.to_str())
622             }
623         }
624     }
625 }
626
627 struct TypedAnnotation {
628     analysis: CrateAnalysis,
629 }
630
631 impl pprust::PpAnn for TypedAnnotation {
632     fn pre(&self,
633            s: &mut pprust::State,
634            node: pprust::AnnNode) -> io::IoResult<()> {
635         match node {
636             pprust::NodeExpr(_) => s.popen(),
637             _ => Ok(())
638         }
639     }
640     fn post(&self,
641             s: &mut pprust::State,
642             node: pprust::AnnNode) -> io::IoResult<()> {
643         let tcx = &self.analysis.ty_cx;
644         match node {
645             pprust::NodeExpr(expr) => {
646                 try!(pp::space(&mut s.s));
647                 try!(pp::word(&mut s.s, "as"));
648                 try!(pp::space(&mut s.s));
649                 try!(pp::word(&mut s.s,
650                                 ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))));
651                 s.pclose()
652             }
653             _ => Ok(())
654         }
655     }
656 }
657
658 pub fn pretty_print_input(sess: Session,
659                           cfg: ast::CrateConfig,
660                           input: &Input,
661                           ppm: PpMode,
662                           ofile: Option<Path>) {
663     let krate = phase_1_parse_input(&sess, cfg, input);
664     let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem());
665
666     let (krate, ast_map, is_expanded) = match ppm {
667         PpmExpanded | PpmExpandedIdentified | PpmTyped => {
668             let loader = &mut Loader::new(&sess);
669             let (krate, ast_map) = phase_2_configure_and_expand(&sess, loader,
670                                                                 krate, &id);
671             (krate, Some(ast_map), true)
672         }
673         _ => (krate, None, false)
674     };
675
676     let src_name = source_name(input);
677     let src = Vec::from_slice(sess.codemap().get_filemap(src_name).src.as_bytes());
678     let mut rdr = MemReader::new(src);
679
680     let out = match ofile {
681         None => ~io::stdout() as ~Writer,
682         Some(p) => {
683             let r = io::File::create(&p);
684             match r {
685                 Ok(w) => ~w as ~Writer,
686                 Err(e) => fail!("print-print failed to open {} due to {}",
687                                 p.display(), e),
688             }
689         }
690     };
691     match ppm {
692         PpmIdentified | PpmExpandedIdentified => {
693             pprust::print_crate(sess.codemap(),
694                                 sess.diagnostic(),
695                                 &krate,
696                                 src_name,
697                                 &mut rdr,
698                                 out,
699                                 &IdentifiedAnnotation,
700                                 is_expanded)
701         }
702         PpmTyped => {
703             let ast_map = ast_map.expect("--pretty=typed missing ast_map");
704             let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
705             let annotation = TypedAnnotation {
706                 analysis: analysis
707             };
708             pprust::print_crate(annotation.analysis.ty_cx.sess.codemap(),
709                                 annotation.analysis.ty_cx.sess.diagnostic(),
710                                 &krate,
711                                 src_name,
712                                 &mut rdr,
713                                 out,
714                                 &annotation,
715                                 is_expanded)
716         }
717         _ => {
718             pprust::print_crate(sess.codemap(),
719                                 sess.diagnostic(),
720                                 &krate,
721                                 src_name,
722                                 &mut rdr,
723                                 out,
724                                 &pprust::NoAnn,
725                                 is_expanded)
726         }
727     }.unwrap()
728
729 }
730
731 pub fn get_os(triple: &str) -> Option<abi::Os> {
732     for &(name, os) in os_names.iter() {
733         if triple.contains(name) { return Some(os) }
734     }
735     None
736 }
737 static os_names : &'static [(&'static str, abi::Os)] = &'static [
738     ("mingw32", abi::OsWin32),
739     ("win32",   abi::OsWin32),
740     ("darwin",  abi::OsMacos),
741     ("android", abi::OsAndroid),
742     ("linux",   abi::OsLinux),
743     ("freebsd", abi::OsFreebsd)];
744
745 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
746     for &(arch, abi) in architecture_abis.iter() {
747         if triple.contains(arch) { return Some(abi) }
748     }
749     None
750 }
751 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
752     ("i386",   abi::X86),
753     ("i486",   abi::X86),
754     ("i586",   abi::X86),
755     ("i686",   abi::X86),
756     ("i786",   abi::X86),
757
758     ("x86_64", abi::X86_64),
759
760     ("arm",    abi::Arm),
761     ("xscale", abi::Arm),
762     ("thumb",  abi::Arm),
763
764     ("mips",   abi::Mips)];
765
766 pub fn build_target_config(sopts: &session::Options) -> session::Config {
767     let os = match get_os(sopts.target_triple) {
768       Some(os) => os,
769       None => early_error("unknown operating system")
770     };
771     let arch = match get_arch(sopts.target_triple) {
772       Some(arch) => arch,
773       None => early_error("unknown architecture: " + sopts.target_triple)
774     };
775     let (int_type, uint_type) = match arch {
776       abi::X86 => (ast::TyI32, ast::TyU32),
777       abi::X86_64 => (ast::TyI64, ast::TyU64),
778       abi::Arm => (ast::TyI32, ast::TyU32),
779       abi::Mips => (ast::TyI32, ast::TyU32)
780     };
781     let target_triple = sopts.target_triple.clone();
782     let target_strs = match arch {
783       abi::X86 => x86::get_target_strs(target_triple, os),
784       abi::X86_64 => x86_64::get_target_strs(target_triple, os),
785       abi::Arm => arm::get_target_strs(target_triple, os),
786       abi::Mips => mips::get_target_strs(target_triple, os)
787     };
788     session::Config {
789         os: os,
790         arch: arch,
791         target_strs: target_strs,
792         int_type: int_type,
793         uint_type: uint_type,
794     }
795 }
796
797 pub fn host_triple() -> ~str {
798     // Get the host triple out of the build environment. This ensures that our
799     // idea of the host triple is the same as for the set of libraries we've
800     // actually built.  We can't just take LLVM's host triple because they
801     // normalize all ix86 architectures to i386.
802     //
803     // Instead of grabbing the host triple (for the current host), we grab (at
804     // compile time) the target triple that this rustc is built with and
805     // calling that (at runtime) the host triple.
806     (env!("CFG_COMPILER_HOST_TRIPLE")).to_owned()
807 }
808
809 pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
810     let mut crate_types: Vec<CrateType> = Vec::new();
811     let unparsed_crate_types = matches.opt_strs("crate-type");
812     for unparsed_crate_type in unparsed_crate_types.iter() {
813         for part in unparsed_crate_type.split(',') {
814             let new_part = match part {
815                 "lib"       => session::default_lib_output(),
816                 "rlib"      => session::CrateTypeRlib,
817                 "staticlib" => session::CrateTypeStaticlib,
818                 "dylib"     => session::CrateTypeDylib,
819                 "bin"       => session::CrateTypeExecutable,
820                 _ => early_error(format!("unknown crate type: `{}`", part))
821             };
822             crate_types.push(new_part)
823         }
824     }
825
826     let parse_only = matches.opt_present("parse-only");
827     let no_trans = matches.opt_present("no-trans");
828     let no_analysis = matches.opt_present("no-analysis");
829
830     let lint_levels = [lint::allow, lint::warn,
831                        lint::deny, lint::forbid];
832     let mut lint_opts = Vec::new();
833     let lint_dict = lint::get_lint_dict();
834     for level in lint_levels.iter() {
835         let level_name = lint::level_to_str(*level);
836
837         let level_short = level_name.slice_chars(0, 1);
838         let level_short = level_short.to_ascii().to_upper().into_str();
839         let flags = matches.opt_strs(level_short).move_iter().collect::<Vec<_>>().append(
840                                    matches.opt_strs(level_name).as_slice());
841         for lint_name in flags.iter() {
842             let lint_name = lint_name.replace("-", "_");
843             match lint_dict.find_equiv(&lint_name) {
844               None => {
845                 early_error(format!("unknown {} flag: {}",
846                                     level_name, lint_name));
847               }
848               Some(lint) => {
849                 lint_opts.push((lint.lint, *level));
850               }
851             }
852         }
853     }
854
855     let mut debugging_opts = 0;
856     let debug_flags = matches.opt_strs("Z");
857     let debug_map = session::debugging_opts_map();
858     for debug_flag in debug_flags.iter() {
859         let mut this_bit = 0;
860         for tuple in debug_map.iter() {
861             let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
862             if *name == *debug_flag { this_bit = bit; break; }
863         }
864         if this_bit == 0 {
865             early_error(format!("unknown debug flag: {}", *debug_flag))
866         }
867         debugging_opts |= this_bit;
868     }
869
870     if debugging_opts & session::DEBUG_LLVM != 0 {
871         unsafe { llvm::LLVMSetDebug(1); }
872     }
873
874     let mut output_types = Vec::new();
875     if !parse_only && !no_trans {
876         let unparsed_output_types = matches.opt_strs("emit");
877         for unparsed_output_type in unparsed_output_types.iter() {
878             for part in unparsed_output_type.split(',') {
879                 let output_type = match part.as_slice() {
880                     "asm"  => link::OutputTypeAssembly,
881                     "ir"   => link::OutputTypeLlvmAssembly,
882                     "bc"   => link::OutputTypeBitcode,
883                     "obj"  => link::OutputTypeObject,
884                     "link" => link::OutputTypeExe,
885                     _ => early_error(format!("unknown emission type: `{}`", part))
886                 };
887                 output_types.push(output_type)
888             }
889         }
890     };
891     output_types.as_mut_slice().sort();
892     output_types.dedup();
893     if output_types.len() == 0 {
894         output_types.push(link::OutputTypeExe);
895     }
896
897     let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
898     let target = matches.opt_str("target").unwrap_or(host_triple());
899     let opt_level = {
900         if (debugging_opts & session::NO_OPT) != 0 {
901             No
902         } else if matches.opt_present("O") {
903             if matches.opt_present("opt-level") {
904                 early_error("-O and --opt-level both provided");
905             }
906             Default
907         } else if matches.opt_present("opt-level") {
908             match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
909                 None      |
910                 Some("0") => No,
911                 Some("1") => Less,
912                 Some("2") => Default,
913                 Some("3") => Aggressive,
914                 Some(arg) => {
915                     early_error(format!("optimization level needs to be between 0-3 \
916                                         (instead was `{}`)", arg));
917                 }
918             }
919         } else {
920             No
921         }
922     };
923     let gc = debugging_opts & session::GC != 0;
924     let debuginfo = if matches.opt_present("g") {
925         if matches.opt_present("debuginfo") {
926             early_error("-g and --debuginfo both provided");
927         }
928         FullDebugInfo
929     } else if matches.opt_present("debuginfo") {
930         match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
931             Some("0") => NoDebugInfo,
932             Some("1") => LimitedDebugInfo,
933             None      |
934             Some("2") => FullDebugInfo,
935             Some(arg) => {
936                 early_error(format!("optimization level needs to be between 0-3 \
937                                     (instead was `{}`)", arg));
938             }
939         }
940     } else {
941         NoDebugInfo
942     };
943
944     let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
945         Path::new(s.as_slice())
946     }).collect();
947
948     let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
949     let test = matches.opt_present("test");
950     let write_dependency_info = (matches.opt_present("dep-info"),
951                                  matches.opt_str("dep-info").map(|p| Path::new(p)));
952
953     let print_metas = (matches.opt_present("crate-id"),
954                        matches.opt_present("crate-name"),
955                        matches.opt_present("crate-file-name"));
956     let cg = build_codegen_options(matches);
957
958     session::Options {
959         crate_types: crate_types,
960         gc: gc,
961         optimize: opt_level,
962         debuginfo: debuginfo,
963         lint_opts: lint_opts,
964         output_types: output_types,
965         addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
966         maybe_sysroot: sysroot_opt,
967         target_triple: target,
968         cfg: cfg,
969         test: test,
970         parse_only: parse_only,
971         no_trans: no_trans,
972         no_analysis: no_analysis,
973         debugging_opts: debugging_opts,
974         write_dependency_info: write_dependency_info,
975         print_metas: print_metas,
976         cg: cg,
977     }
978 }
979
980 pub fn build_codegen_options(matches: &getopts::Matches)
981         -> session::CodegenOptions
982 {
983     let mut cg = session::basic_codegen_options();
984     for option in matches.opt_strs("C").move_iter() {
985         let mut iter = option.splitn('=', 1);
986         let key = iter.next().unwrap();
987         let value = iter.next();
988         let option_to_lookup = key.replace("-", "_");
989         let mut found = false;
990         for &(candidate, setter, _) in session::CG_OPTIONS.iter() {
991             if option_to_lookup.as_slice() != candidate { continue }
992             if !setter(&mut cg, value) {
993                 match value {
994                     Some(..) => early_error(format!("codegen option `{}` takes \
995                                                      no value", key)),
996                     None => early_error(format!("codegen option `{0}` requires \
997                                                  a value (-C {0}=<value>)",
998                                                 key))
999                 }
1000             }
1001             found = true;
1002             break;
1003         }
1004         if !found {
1005             early_error(format!("unknown codegen option: `{}`", key));
1006         }
1007     }
1008     return cg;
1009 }
1010
1011 pub fn build_session(sopts: session::Options,
1012                      local_crate_source_file: Option<Path>)
1013                      -> Session {
1014     let codemap = codemap::CodeMap::new();
1015     let diagnostic_handler =
1016         diagnostic::default_handler();
1017     let span_diagnostic_handler =
1018         diagnostic::mk_span_handler(diagnostic_handler, codemap);
1019
1020     build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
1021 }
1022
1023 pub fn build_session_(sopts: session::Options,
1024                       local_crate_source_file: Option<Path>,
1025                       span_diagnostic: diagnostic::SpanHandler)
1026                       -> Session {
1027     let target_cfg = build_target_config(&sopts);
1028     let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
1029     let default_sysroot = match sopts.maybe_sysroot {
1030         Some(_) => None,
1031         None => Some(filesearch::get_or_default_sysroot())
1032     };
1033
1034     // Make the path absolute, if necessary
1035     let local_crate_source_file = local_crate_source_file.map(|path|
1036         if path.is_absolute() {
1037             path.clone()
1038         } else {
1039             os::getcwd().join(path.clone())
1040         }
1041     );
1042
1043     Session {
1044         targ_cfg: target_cfg,
1045         opts: sopts,
1046         cstore: CStore::new(token::get_ident_interner()),
1047         parse_sess: p_s,
1048         // For a library crate, this is always none
1049         entry_fn: RefCell::new(None),
1050         entry_type: Cell::new(None),
1051         macro_registrar_fn: Cell::new(None),
1052         default_sysroot: default_sysroot,
1053         building_library: Cell::new(false),
1054         local_crate_source_file: local_crate_source_file,
1055         working_dir: os::getcwd(),
1056         lints: RefCell::new(NodeMap::new()),
1057         node_id: Cell::new(1),
1058         crate_types: RefCell::new(Vec::new()),
1059         features: front::feature_gate::Features::new(),
1060         recursion_limit: Cell::new(64),
1061     }
1062 }
1063
1064 pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
1065     match name {
1066       &"normal" => PpmNormal,
1067       &"expanded" => PpmExpanded,
1068       &"typed" => PpmTyped,
1069       &"expanded,identified" => PpmExpandedIdentified,
1070       &"identified" => PpmIdentified,
1071       _ => {
1072         sess.fatal("argument to `pretty` must be one of `normal`, \
1073                     `expanded`, `typed`, `identified`, \
1074                     or `expanded,identified`");
1075       }
1076     }
1077 }
1078
1079 // rustc command line options
1080 pub fn optgroups() -> Vec<getopts::OptGroup> {
1081  vec!(
1082   optflag("h", "help", "Display this message"),
1083   optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
1084   optmulti("L", "",   "Add a directory to the library search path", "PATH"),
1085   optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit",
1086            "[bin|lib|rlib|dylib|staticlib]"),
1087   optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
1088            "[asm|bc|ir|obj|link]"),
1089   optflag("", "crate-id", "Output the crate id and exit"),
1090   optflag("", "crate-name", "Output the crate name and exit"),
1091   optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
1092           continued and exit"),
1093   optflag("g",  "",  "Equivalent to --debuginfo=2"),
1094   optopt("",  "debuginfo",  "Emit DWARF debug info to the objects created:
1095          0 = no debug info,
1096          1 = line-tables only (for stacktraces and breakpoints),
1097          2 = full debug info with variable and type information (same as -g)", "LEVEL"),
1098   optflag("", "no-trans", "Run all passes except translation; no output"),
1099   optflag("", "no-analysis",
1100           "Parse and expand the source, but run no analysis and produce no output"),
1101   optflag("O", "", "Equivalent to --opt-level=2"),
1102   optopt("o", "", "Write output to <filename>", "FILENAME"),
1103   optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
1104   optopt( "",  "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
1105   optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
1106   optflagopt("", "pretty",
1107              "Pretty-print the input instead of compiling;
1108               valid types are: normal (un-annotated source),
1109               expanded (crates expanded),
1110               typed (crates expanded, with type annotations),
1111               or identified (fully parenthesized,
1112               AST nodes and blocks with IDs)", "TYPE"),
1113   optflagopt("", "dep-info",
1114              "Output dependency info to <filename> after compiling, \
1115               in a format suitable for use by Makefiles", "FILENAME"),
1116   optopt("", "sysroot", "Override the system root", "PATH"),
1117   optflag("", "test", "Build a test harness"),
1118   optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
1119                         to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
1120                         for details)", "TRIPLE"),
1121   optmulti("W", "warn", "Set lint warnings", "OPT"),
1122   optmulti("A", "allow", "Set lint allowed", "OPT"),
1123   optmulti("D", "deny", "Set lint denied", "OPT"),
1124   optmulti("F", "forbid", "Set lint forbidden", "OPT"),
1125   optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1126   optmulti("Z", "", "Set internal debugging options", "FLAG"),
1127   optflag( "v", "version", "Print version info and exit"))
1128 }
1129
1130 pub struct OutputFilenames {
1131     pub out_directory: Path,
1132     pub out_filestem: ~str,
1133     pub single_output_file: Option<Path>,
1134 }
1135
1136 impl OutputFilenames {
1137     pub fn path(&self, flavor: link::OutputType) -> Path {
1138         match self.single_output_file {
1139             Some(ref path) => return path.clone(),
1140             None => {}
1141         }
1142         self.temp_path(flavor)
1143     }
1144
1145     pub fn temp_path(&self, flavor: link::OutputType) -> Path {
1146         let base = self.out_directory.join(self.out_filestem.as_slice());
1147         match flavor {
1148             link::OutputTypeBitcode => base.with_extension("bc"),
1149             link::OutputTypeAssembly => base.with_extension("s"),
1150             link::OutputTypeLlvmAssembly => base.with_extension("ll"),
1151             link::OutputTypeObject => base.with_extension("o"),
1152             link::OutputTypeExe => base,
1153         }
1154     }
1155
1156     pub fn with_extension(&self, extension: &str) -> Path {
1157         let stem = self.out_filestem.as_slice();
1158         self.out_directory.join(stem).with_extension(extension)
1159     }
1160 }
1161
1162 pub fn build_output_filenames(input: &Input,
1163                               odir: &Option<Path>,
1164                               ofile: &Option<Path>,
1165                               attrs: &[ast::Attribute],
1166                               sess: &Session)
1167                            -> OutputFilenames {
1168     match *ofile {
1169         None => {
1170             // "-" as input file will cause the parser to read from stdin so we
1171             // have to make up a name
1172             // We want to toss everything after the final '.'
1173             let dirpath = match *odir {
1174                 Some(ref d) => d.clone(),
1175                 None => Path::new(".")
1176             };
1177
1178             let mut stem = input.filestem();
1179
1180             // If a crateid is present, we use it as the link name
1181             let crateid = attr::find_crateid(attrs);
1182             match crateid {
1183                 None => {}
1184                 Some(crateid) => stem = crateid.name.to_str(),
1185             }
1186             OutputFilenames {
1187                 out_directory: dirpath,
1188                 out_filestem: stem,
1189                 single_output_file: None,
1190             }
1191         }
1192
1193         Some(ref out_file) => {
1194             let ofile = if sess.opts.output_types.len() > 1 {
1195                 sess.warn("ignoring specified output filename because multiple \
1196                            outputs were requested");
1197                 None
1198             } else {
1199                 Some(out_file.clone())
1200             };
1201             if *odir != None {
1202                 sess.warn("ignoring --out-dir flag due to -o flag.");
1203             }
1204             OutputFilenames {
1205                 out_directory: out_file.dir_path(),
1206                 out_filestem: out_file.filestem_str().unwrap().to_str(),
1207                 single_output_file: ofile,
1208             }
1209         }
1210     }
1211 }
1212
1213 pub fn early_error(msg: &str) -> ! {
1214     let mut emitter = diagnostic::EmitterWriter::stderr();
1215     emitter.emit(None, msg, diagnostic::Fatal);
1216     fail!(diagnostic::FatalError);
1217 }
1218
1219 pub fn list_metadata(sess: &Session, path: &Path,
1220                      out: &mut io::Writer) -> io::IoResult<()> {
1221     metadata::loader::list_file_metadata(
1222         session::sess_os_to_meta_os(sess.targ_cfg.os), path, out)
1223 }
1224
1225 #[cfg(test)]
1226 mod test {
1227
1228     use driver::driver::{build_configuration, build_session};
1229     use driver::driver::{build_session_options, optgroups};
1230
1231     use getopts::getopts;
1232     use syntax::attr;
1233     use syntax::attr::AttrMetaMethods;
1234
1235     // When the user supplies --test we should implicitly supply --cfg test
1236     #[test]
1237     fn test_switch_implies_cfg_test() {
1238         let matches =
1239             &match getopts(["--test".to_owned()], optgroups().as_slice()) {
1240               Ok(m) => m,
1241               Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
1242             };
1243         let sessopts = build_session_options(matches);
1244         let sess = build_session(sessopts, None);
1245         let cfg = build_configuration(&sess);
1246         assert!((attr::contains_name(cfg.as_slice(), "test")));
1247     }
1248
1249     // When the user supplies --test and --cfg test, don't implicitly add
1250     // another --cfg test
1251     #[test]
1252     fn test_switch_implies_cfg_test_unless_cfg_test() {
1253         let matches =
1254             &match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
1255                            optgroups().as_slice()) {
1256               Ok(m) => m,
1257               Err(f) => {
1258                 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
1259                        f.to_err_msg());
1260               }
1261             };
1262         let sessopts = build_session_options(matches);
1263         let sess = build_session(sessopts, None);
1264         let cfg = build_configuration(&sess);
1265         let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
1266         assert!(test_items.next().is_some());
1267         assert!(test_items.next().is_none());
1268     }
1269 }