]> git.lizzy.rs Git - rust.git/blob - src/librustc/lib.rs
d1560abf773d1eb035765b2e919f07a815b40054
[rust.git] / src / librustc / lib.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
13 The Rust compiler.
14
15 # Note
16
17 This API is completely unstable and subject to change.
18
19 */
20
21 #[crate_id = "rustc#0.10-pre"];
22 #[comment = "The Rust compiler"];
23 #[license = "MIT/ASL2"];
24 #[crate_type = "dylib"];
25 #[crate_type = "rlib"];
26 #[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
27       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
28       html_root_url = "http://static.rust-lang.org/doc/master")];
29
30 #[allow(deprecated)];
31 #[feature(macro_rules, globs, struct_variant, managed_boxes)];
32 #[feature(quote, default_type_params)];
33
34 extern crate extra;
35 extern crate flate;
36 extern crate arena;
37 extern crate syntax;
38 extern crate serialize;
39 extern crate sync;
40 extern crate getopts;
41 extern crate collections;
42 extern crate time;
43
44 use back::link;
45 use driver::session;
46 use middle::lint;
47
48 use d = driver::driver;
49
50 use std::any::AnyRefExt;
51 use std::cmp;
52 use std::io;
53 use std::os;
54 use std::str;
55 use std::task;
56 use std::vec;
57 use std::vec_ng::Vec;
58 use syntax::ast;
59 use syntax::diagnostic::Emitter;
60 use syntax::diagnostic;
61 use syntax::parse;
62
63 pub mod middle {
64     pub mod trans;
65     pub mod ty;
66     pub mod ty_fold;
67     pub mod subst;
68     pub mod resolve;
69     pub mod resolve_lifetime;
70     pub mod typeck;
71     pub mod check_loop;
72     pub mod check_match;
73     pub mod check_const;
74     pub mod check_static;
75     pub mod lint;
76     pub mod borrowck;
77     pub mod dataflow;
78     pub mod mem_categorization;
79     pub mod liveness;
80     pub mod kind;
81     pub mod freevars;
82     pub mod pat_util;
83     pub mod region;
84     pub mod const_eval;
85     pub mod astencode;
86     pub mod lang_items;
87     pub mod privacy;
88     pub mod moves;
89     pub mod entry;
90     pub mod effect;
91     pub mod reachable;
92     pub mod graph;
93     pub mod cfg;
94     pub mod dead;
95 }
96
97 pub mod front {
98     pub mod config;
99     pub mod test;
100     pub mod std_inject;
101     pub mod assign_node_ids_and_map;
102     pub mod feature_gate;
103     pub mod show_span;
104 }
105
106 pub mod back {
107     pub mod abi;
108     pub mod archive;
109     pub mod arm;
110     pub mod link;
111     pub mod lto;
112     pub mod mips;
113     pub mod rpath;
114     pub mod svh;
115     pub mod target_strs;
116     pub mod x86;
117     pub mod x86_64;
118 }
119
120 pub mod metadata;
121
122 pub mod driver;
123
124 pub mod util {
125     pub mod common;
126     pub mod ppaux;
127     pub mod sha2;
128     pub mod nodemap;
129 }
130
131 pub mod lib {
132     pub mod llvm;
133     pub mod llvmdeps;
134 }
135
136 pub fn version(argv0: &str) {
137     let vers = match option_env!("CFG_VERSION") {
138         Some(vers) => vers,
139         None => "unknown version"
140     };
141     println!("{} {}", argv0, vers);
142     println!("host: {}", d::host_triple());
143 }
144
145 pub fn usage(argv0: &str) {
146     let message = format!("Usage: {} [OPTIONS] INPUT", argv0);
147     println!("{}\n\
148 Additional help:
149     -C help             Print codegen options
150     -W help             Print 'lint' options and default settings
151     -Z help             Print internal options for debugging rustc\n",
152               getopts::usage(message, d::optgroups()));
153 }
154
155 pub fn describe_warnings() {
156     println!("
157 Available lint options:
158     -W <foo>           Warn about <foo>
159     -A <foo>           Allow <foo>
160     -D <foo>           Deny <foo>
161     -F <foo>           Forbid <foo> (deny, and deny all overrides)
162 ");
163
164     let lint_dict = lint::get_lint_dict();
165     let mut lint_dict = lint_dict.move_iter()
166                                  .map(|(k, v)| (v, k))
167                                  .collect::<~[(lint::LintSpec, &'static str)]>();
168     lint_dict.sort();
169
170     let mut max_key = 0;
171     for &(_, name) in lint_dict.iter() {
172         max_key = cmp::max(name.len(), max_key);
173     }
174     fn padded(max: uint, s: &str) -> ~str {
175         " ".repeat(max - s.len()) + s
176     }
177     println!("\nAvailable lint checks:\n");
178     println!("    {}  {:7.7s}  {}",
179              padded(max_key, "name"), "default", "meaning");
180     println!("    {}  {:7.7s}  {}\n",
181              padded(max_key, "----"), "-------", "-------");
182     for (spec, name) in lint_dict.move_iter() {
183         let name = name.replace("_", "-");
184         println!("    {}  {:7.7s}  {}",
185                  padded(max_key, name),
186                  lint::level_to_str(spec.default),
187                  spec.desc);
188     }
189     println!("");
190 }
191
192 pub fn describe_debug_flags() {
193     println!("\nAvailable debug options:\n");
194     let r = session::debugging_opts_map();
195     for tuple in r.iter() {
196         match *tuple {
197             (ref name, ref desc, _) => {
198                 println!("    -Z {:>20s} -- {}", *name, *desc);
199             }
200         }
201     }
202 }
203
204 pub fn describe_codegen_flags() {
205     println!("\nAvailable codegen options:\n");
206     let mut cg = session::basic_codegen_options();
207     for &(name, parser, desc) in session::CG_OPTIONS.iter() {
208         // we invoke the parser function on `None` to see if this option needs
209         // an argument or not.
210         let (width, extra) = if parser(&mut cg, None) {
211             (25, "")
212         } else {
213             (21, "=val")
214         };
215         println!("    -C {:>width$s}{} -- {}", name.replace("_", "-"),
216                  extra, desc, width=width);
217     }
218 }
219
220 pub fn run_compiler(args: &[~str]) {
221     let mut args = args.to_owned();
222     let binary = args.shift().unwrap();
223
224     if args.is_empty() { usage(binary); return; }
225
226     let matches =
227         &match getopts::getopts(args, d::optgroups()) {
228           Ok(m) => m,
229           Err(f) => {
230             d::early_error(f.to_err_msg());
231           }
232         };
233
234     if matches.opt_present("h") || matches.opt_present("help") {
235         usage(binary);
236         return;
237     }
238
239     let lint_flags = vec::append(matches.opt_strs("W"),
240                                  matches.opt_strs("warn"));
241     if lint_flags.iter().any(|x| x == &~"help") {
242         describe_warnings();
243         return;
244     }
245
246     let r = matches.opt_strs("Z");
247     if r.iter().any(|x| x == &~"help") {
248         describe_debug_flags();
249         return;
250     }
251
252     let cg_flags = matches.opt_strs("C");
253     if cg_flags.iter().any(|x| x == &~"help") {
254         describe_codegen_flags();
255         return;
256     }
257
258     if cg_flags.contains(&~"passes=list") {
259         unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
260         return;
261     }
262
263     if matches.opt_present("v") || matches.opt_present("version") {
264         version(binary);
265         return;
266     }
267     let (input, input_file_path) = match matches.free.len() {
268       0u => d::early_error("no input filename given"),
269       1u => {
270         let ifile = matches.free[0].as_slice();
271         if ifile == "-" {
272             let contents = io::stdin().read_to_end().unwrap();
273             let src = str::from_utf8_owned(contents).unwrap();
274             (d::StrInput(src), None)
275         } else {
276             (d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
277         }
278       }
279       _ => d::early_error("multiple input filenames provided")
280     };
281
282     let sopts = d::build_session_options(matches);
283     let sess = d::build_session(sopts, input_file_path);
284     let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
285     let ofile = matches.opt_str("o").map(|o| Path::new(o));
286     let cfg = d::build_configuration(sess);
287     let pretty = matches.opt_default("pretty", "normal").map(|a| {
288         d::parse_pretty(sess, a)
289     });
290     match pretty {
291       Some::<d::PpMode>(ppm) => {
292         d::pretty_print_input(sess, cfg, &input, ppm);
293         return;
294       }
295       None::<d::PpMode> => {/* continue */ }
296     }
297     let ls = matches.opt_present("ls");
298     if ls {
299         match input {
300           d::FileInput(ref ifile) => {
301             let mut stdout = io::stdout();
302             d::list_metadata(sess, &(*ifile), &mut stdout).unwrap();
303           }
304           d::StrInput(_) => {
305             d::early_error("can not list metadata for stdin");
306           }
307         }
308         return;
309     }
310     let (crate_id, crate_name, crate_file_name) = sopts.print_metas;
311     // these nasty nested conditions are to avoid doing extra work
312     if crate_id || crate_name || crate_file_name {
313         let attrs = parse_crate_attrs(sess, &input);
314         let t_outputs = d::build_output_filenames(&input, &odir, &ofile,
315                                                   attrs, sess);
316         let id = link::find_crate_id(attrs, &t_outputs);
317
318         if crate_id {
319             println!("{}", id.to_str());
320         }
321         if crate_name {
322             println!("{}", id.name);
323         }
324         if crate_file_name {
325             let crate_types = session::collect_crate_types(&sess, attrs);
326             for &style in crate_types.iter() {
327                 let fname = link::filename_for_input(&sess, style, &id,
328                                                      &t_outputs.with_extension(""));
329                 println!("{}", fname.filename_display());
330             }
331         }
332
333         return;
334     }
335
336     d::compile_input(sess, cfg, &input, &odir, &ofile);
337 }
338
339 fn parse_crate_attrs(sess: session::Session, input: &d::Input) ->
340                      ~[ast::Attribute] {
341     let result = match *input {
342         d::FileInput(ref ifile) => {
343             parse::parse_crate_attrs_from_file(ifile,
344                                                Vec::new(),
345                                                sess.parse_sess)
346         }
347         d::StrInput(ref src) => {
348             parse::parse_crate_attrs_from_source_str(d::anon_src(),
349                                                      (*src).clone(),
350                                                      Vec::new(),
351                                                      sess.parse_sess)
352         }
353     };
354     result.move_iter().collect()
355 }
356
357 /// Run a procedure which will detect failures in the compiler and print nicer
358 /// error messages rather than just failing the test.
359 ///
360 /// The diagnostic emitter yielded to the procedure should be used for reporting
361 /// errors of the compiler.
362 pub fn monitor(f: proc()) {
363     // FIXME: This is a hack for newsched since it doesn't support split stacks.
364     // rustc needs a lot of stack! When optimizations are disabled, it needs
365     // even *more* stack than usual as well.
366     #[cfg(rtopt)]
367     static STACK_SIZE: uint = 6000000;  // 6MB
368     #[cfg(not(rtopt))]
369     static STACK_SIZE: uint = 20000000; // 20MB
370
371     let mut task_builder = task::task().named("rustc");
372
373     // FIXME: Hacks on hacks. If the env is trying to override the stack size
374     // then *don't* set it explicitly.
375     if os::getenv("RUST_MIN_STACK").is_none() {
376         task_builder.opts.stack_size = Some(STACK_SIZE);
377     }
378
379     let (p, c) = Chan::new();
380     let w = io::ChanWriter::new(c);
381     let mut r = io::PortReader::new(p);
382
383     match task_builder.try(proc() {
384         io::stdio::set_stderr(~w as ~io::Writer);
385         f()
386     }) {
387         Ok(()) => { /* fallthrough */ }
388         Err(value) => {
389             // Task failed without emitting a fatal diagnostic
390             if !value.is::<diagnostic::FatalError>() {
391                 let mut emitter = diagnostic::EmitterWriter::stderr();
392                 emitter.emit(
393                     None,
394                     diagnostic::ice_msg("unexpected failure"),
395                     diagnostic::Error);
396
397                 let xs = [
398                     ~"the compiler hit an unexpected failure path. \
399                      this is a bug",
400                 ];
401                 for note in xs.iter() {
402                     emitter.emit(None, *note, diagnostic::Note)
403                 }
404
405                 println!("{}", r.read_to_str());
406             }
407
408             // Fail so the process returns a failure code, but don't pollute the
409             // output with some unnecessary failure messages, we've already
410             // printed everything that we needed to.
411             io::stdio::set_stderr(~io::util::NullWriter as ~io::Writer);
412             fail!();
413         }
414     }
415 }
416
417 pub fn main() {
418     std::os::set_exit_status(main_args(std::os::args()));
419 }
420
421 pub fn main_args(args: &[~str]) -> int {
422     let owned_args = args.to_owned();
423     monitor(proc() run_compiler(owned_args));
424     0
425 }