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