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