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.
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.
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};
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;
26 use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
28 use util::common::time;
30 use util::nodemap::{NodeMap, NodeSet};
32 use serialize::{json, Encodable};
34 use std::cell::{Cell, RefCell};
37 use std::io::MemReader;
40 use getopts::{optopt, optmulti, optflag, optflagopt};
45 use syntax::attr::{AttrMetaMethods};
47 use syntax::crateid::CrateId;
48 use syntax::diagnostic;
49 use syntax::diagnostic::Emitter;
50 use syntax::ext::base::CrateLoader;
52 use syntax::parse::token::InternedString;
53 use syntax::parse::token;
54 use syntax::print::{pp, pprust};
66 * The name used for source code that doesn't originate in a file
67 * (e.g. source from stdin or a string)
69 pub fn anon_src() -> ~str {
73 pub fn source_name(input: &Input) -> ~str {
75 // FIXME (#9639): This needs to handle non-utf8 paths
76 FileInput(ref ifile) => ifile.as_str().unwrap().to_str(),
77 StrInput(_) => anon_src()
81 pub fn default_configuration(sess: &Session) ->
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"),
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")
100 let fam = match sess.targ_cfg.os {
101 abi::OsWin32 => InternedString::new("windows"),
102 _ => InternedString::new("unix")
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))
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))
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
131 append_configuration(&mut user_cfg, InternedString::new("test"))
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")
137 InternedString::new("nogc")
139 user_cfg.move_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
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(),
149 &parse::new_parse_sess())
150 }).collect::<ast::CrateConfig>()
154 /// Load source from file
156 /// The string is the source
161 fn filestem(&self) -> ~str {
163 FileInput(ref ifile) => ifile.filestem_str().unwrap().to_str(),
164 StrInput(_) => "rust_out".to_owned(),
170 pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
172 let krate = time(sess.time_passes(), "parsing", (), |_| {
174 FileInput(ref file) => {
175 parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
177 StrInput(ref src) => {
178 parse::parse_crate_from_source_str(anon_src(),
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();
193 if sess.show_span() {
194 front::show_span::run(sess, &krate);
200 // For continuing compilation after a parsed crate has been
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,
211 -> (ast::Crate, syntax::ast_map::Map) {
212 let time_passes = sess.time_passes();
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());
217 time(time_passes, "gated feature checking", (), |_|
218 front::feature_gate::check_crate(sess, &krate));
220 krate = time(time_passes, "crate injection", krate, |krate|
221 front::std_inject::maybe_inject_crates_ref(sess, krate));
223 // strip before expansion to allow macros to depend on
224 // configuration variables e.g/ in
226 // #[macro_escape] #[cfg(foo)]
227 // mod bar { macro_rules! baz!(() => {{}}) }
229 // baz! should not use this definition unless foo is enabled.
231 krate = time(time_passes, "configuration 1", krate, |krate|
232 front::config::strip_unconfigured_items(krate));
234 krate = time(time_passes, "expansion", krate, |krate| {
235 let cfg = syntax::ext::expand::ExpansionConfig {
237 deriving_hash_type_parameter: sess.features.default_type_params.get(),
238 crate_id: crate_id.clone(),
240 syntax::ext::expand::expand_crate(&sess.parse_sess,
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));
249 krate = time(time_passes, "maybe building test harness", krate, |krate|
250 front::test::modify_for_testing(sess, krate));
252 krate = time(time_passes, "prelude injection", krate, |krate|
253 front::std_inject::maybe_inject_prelude(sess, krate));
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));
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();
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,
273 pub maps: astencode::Maps,
274 pub reachable: NodeSet,
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,
282 ast_map: syntax::ast_map::Map) -> CrateAnalysis {
284 let time_passes = sess.time_passes();
286 time(time_passes, "external crate/lib resolution", (), |_|
287 creader::read_crates(&sess, krate));
289 let lang_items = time(time_passes, "language item collection", (), |_|
290 middle::lang_items::collect_language_items(krate, &sess));
292 let middle::resolve::CrateMap {
295 trait_map: trait_map,
296 external_exports: external_exports,
297 last_private_map: last_private_map
299 time(time_passes, "resolution", (), |_|
300 middle::resolve::resolve_crate(&sess, &lang_items, krate));
302 // Discard MTWT tables that aren't required past resolution.
303 syntax::ext::mtwt::clear_tables();
305 let named_region_map = time(time_passes, "lifetime resolution", (),
306 |_| middle::resolve_lifetime::krate(&sess, krate));
308 time(time_passes, "looking for entry point", (),
309 |_| middle::entry::find_entry_point(&sess, krate, &ast_map));
311 sess.macro_registrar_fn.set(
312 time(time_passes, "looking for macro registrar", (), |_|
313 syntax::ext::registrar::find_macro_registrar(
314 sess.diagnostic(), krate)));
316 let freevars = time(time_passes, "freevar finding", (), |_|
317 freevars::annotate_freevars(&def_map, krate));
319 let region_map = time(time_passes, "region resolution", (), |_|
320 middle::region::resolve_crate(&sess, krate));
322 time(time_passes, "loop checking", (), |_|
323 middle::check_loop::check_crate(&sess, krate));
325 let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
326 freevars, region_map, lang_items);
328 // passes are timed inside typeck
329 typeck::check_crate(&ty_cx, trait_map, krate);
331 time(time_passes, "check static items", (), |_|
332 middle::check_static::check_crate(&ty_cx, krate));
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));
338 time(time_passes, "const checking", (), |_|
339 middle::check_const::check_crate(krate, &ty_cx));
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, &exp_map2, a, b, krate));
346 time(time_passes, "effect checking", (), |_|
347 middle::effect::check_crate(&ty_cx, krate));
349 let middle::moves::MoveMaps {moves_map, capture_map} =
350 time(time_passes, "compute moves", (), |_|
351 middle::moves::compute_moves(&ty_cx, krate));
353 time(time_passes, "match checking", (), |_|
354 middle::check_match::check_crate(&ty_cx, &moves_map, krate));
356 time(time_passes, "liveness checking", (), |_|
357 middle::liveness::check_crate(&ty_cx, &capture_map, krate));
359 time(time_passes, "borrow checking", (), |_|
360 middle::borrowck::check_crate(&ty_cx, &moves_map,
361 &capture_map, krate));
365 time(time_passes, "kind checking", (), |_|
366 kind::check_crate(&ty_cx, krate));
369 time(time_passes, "reachability checking", (), |_|
370 reachable::find_reachable(&ty_cx, &exported_items));
372 time(time_passes, "death checking", (), |_| {
373 middle::dead::check_crate(&ty_cx,
379 time(time_passes, "lint checking", (), |_|
380 lint::check_crate(&ty_cx, &exported_items, krate));
385 exported_items: exported_items,
386 public_items: public_items,
387 maps: astencode::Maps {
388 capture_map: RefCell::new(capture_map)
390 reachable: reachable_map
394 pub struct CrateTranslation {
395 pub context: ContextRef,
396 pub module: ModuleRef,
397 pub metadata_module: ModuleRef,
399 pub metadata: Vec<u8>,
400 pub reachable: Vec<~str>,
403 /// Run the translation phase to LLVM, after which the AST and analysis can
405 pub fn phase_4_translate_to_llvm(krate: ast::Crate,
406 analysis: CrateAnalysis,
407 outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
408 // Option dance to work around the lack of stack once closures.
409 let time_passes = analysis.ty_cx.sess.time_passes();
410 let mut analysis = Some(analysis);
411 time(time_passes, "translation", krate, |krate|
412 trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
415 /// Run LLVM itself, producing a bitcode file, assembly file or object file
416 /// as a side effect.
417 pub fn phase_5_run_llvm_passes(sess: &Session,
418 trans: &CrateTranslation,
419 outputs: &OutputFilenames) {
420 if sess.opts.cg.no_integrated_as {
421 let output_type = link::OutputTypeAssembly;
423 time(sess.time_passes(), "LLVM passes", (), |_|
424 link::write::run_passes(sess, trans, [output_type], outputs));
426 link::write::run_assembler(sess, outputs);
428 // Remove assembly source, unless --save-temps was specified
429 if !sess.opts.cg.save_temps {
430 fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
433 time(sess.time_passes(), "LLVM passes", (), |_|
434 link::write::run_passes(sess,
436 sess.opts.output_types.as_slice(),
441 /// Run the linker on any artifacts that resulted from the LLVM run.
442 /// This should produce either a finished executable or library.
443 pub fn phase_6_link_output(sess: &Session,
444 trans: &CrateTranslation,
445 outputs: &OutputFilenames) {
446 time(sess.time_passes(), "linking", (), |_|
447 link::link_binary(sess,
450 &trans.link.crateid));
453 pub fn stop_after_phase_3(sess: &Session) -> bool {
454 if sess.opts.no_trans {
455 debug!("invoked with --no-trans, returning early from compile_input");
461 pub fn stop_after_phase_1(sess: &Session) -> bool {
462 if sess.opts.parse_only {
463 debug!("invoked with --parse-only, returning early from compile_input");
466 if sess.show_span() {
469 return sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0;
472 pub fn stop_after_phase_2(sess: &Session) -> bool {
473 if sess.opts.no_analysis {
474 debug!("invoked with --no-analysis, returning early from compile_input");
477 return sess.opts.debugging_opts & session::AST_JSON != 0;
480 pub fn stop_after_phase_5(sess: &Session) -> bool {
481 if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) {
482 debug!("not building executable, returning early from compile_input");
488 fn write_out_deps(sess: &Session,
490 outputs: &OutputFilenames,
491 krate: &ast::Crate) {
492 let id = link::find_crate_id(krate.attrs.as_slice(), outputs.out_filestem);
494 let mut out_filenames = Vec::new();
495 for output_type in sess.opts.output_types.iter() {
496 let file = outputs.path(*output_type);
498 link::OutputTypeExe => {
499 for output in sess.crate_types.borrow().iter() {
500 let p = link::filename_for_input(sess, *output, &id, &file);
501 out_filenames.push(p);
504 _ => { out_filenames.push(file); }
508 // Write out dependency rules to the dep-info file if requested with
510 let deps_filename = match sess.opts.write_dependency_info {
511 // Use filename from --dep-file argument if given
512 (true, Some(ref filename)) => filename.clone(),
513 // Use default filename: crate source filename with extension replaced
515 (true, None) => match *input {
516 FileInput(..) => outputs.with_extension("d"),
518 sess.warn("can not write --dep-info without a filename \
519 when compiling stdin.");
527 // Build a list of files used to compile the output and
528 // write Makefile-compatible dependency rules
529 let files: Vec<~str> = sess.codemap().files.borrow()
530 .iter().filter(|fmap| fmap.is_real_file())
531 .map(|fmap| fmap.name.clone())
533 let mut file = try!(io::File::create(&deps_filename));
534 for path in out_filenames.iter() {
535 try!(write!(&mut file as &mut Writer,
536 "{}: {}\n\n", path.display(), files.connect(" ")));
544 sess.fatal(format!("error writing dependencies to `{}`: {}",
545 deps_filename.display(), e));
550 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
551 outdir: &Option<Path>, output: &Option<Path>) {
552 // We need nested scopes here, because the intermediate results can keep
553 // large chunks of memory alive and we want to free them as soon as
554 // possible to keep the peak memory usage low
555 let (outputs, trans, sess) = {
556 let (outputs, expanded_crate, ast_map) = {
557 let krate = phase_1_parse_input(&sess, cfg, input);
558 if stop_after_phase_1(&sess) { return; }
559 let outputs = build_output_filenames(input,
562 krate.attrs.as_slice(),
564 let loader = &mut Loader::new(&sess);
565 let id = link::find_crate_id(krate.attrs.as_slice(),
566 outputs.out_filestem);
567 let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
569 (outputs, expanded_crate, ast_map)
571 write_out_deps(&sess, input, &outputs, &expanded_crate);
573 if stop_after_phase_2(&sess) { return; }
575 let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
576 if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
577 let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
580 // Discard interned strings as they are no longer required.
581 token::get_ident_interner().clear();
583 (outputs, trans, tcx.sess)
585 phase_5_run_llvm_passes(&sess, &trans, &outputs);
586 if stop_after_phase_5(&sess) { return; }
587 phase_6_link_output(&sess, &trans, &outputs);
590 struct IdentifiedAnnotation;
592 impl pprust::PpAnn for IdentifiedAnnotation {
594 s: &mut pprust::State,
595 node: pprust::AnnNode) -> io::IoResult<()> {
597 pprust::NodeExpr(_) => s.popen(),
602 s: &mut pprust::State,
603 node: pprust::AnnNode) -> io::IoResult<()> {
605 pprust::NodeItem(item) => {
606 try!(pp::space(&mut s.s));
607 s.synth_comment(item.id.to_str())
609 pprust::NodeBlock(blk) => {
610 try!(pp::space(&mut s.s));
611 s.synth_comment("block ".to_owned() + blk.id.to_str())
613 pprust::NodeExpr(expr) => {
614 try!(pp::space(&mut s.s));
615 try!(s.synth_comment(expr.id.to_str()));
618 pprust::NodePat(pat) => {
619 try!(pp::space(&mut s.s));
620 s.synth_comment("pat ".to_owned() + pat.id.to_str())
626 struct TypedAnnotation {
627 analysis: CrateAnalysis,
630 impl pprust::PpAnn for TypedAnnotation {
632 s: &mut pprust::State,
633 node: pprust::AnnNode) -> io::IoResult<()> {
635 pprust::NodeExpr(_) => s.popen(),
640 s: &mut pprust::State,
641 node: pprust::AnnNode) -> io::IoResult<()> {
642 let tcx = &self.analysis.ty_cx;
644 pprust::NodeExpr(expr) => {
645 try!(pp::space(&mut s.s));
646 try!(pp::word(&mut s.s, "as"));
647 try!(pp::space(&mut s.s));
648 try!(pp::word(&mut s.s,
649 ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))));
657 pub fn pretty_print_input(sess: Session,
658 cfg: ast::CrateConfig,
661 ofile: Option<Path>) {
662 let krate = phase_1_parse_input(&sess, cfg, input);
663 let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem());
665 let (krate, ast_map, is_expanded) = match ppm {
666 PpmExpanded | PpmExpandedIdentified | PpmTyped => {
667 let loader = &mut Loader::new(&sess);
668 let (krate, ast_map) = phase_2_configure_and_expand(&sess, loader,
670 (krate, Some(ast_map), true)
672 _ => (krate, None, false)
675 let src_name = source_name(input);
676 let src = Vec::from_slice(sess.codemap().get_filemap(src_name).src.as_bytes());
677 let mut rdr = MemReader::new(src);
679 let out = match ofile {
680 None => ~io::stdout() as ~Writer,
682 let r = io::File::create(&p);
684 Ok(w) => ~w as ~Writer,
685 Err(e) => fail!("print-print failed to open {} due to {}",
691 PpmIdentified | PpmExpandedIdentified => {
692 pprust::print_crate(sess.codemap(),
698 &IdentifiedAnnotation,
702 let ast_map = ast_map.expect("--pretty=typed missing ast_map");
703 let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
704 let annotation = TypedAnnotation {
707 pprust::print_crate(annotation.analysis.ty_cx.sess.codemap(),
708 annotation.analysis.ty_cx.sess.diagnostic(),
717 pprust::print_crate(sess.codemap(),
730 pub fn get_os(triple: &str) -> Option<abi::Os> {
731 for &(name, os) in os_names.iter() {
732 if triple.contains(name) { return Some(os) }
736 static os_names : &'static [(&'static str, abi::Os)] = &'static [
737 ("mingw32", abi::OsWin32),
738 ("win32", abi::OsWin32),
739 ("darwin", abi::OsMacos),
740 ("android", abi::OsAndroid),
741 ("linux", abi::OsLinux),
742 ("freebsd", abi::OsFreebsd)];
744 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
745 for &(arch, abi) in architecture_abis.iter() {
746 if triple.contains(arch) { return Some(abi) }
750 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
757 ("x86_64", abi::X86_64),
760 ("xscale", abi::Arm),
763 ("mips", abi::Mips)];
765 pub fn build_target_config(sopts: &session::Options) -> session::Config {
766 let os = match get_os(sopts.target_triple) {
768 None => early_error("unknown operating system")
770 let arch = match get_arch(sopts.target_triple) {
772 None => early_error("unknown architecture: " + sopts.target_triple)
774 let (int_type, uint_type) = match arch {
775 abi::X86 => (ast::TyI32, ast::TyU32),
776 abi::X86_64 => (ast::TyI64, ast::TyU64),
777 abi::Arm => (ast::TyI32, ast::TyU32),
778 abi::Mips => (ast::TyI32, ast::TyU32)
780 let target_triple = sopts.target_triple.clone();
781 let target_strs = match arch {
782 abi::X86 => x86::get_target_strs(target_triple, os),
783 abi::X86_64 => x86_64::get_target_strs(target_triple, os),
784 abi::Arm => arm::get_target_strs(target_triple, os),
785 abi::Mips => mips::get_target_strs(target_triple, os)
790 target_strs: target_strs,
792 uint_type: uint_type,
796 pub fn host_triple() -> &'static str {
797 // Get the host triple out of the build environment. This ensures that our
798 // idea of the host triple is the same as for the set of libraries we've
799 // actually built. We can't just take LLVM's host triple because they
800 // normalize all ix86 architectures to i386.
802 // Instead of grabbing the host triple (for the current host), we grab (at
803 // compile time) the target triple that this rustc is built with and
804 // calling that (at runtime) the host triple.
805 env!("CFG_COMPILER_HOST_TRIPLE")
808 pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
809 let mut crate_types: Vec<CrateType> = Vec::new();
810 let unparsed_crate_types = matches.opt_strs("crate-type");
811 for unparsed_crate_type in unparsed_crate_types.iter() {
812 for part in unparsed_crate_type.split(',') {
813 let new_part = match part {
814 "lib" => session::default_lib_output(),
815 "rlib" => session::CrateTypeRlib,
816 "staticlib" => session::CrateTypeStaticlib,
817 "dylib" => session::CrateTypeDylib,
818 "bin" => session::CrateTypeExecutable,
819 _ => early_error(format!("unknown crate type: `{}`", part))
821 crate_types.push(new_part)
825 let parse_only = matches.opt_present("parse-only");
826 let no_trans = matches.opt_present("no-trans");
827 let no_analysis = matches.opt_present("no-analysis");
829 let lint_levels = [lint::allow, lint::warn,
830 lint::deny, lint::forbid];
831 let mut lint_opts = Vec::new();
832 let lint_dict = lint::get_lint_dict();
833 for level in lint_levels.iter() {
834 let level_name = lint::level_to_str(*level);
836 let level_short = level_name.slice_chars(0, 1);
837 let level_short = level_short.to_ascii().to_upper().into_str();
838 let flags = matches.opt_strs(level_short).move_iter().collect::<Vec<_>>().append(
839 matches.opt_strs(level_name).as_slice());
840 for lint_name in flags.iter() {
841 let lint_name = lint_name.replace("-", "_");
842 match lint_dict.find_equiv(&lint_name) {
844 early_error(format!("unknown {} flag: {}",
845 level_name, lint_name));
848 lint_opts.push((lint.lint, *level));
854 let mut debugging_opts = 0;
855 let debug_flags = matches.opt_strs("Z");
856 let debug_map = session::debugging_opts_map();
857 for debug_flag in debug_flags.iter() {
858 let mut this_bit = 0;
859 for tuple in debug_map.iter() {
860 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
861 if *name == *debug_flag { this_bit = bit; break; }
864 early_error(format!("unknown debug flag: {}", *debug_flag))
866 debugging_opts |= this_bit;
869 if debugging_opts & session::DEBUG_LLVM != 0 {
870 unsafe { llvm::LLVMSetDebug(1); }
873 let mut output_types = Vec::new();
874 if !parse_only && !no_trans {
875 let unparsed_output_types = matches.opt_strs("emit");
876 for unparsed_output_type in unparsed_output_types.iter() {
877 for part in unparsed_output_type.split(',') {
878 let output_type = match part.as_slice() {
879 "asm" => link::OutputTypeAssembly,
880 "ir" => link::OutputTypeLlvmAssembly,
881 "bc" => link::OutputTypeBitcode,
882 "obj" => link::OutputTypeObject,
883 "link" => link::OutputTypeExe,
884 _ => early_error(format!("unknown emission type: `{}`", part))
886 output_types.push(output_type)
890 output_types.as_mut_slice().sort();
891 output_types.dedup();
892 if output_types.len() == 0 {
893 output_types.push(link::OutputTypeExe);
896 let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
897 let target = matches.opt_str("target").unwrap_or(host_triple().to_owned());
899 if (debugging_opts & session::NO_OPT) != 0 {
901 } else if matches.opt_present("O") {
902 if matches.opt_present("opt-level") {
903 early_error("-O and --opt-level both provided");
906 } else if matches.opt_present("opt-level") {
907 match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
911 Some("2") => Default,
912 Some("3") => Aggressive,
914 early_error(format!("optimization level needs to be between 0-3 \
915 (instead was `{}`)", arg));
922 let gc = debugging_opts & session::GC != 0;
923 let debuginfo = if matches.opt_present("g") {
924 if matches.opt_present("debuginfo") {
925 early_error("-g and --debuginfo both provided");
928 } else if matches.opt_present("debuginfo") {
929 match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
930 Some("0") => NoDebugInfo,
931 Some("1") => LimitedDebugInfo,
933 Some("2") => FullDebugInfo,
935 early_error(format!("optimization level needs to be between 0-3 \
936 (instead was `{}`)", arg));
943 let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
944 Path::new(s.as_slice())
947 let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
948 let test = matches.opt_present("test");
949 let write_dependency_info = (matches.opt_present("dep-info"),
950 matches.opt_str("dep-info").map(|p| Path::new(p)));
952 let print_metas = (matches.opt_present("crate-id"),
953 matches.opt_present("crate-name"),
954 matches.opt_present("crate-file-name"));
955 let cg = build_codegen_options(matches);
958 crate_types: crate_types,
961 debuginfo: debuginfo,
962 lint_opts: lint_opts,
963 output_types: output_types,
964 addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
965 maybe_sysroot: sysroot_opt,
966 target_triple: target,
969 parse_only: parse_only,
971 no_analysis: no_analysis,
972 debugging_opts: debugging_opts,
973 write_dependency_info: write_dependency_info,
974 print_metas: print_metas,
979 pub fn build_codegen_options(matches: &getopts::Matches)
980 -> session::CodegenOptions
982 let mut cg = session::basic_codegen_options();
983 for option in matches.opt_strs("C").move_iter() {
984 let mut iter = option.splitn('=', 1);
985 let key = iter.next().unwrap();
986 let value = iter.next();
987 let option_to_lookup = key.replace("-", "_");
988 let mut found = false;
989 for &(candidate, setter, _) in session::CG_OPTIONS.iter() {
990 if option_to_lookup.as_slice() != candidate { continue }
991 if !setter(&mut cg, value) {
993 Some(..) => early_error(format!("codegen option `{}` takes \
995 None => early_error(format!("codegen option `{0}` requires \
996 a value (-C {0}=<value>)",
1004 early_error(format!("unknown codegen option: `{}`", key));
1010 pub fn build_session(sopts: session::Options,
1011 local_crate_source_file: Option<Path>)
1013 let codemap = codemap::CodeMap::new();
1014 let diagnostic_handler =
1015 diagnostic::default_handler();
1016 let span_diagnostic_handler =
1017 diagnostic::mk_span_handler(diagnostic_handler, codemap);
1019 build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
1022 pub fn build_session_(sopts: session::Options,
1023 local_crate_source_file: Option<Path>,
1024 span_diagnostic: diagnostic::SpanHandler)
1026 let target_cfg = build_target_config(&sopts);
1027 let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
1028 let default_sysroot = match sopts.maybe_sysroot {
1030 None => Some(filesearch::get_or_default_sysroot())
1033 // Make the path absolute, if necessary
1034 let local_crate_source_file = local_crate_source_file.map(|path|
1035 if path.is_absolute() {
1038 os::getcwd().join(path.clone())
1043 targ_cfg: target_cfg,
1045 cstore: CStore::new(token::get_ident_interner()),
1047 // For a library crate, this is always none
1048 entry_fn: RefCell::new(None),
1049 entry_type: Cell::new(None),
1050 macro_registrar_fn: Cell::new(None),
1051 default_sysroot: default_sysroot,
1052 building_library: Cell::new(false),
1053 local_crate_source_file: local_crate_source_file,
1054 working_dir: os::getcwd(),
1055 lints: RefCell::new(NodeMap::new()),
1056 node_id: Cell::new(1),
1057 crate_types: RefCell::new(Vec::new()),
1058 features: front::feature_gate::Features::new(),
1059 recursion_limit: Cell::new(64),
1063 pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
1065 &"normal" => PpmNormal,
1066 &"expanded" => PpmExpanded,
1067 &"typed" => PpmTyped,
1068 &"expanded,identified" => PpmExpandedIdentified,
1069 &"identified" => PpmIdentified,
1071 sess.fatal("argument to `pretty` must be one of `normal`, \
1072 `expanded`, `typed`, `identified`, \
1073 or `expanded,identified`");
1078 // rustc command line options
1079 pub fn optgroups() -> Vec<getopts::OptGroup> {
1081 optflag("h", "help", "Display this message"),
1082 optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
1083 optmulti("L", "", "Add a directory to the library search path", "PATH"),
1084 optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit",
1085 "[bin|lib|rlib|dylib|staticlib]"),
1086 optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
1087 "[asm|bc|ir|obj|link]"),
1088 optflag("", "crate-id", "Output the crate id and exit"),
1089 optflag("", "crate-name", "Output the crate name and exit"),
1090 optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
1091 continued and exit"),
1092 optflag("g", "", "Equivalent to --debuginfo=2"),
1093 optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
1095 1 = line-tables only (for stacktraces and breakpoints),
1096 2 = full debug info with variable and type information (same as -g)", "LEVEL"),
1097 optflag("", "no-trans", "Run all passes except translation; no output"),
1098 optflag("", "no-analysis",
1099 "Parse and expand the source, but run no analysis and produce no output"),
1100 optflag("O", "", "Equivalent to --opt-level=2"),
1101 optopt("o", "", "Write output to <filename>", "FILENAME"),
1102 optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
1103 optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
1104 optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
1105 optflagopt("", "pretty",
1106 "Pretty-print the input instead of compiling;
1107 valid types are: normal (un-annotated source),
1108 expanded (crates expanded),
1109 typed (crates expanded, with type annotations),
1110 or identified (fully parenthesized,
1111 AST nodes and blocks with IDs)", "TYPE"),
1112 optflagopt("", "dep-info",
1113 "Output dependency info to <filename> after compiling, \
1114 in a format suitable for use by Makefiles", "FILENAME"),
1115 optopt("", "sysroot", "Override the system root", "PATH"),
1116 optflag("", "test", "Build a test harness"),
1117 optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
1118 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
1119 for details)", "TRIPLE"),
1120 optmulti("W", "warn", "Set lint warnings", "OPT"),
1121 optmulti("A", "allow", "Set lint allowed", "OPT"),
1122 optmulti("D", "deny", "Set lint denied", "OPT"),
1123 optmulti("F", "forbid", "Set lint forbidden", "OPT"),
1124 optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1125 optmulti("Z", "", "Set internal debugging options", "FLAG"),
1126 optflag( "v", "version", "Print version info and exit"))
1129 pub struct OutputFilenames {
1130 pub out_directory: Path,
1131 pub out_filestem: ~str,
1132 pub single_output_file: Option<Path>,
1135 impl OutputFilenames {
1136 pub fn path(&self, flavor: link::OutputType) -> Path {
1137 match self.single_output_file {
1138 Some(ref path) => return path.clone(),
1141 self.temp_path(flavor)
1144 pub fn temp_path(&self, flavor: link::OutputType) -> Path {
1145 let base = self.out_directory.join(self.out_filestem.as_slice());
1147 link::OutputTypeBitcode => base.with_extension("bc"),
1148 link::OutputTypeAssembly => base.with_extension("s"),
1149 link::OutputTypeLlvmAssembly => base.with_extension("ll"),
1150 link::OutputTypeObject => base.with_extension("o"),
1151 link::OutputTypeExe => base,
1155 pub fn with_extension(&self, extension: &str) -> Path {
1156 let stem = self.out_filestem.as_slice();
1157 self.out_directory.join(stem).with_extension(extension)
1161 pub fn build_output_filenames(input: &Input,
1162 odir: &Option<Path>,
1163 ofile: &Option<Path>,
1164 attrs: &[ast::Attribute],
1166 -> OutputFilenames {
1169 // "-" as input file will cause the parser to read from stdin so we
1170 // have to make up a name
1171 // We want to toss everything after the final '.'
1172 let dirpath = match *odir {
1173 Some(ref d) => d.clone(),
1174 None => Path::new(".")
1177 let mut stem = input.filestem();
1179 // If a crateid is present, we use it as the link name
1180 let crateid = attr::find_crateid(attrs);
1183 Some(crateid) => stem = crateid.name.to_str(),
1186 out_directory: dirpath,
1188 single_output_file: None,
1192 Some(ref out_file) => {
1193 let ofile = if sess.opts.output_types.len() > 1 {
1194 sess.warn("ignoring specified output filename because multiple \
1195 outputs were requested");
1198 Some(out_file.clone())
1201 sess.warn("ignoring --out-dir flag due to -o flag.");
1204 out_directory: out_file.dir_path(),
1205 out_filestem: out_file.filestem_str().unwrap().to_str(),
1206 single_output_file: ofile,
1212 pub fn early_error(msg: &str) -> ! {
1213 let mut emitter = diagnostic::EmitterWriter::stderr();
1214 emitter.emit(None, msg, diagnostic::Fatal);
1215 fail!(diagnostic::FatalError);
1218 pub fn list_metadata(sess: &Session, path: &Path,
1219 out: &mut io::Writer) -> io::IoResult<()> {
1220 metadata::loader::list_file_metadata(
1221 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out)
1227 use driver::driver::{build_configuration, build_session};
1228 use driver::driver::{build_session_options, optgroups};
1230 use getopts::getopts;
1232 use syntax::attr::AttrMetaMethods;
1234 // When the user supplies --test we should implicitly supply --cfg test
1236 fn test_switch_implies_cfg_test() {
1238 &match getopts(["--test".to_owned()], optgroups().as_slice()) {
1240 Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
1242 let sessopts = build_session_options(matches);
1243 let sess = build_session(sessopts, None);
1244 let cfg = build_configuration(&sess);
1245 assert!((attr::contains_name(cfg.as_slice(), "test")));
1248 // When the user supplies --test and --cfg test, don't implicitly add
1249 // another --cfg test
1251 fn test_switch_implies_cfg_test_unless_cfg_test() {
1253 &match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
1254 optgroups().as_slice()) {
1257 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
1261 let sessopts = build_session_options(matches);
1262 let sess = build_session(sessopts, None);
1263 let cfg = build_configuration(&sess);
1264 let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
1265 assert!(test_items.next().is_some());
1266 assert!(test_items.next().is_none());