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, moved_variables_set,
351 time(time_passes, "compute moves", (), |_|
352 middle::moves::compute_moves(&ty_cx, krate));
354 time(time_passes, "match checking", (), |_|
355 middle::check_match::check_crate(&ty_cx, &moves_map, krate));
357 time(time_passes, "liveness checking", (), |_|
358 middle::liveness::check_crate(&ty_cx, &capture_map, krate));
361 time(time_passes, "borrow checking", (), |_|
362 middle::borrowck::check_crate(&ty_cx, &moves_map,
363 &moved_variables_set,
364 &capture_map, krate));
367 drop(moved_variables_set);
369 time(time_passes, "kind checking", (), |_|
370 kind::check_crate(&ty_cx, krate));
373 time(time_passes, "reachability checking", (), |_|
374 reachable::find_reachable(&ty_cx, &exported_items));
376 time(time_passes, "death checking", (), |_| {
377 middle::dead::check_crate(&ty_cx,
383 time(time_passes, "lint checking", (), |_|
384 lint::check_crate(&ty_cx, &exported_items, krate));
389 exported_items: exported_items,
390 public_items: public_items,
391 maps: astencode::Maps {
393 capture_map: RefCell::new(capture_map)
395 reachable: reachable_map
399 pub struct CrateTranslation {
400 pub context: ContextRef,
401 pub module: ModuleRef,
402 pub metadata_module: ModuleRef,
404 pub metadata: Vec<u8>,
405 pub reachable: Vec<~str>,
408 /// Run the translation phase to LLVM, after which the AST and analysis can
410 pub fn phase_4_translate_to_llvm(krate: ast::Crate,
411 analysis: CrateAnalysis,
412 outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
413 // Option dance to work around the lack of stack once closures.
414 let time_passes = analysis.ty_cx.sess.time_passes();
415 let mut analysis = Some(analysis);
416 time(time_passes, "translation", krate, |krate|
417 trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
420 /// Run LLVM itself, producing a bitcode file, assembly file or object file
421 /// as a side effect.
422 pub fn phase_5_run_llvm_passes(sess: &Session,
423 trans: &CrateTranslation,
424 outputs: &OutputFilenames) {
425 if sess.opts.cg.no_integrated_as {
426 let output_type = link::OutputTypeAssembly;
428 time(sess.time_passes(), "LLVM passes", (), |_|
429 link::write::run_passes(sess, trans, [output_type], outputs));
431 link::write::run_assembler(sess, outputs);
433 // Remove assembly source, unless --save-temps was specified
434 if !sess.opts.cg.save_temps {
435 fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
438 time(sess.time_passes(), "LLVM passes", (), |_|
439 link::write::run_passes(sess,
441 sess.opts.output_types.as_slice(),
446 /// Run the linker on any artifacts that resulted from the LLVM run.
447 /// This should produce either a finished executable or library.
448 pub fn phase_6_link_output(sess: &Session,
449 trans: &CrateTranslation,
450 outputs: &OutputFilenames) {
451 time(sess.time_passes(), "linking", (), |_|
452 link::link_binary(sess,
455 &trans.link.crateid));
458 pub fn stop_after_phase_3(sess: &Session) -> bool {
459 if sess.opts.no_trans {
460 debug!("invoked with --no-trans, returning early from compile_input");
466 pub fn stop_after_phase_1(sess: &Session) -> bool {
467 if sess.opts.parse_only {
468 debug!("invoked with --parse-only, returning early from compile_input");
471 if sess.show_span() {
474 return sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0;
477 pub fn stop_after_phase_2(sess: &Session) -> bool {
478 if sess.opts.no_analysis {
479 debug!("invoked with --no-analysis, returning early from compile_input");
482 return sess.opts.debugging_opts & session::AST_JSON != 0;
485 pub fn stop_after_phase_5(sess: &Session) -> bool {
486 if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) {
487 debug!("not building executable, returning early from compile_input");
493 fn write_out_deps(sess: &Session,
495 outputs: &OutputFilenames,
496 krate: &ast::Crate) -> io::IoResult<()> {
497 let id = link::find_crate_id(krate.attrs.as_slice(), outputs.out_filestem);
499 let mut out_filenames = Vec::new();
500 for output_type in sess.opts.output_types.iter() {
501 let file = outputs.path(*output_type);
503 link::OutputTypeExe => {
504 for output in sess.crate_types.borrow().iter() {
505 let p = link::filename_for_input(sess, *output, &id, &file);
506 out_filenames.push(p);
509 _ => { out_filenames.push(file); }
513 // Write out dependency rules to the dep-info file if requested with
515 let deps_filename = match sess.opts.write_dependency_info {
516 // Use filename from --dep-file argument if given
517 (true, Some(ref filename)) => filename.clone(),
518 // Use default filename: crate source filename with extension replaced
520 (true, None) => match *input {
521 FileInput(..) => outputs.with_extension("d"),
523 sess.warn("can not write --dep-info without a filename \
524 when compiling stdin.");
531 // Build a list of files used to compile the output and
532 // write Makefile-compatible dependency rules
533 let files: Vec<~str> = sess.codemap().files.borrow()
534 .iter().filter_map(|fmap| {
535 if fmap.is_real_file() {
536 Some(fmap.name.clone())
541 let mut file = try!(io::File::create(&deps_filename));
542 for path in out_filenames.iter() {
543 try!(write!(&mut file as &mut Writer,
544 "{}: {}\n\n", path.display(), files.connect(" ")));
549 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
550 outdir: &Option<Path>, output: &Option<Path>) {
551 // We need nested scopes here, because the intermediate results can keep
552 // large chunks of memory alive and we want to free them as soon as
553 // possible to keep the peak memory usage low
554 let (outputs, trans, sess) = {
555 let (outputs, expanded_crate, ast_map) = {
556 let krate = phase_1_parse_input(&sess, cfg, input);
557 if stop_after_phase_1(&sess) { return; }
558 let outputs = build_output_filenames(input,
561 krate.attrs.as_slice(),
563 let loader = &mut Loader::new(&sess);
564 let id = link::find_crate_id(krate.attrs.as_slice(),
565 outputs.out_filestem);
566 let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
568 (outputs, expanded_crate, ast_map)
570 write_out_deps(&sess, input, &outputs, &expanded_crate).unwrap();
572 if stop_after_phase_2(&sess) { return; }
574 let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
575 if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
576 let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
579 // Discard interned strings as they are no longer required.
580 token::get_ident_interner().clear();
582 (outputs, trans, tcx.sess)
584 phase_5_run_llvm_passes(&sess, &trans, &outputs);
585 if stop_after_phase_5(&sess) { return; }
586 phase_6_link_output(&sess, &trans, &outputs);
589 struct IdentifiedAnnotation;
591 impl pprust::PpAnn for IdentifiedAnnotation {
593 s: &mut pprust::State,
594 node: pprust::AnnNode) -> io::IoResult<()> {
596 pprust::NodeExpr(_) => s.popen(),
601 s: &mut pprust::State,
602 node: pprust::AnnNode) -> io::IoResult<()> {
604 pprust::NodeItem(item) => {
605 try!(pp::space(&mut s.s));
606 s.synth_comment(item.id.to_str())
608 pprust::NodeBlock(blk) => {
609 try!(pp::space(&mut s.s));
610 s.synth_comment("block ".to_owned() + blk.id.to_str())
612 pprust::NodeExpr(expr) => {
613 try!(pp::space(&mut s.s));
614 try!(s.synth_comment(expr.id.to_str()));
617 pprust::NodePat(pat) => {
618 try!(pp::space(&mut s.s));
619 s.synth_comment("pat ".to_owned() + pat.id.to_str())
625 struct TypedAnnotation {
626 analysis: CrateAnalysis,
629 impl pprust::PpAnn for TypedAnnotation {
631 s: &mut pprust::State,
632 node: pprust::AnnNode) -> io::IoResult<()> {
634 pprust::NodeExpr(_) => s.popen(),
639 s: &mut pprust::State,
640 node: pprust::AnnNode) -> io::IoResult<()> {
641 let tcx = &self.analysis.ty_cx;
643 pprust::NodeExpr(expr) => {
644 try!(pp::space(&mut s.s));
645 try!(pp::word(&mut s.s, "as"));
646 try!(pp::space(&mut s.s));
647 try!(pp::word(&mut s.s,
648 ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))));
656 pub fn pretty_print_input(sess: Session,
657 cfg: ast::CrateConfig,
660 ofile: Option<Path>) {
661 let krate = phase_1_parse_input(&sess, cfg, input);
662 let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem());
664 let (krate, ast_map, is_expanded) = match ppm {
665 PpmExpanded | PpmExpandedIdentified | PpmTyped => {
666 let loader = &mut Loader::new(&sess);
667 let (krate, ast_map) = phase_2_configure_and_expand(&sess, loader,
669 (krate, Some(ast_map), true)
671 _ => (krate, None, false)
674 let src_name = source_name(input);
675 let src = Vec::from_slice(sess.codemap().get_filemap(src_name).src.as_bytes());
676 let mut rdr = MemReader::new(src);
678 let out = match ofile {
679 None => ~io::stdout() as ~Writer,
681 let r = io::File::create(&p);
683 Ok(w) => ~w as ~Writer,
684 Err(e) => fail!("print-print failed to open {} due to {}",
690 PpmIdentified | PpmExpandedIdentified => {
691 pprust::print_crate(sess.codemap(),
697 &IdentifiedAnnotation,
701 let ast_map = ast_map.expect("--pretty=typed missing ast_map");
702 let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
703 let annotation = TypedAnnotation {
706 pprust::print_crate(annotation.analysis.ty_cx.sess.codemap(),
707 annotation.analysis.ty_cx.sess.diagnostic(),
716 pprust::print_crate(sess.codemap(),
729 pub fn get_os(triple: &str) -> Option<abi::Os> {
730 for &(name, os) in os_names.iter() {
731 if triple.contains(name) { return Some(os) }
735 static os_names : &'static [(&'static str, abi::Os)] = &'static [
736 ("mingw32", abi::OsWin32),
737 ("win32", abi::OsWin32),
738 ("darwin", abi::OsMacos),
739 ("android", abi::OsAndroid),
740 ("linux", abi::OsLinux),
741 ("freebsd", abi::OsFreebsd)];
743 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
744 for &(arch, abi) in architecture_abis.iter() {
745 if triple.contains(arch) { return Some(abi) }
749 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
756 ("x86_64", abi::X86_64),
759 ("xscale", abi::Arm),
762 ("mips", abi::Mips)];
764 pub fn build_target_config(sopts: &session::Options) -> session::Config {
765 let os = match get_os(sopts.target_triple) {
767 None => early_error("unknown operating system")
769 let arch = match get_arch(sopts.target_triple) {
771 None => early_error("unknown architecture: " + sopts.target_triple)
773 let (int_type, uint_type) = match arch {
774 abi::X86 => (ast::TyI32, ast::TyU32),
775 abi::X86_64 => (ast::TyI64, ast::TyU64),
776 abi::Arm => (ast::TyI32, ast::TyU32),
777 abi::Mips => (ast::TyI32, ast::TyU32)
779 let target_triple = sopts.target_triple.clone();
780 let target_strs = match arch {
781 abi::X86 => x86::get_target_strs(target_triple, os),
782 abi::X86_64 => x86_64::get_target_strs(target_triple, os),
783 abi::Arm => arm::get_target_strs(target_triple, os),
784 abi::Mips => mips::get_target_strs(target_triple, os)
789 target_strs: target_strs,
791 uint_type: uint_type,
795 pub fn host_triple() -> &'static str {
796 // Get the host triple out of the build environment. This ensures that our
797 // idea of the host triple is the same as for the set of libraries we've
798 // actually built. We can't just take LLVM's host triple because they
799 // normalize all ix86 architectures to i386.
801 // Instead of grabbing the host triple (for the current host), we grab (at
802 // compile time) the target triple that this rustc is built with and
803 // calling that (at runtime) the host triple.
804 env!("CFG_COMPILER_HOST_TRIPLE")
807 pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
808 let mut crate_types: Vec<CrateType> = Vec::new();
809 let unparsed_crate_types = matches.opt_strs("crate-type");
810 for unparsed_crate_type in unparsed_crate_types.iter() {
811 for part in unparsed_crate_type.split(',') {
812 let new_part = match part {
813 "lib" => session::default_lib_output(),
814 "rlib" => session::CrateTypeRlib,
815 "staticlib" => session::CrateTypeStaticlib,
816 "dylib" => session::CrateTypeDylib,
817 "bin" => session::CrateTypeExecutable,
818 _ => early_error(format!("unknown crate type: `{}`", part))
820 crate_types.push(new_part)
824 let parse_only = matches.opt_present("parse-only");
825 let no_trans = matches.opt_present("no-trans");
826 let no_analysis = matches.opt_present("no-analysis");
828 let lint_levels = [lint::allow, lint::warn,
829 lint::deny, lint::forbid];
830 let mut lint_opts = Vec::new();
831 let lint_dict = lint::get_lint_dict();
832 for level in lint_levels.iter() {
833 let level_name = lint::level_to_str(*level);
835 let level_short = level_name.slice_chars(0, 1);
836 let level_short = level_short.to_ascii().to_upper().into_str();
837 let flags = matches.opt_strs(level_short).move_iter().collect::<Vec<_>>().append(
838 matches.opt_strs(level_name).as_slice());
839 for lint_name in flags.iter() {
840 let lint_name = lint_name.replace("-", "_");
841 match lint_dict.find_equiv(&lint_name) {
843 early_error(format!("unknown {} flag: {}",
844 level_name, lint_name));
847 lint_opts.push((lint.lint, *level));
853 let mut debugging_opts = 0;
854 let debug_flags = matches.opt_strs("Z");
855 let debug_map = session::debugging_opts_map();
856 for debug_flag in debug_flags.iter() {
857 let mut this_bit = 0;
858 for tuple in debug_map.iter() {
859 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
860 if *name == *debug_flag { this_bit = bit; break; }
863 early_error(format!("unknown debug flag: {}", *debug_flag))
865 debugging_opts |= this_bit;
868 if debugging_opts & session::DEBUG_LLVM != 0 {
869 unsafe { llvm::LLVMSetDebug(1); }
872 let mut output_types = Vec::new();
873 if !parse_only && !no_trans {
874 let unparsed_output_types = matches.opt_strs("emit");
875 for unparsed_output_type in unparsed_output_types.iter() {
876 for part in unparsed_output_type.split(',') {
877 let output_type = match part.as_slice() {
878 "asm" => link::OutputTypeAssembly,
879 "ir" => link::OutputTypeLlvmAssembly,
880 "bc" => link::OutputTypeBitcode,
881 "obj" => link::OutputTypeObject,
882 "link" => link::OutputTypeExe,
883 _ => early_error(format!("unknown emission type: `{}`", part))
885 output_types.push(output_type)
889 output_types.as_mut_slice().sort();
890 output_types.dedup();
891 if output_types.len() == 0 {
892 output_types.push(link::OutputTypeExe);
895 let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
896 let target = matches.opt_str("target").unwrap_or(host_triple().to_owned());
898 if (debugging_opts & session::NO_OPT) != 0 {
900 } else if matches.opt_present("O") {
901 if matches.opt_present("opt-level") {
902 early_error("-O and --opt-level both provided");
905 } else if matches.opt_present("opt-level") {
906 match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
910 Some("2") => Default,
911 Some("3") => Aggressive,
913 early_error(format!("optimization level needs to be between 0-3 \
914 (instead was `{}`)", arg));
921 let gc = debugging_opts & session::GC != 0;
922 let debuginfo = if matches.opt_present("g") {
923 if matches.opt_present("debuginfo") {
924 early_error("-g and --debuginfo both provided");
927 } else if matches.opt_present("debuginfo") {
928 match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
929 Some("0") => NoDebugInfo,
930 Some("1") => LimitedDebugInfo,
932 Some("2") => FullDebugInfo,
934 early_error(format!("optimization level needs to be between 0-3 \
935 (instead was `{}`)", arg));
942 let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
943 Path::new(s.as_slice())
946 let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
947 let test = matches.opt_present("test");
948 let write_dependency_info = (matches.opt_present("dep-info"),
949 matches.opt_str("dep-info").map(|p| Path::new(p)));
951 let print_metas = (matches.opt_present("crate-id"),
952 matches.opt_present("crate-name"),
953 matches.opt_present("crate-file-name"));
954 let cg = build_codegen_options(matches);
957 crate_types: crate_types,
960 debuginfo: debuginfo,
961 lint_opts: lint_opts,
962 output_types: output_types,
963 addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
964 maybe_sysroot: sysroot_opt,
965 target_triple: target,
968 parse_only: parse_only,
970 no_analysis: no_analysis,
971 debugging_opts: debugging_opts,
972 write_dependency_info: write_dependency_info,
973 print_metas: print_metas,
978 pub fn build_codegen_options(matches: &getopts::Matches)
979 -> session::CodegenOptions
981 let mut cg = session::basic_codegen_options();
982 for option in matches.opt_strs("C").move_iter() {
983 let mut iter = option.splitn('=', 1);
984 let key = iter.next().unwrap();
985 let value = iter.next();
986 let option_to_lookup = key.replace("-", "_");
987 let mut found = false;
988 for &(candidate, setter, _) in session::CG_OPTIONS.iter() {
989 if option_to_lookup.as_slice() != candidate { continue }
990 if !setter(&mut cg, value) {
992 Some(..) => early_error(format!("codegen option `{}` takes \
994 None => early_error(format!("codegen option `{0}` requires \
995 a value (-C {0}=<value>)",
1003 early_error(format!("unknown codegen option: `{}`", key));
1009 pub fn build_session(sopts: session::Options,
1010 local_crate_source_file: Option<Path>)
1012 let codemap = codemap::CodeMap::new();
1013 let diagnostic_handler =
1014 diagnostic::default_handler();
1015 let span_diagnostic_handler =
1016 diagnostic::mk_span_handler(diagnostic_handler, codemap);
1018 build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
1021 pub fn build_session_(sopts: session::Options,
1022 local_crate_source_file: Option<Path>,
1023 span_diagnostic: diagnostic::SpanHandler)
1025 let target_cfg = build_target_config(&sopts);
1026 let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
1027 let default_sysroot = match sopts.maybe_sysroot {
1029 None => Some(filesearch::get_or_default_sysroot())
1032 // Make the path absolute, if necessary
1033 let local_crate_source_file = local_crate_source_file.map(|path|
1034 if path.is_absolute() {
1037 os::getcwd().join(path.clone())
1042 targ_cfg: target_cfg,
1044 cstore: CStore::new(token::get_ident_interner()),
1046 // For a library crate, this is always none
1047 entry_fn: RefCell::new(None),
1048 entry_type: Cell::new(None),
1049 macro_registrar_fn: Cell::new(None),
1050 default_sysroot: default_sysroot,
1051 building_library: Cell::new(false),
1052 local_crate_source_file: local_crate_source_file,
1053 working_dir: os::getcwd(),
1054 lints: RefCell::new(NodeMap::new()),
1055 node_id: Cell::new(1),
1056 crate_types: RefCell::new(Vec::new()),
1057 features: front::feature_gate::Features::new(),
1058 recursion_limit: Cell::new(64),
1062 pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
1064 &"normal" => PpmNormal,
1065 &"expanded" => PpmExpanded,
1066 &"typed" => PpmTyped,
1067 &"expanded,identified" => PpmExpandedIdentified,
1068 &"identified" => PpmIdentified,
1070 sess.fatal("argument to `pretty` must be one of `normal`, \
1071 `expanded`, `typed`, `identified`, \
1072 or `expanded,identified`");
1077 // rustc command line options
1078 pub fn optgroups() -> Vec<getopts::OptGroup> {
1080 optflag("h", "help", "Display this message"),
1081 optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
1082 optmulti("L", "", "Add a directory to the library search path", "PATH"),
1083 optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit",
1084 "[bin|lib|rlib|dylib|staticlib]"),
1085 optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
1086 "[asm|bc|ir|obj|link]"),
1087 optflag("", "crate-id", "Output the crate id and exit"),
1088 optflag("", "crate-name", "Output the crate name and exit"),
1089 optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
1090 continued and exit"),
1091 optflag("g", "", "Equivalent to --debuginfo=2"),
1092 optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
1094 1 = line-tables only (for stacktraces and breakpoints),
1095 2 = full debug info with variable and type information (same as -g)", "LEVEL"),
1096 optflag("", "no-trans", "Run all passes except translation; no output"),
1097 optflag("", "no-analysis",
1098 "Parse and expand the source, but run no analysis and produce no output"),
1099 optflag("O", "", "Equivalent to --opt-level=2"),
1100 optopt("o", "", "Write output to <filename>", "FILENAME"),
1101 optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
1102 optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
1103 optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
1104 optflagopt("", "pretty",
1105 "Pretty-print the input instead of compiling;
1106 valid types are: normal (un-annotated source),
1107 expanded (crates expanded),
1108 typed (crates expanded, with type annotations),
1109 or identified (fully parenthesized,
1110 AST nodes and blocks with IDs)", "TYPE"),
1111 optflagopt("", "dep-info",
1112 "Output dependency info to <filename> after compiling, \
1113 in a format suitable for use by Makefiles", "FILENAME"),
1114 optopt("", "sysroot", "Override the system root", "PATH"),
1115 optflag("", "test", "Build a test harness"),
1116 optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
1117 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
1118 for details)", "TRIPLE"),
1119 optmulti("W", "warn", "Set lint warnings", "OPT"),
1120 optmulti("A", "allow", "Set lint allowed", "OPT"),
1121 optmulti("D", "deny", "Set lint denied", "OPT"),
1122 optmulti("F", "forbid", "Set lint forbidden", "OPT"),
1123 optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1124 optmulti("Z", "", "Set internal debugging options", "FLAG"),
1125 optflag( "v", "version", "Print version info and exit"))
1128 pub struct OutputFilenames {
1129 pub out_directory: Path,
1130 pub out_filestem: ~str,
1131 pub single_output_file: Option<Path>,
1134 impl OutputFilenames {
1135 pub fn path(&self, flavor: link::OutputType) -> Path {
1136 match self.single_output_file {
1137 Some(ref path) => return path.clone(),
1140 self.temp_path(flavor)
1143 pub fn temp_path(&self, flavor: link::OutputType) -> Path {
1144 let base = self.out_directory.join(self.out_filestem.as_slice());
1146 link::OutputTypeBitcode => base.with_extension("bc"),
1147 link::OutputTypeAssembly => base.with_extension("s"),
1148 link::OutputTypeLlvmAssembly => base.with_extension("ll"),
1149 link::OutputTypeObject => base.with_extension("o"),
1150 link::OutputTypeExe => base,
1154 pub fn with_extension(&self, extension: &str) -> Path {
1155 let stem = self.out_filestem.as_slice();
1156 self.out_directory.join(stem).with_extension(extension)
1160 pub fn build_output_filenames(input: &Input,
1161 odir: &Option<Path>,
1162 ofile: &Option<Path>,
1163 attrs: &[ast::Attribute],
1165 -> OutputFilenames {
1168 // "-" as input file will cause the parser to read from stdin so we
1169 // have to make up a name
1170 // We want to toss everything after the final '.'
1171 let dirpath = match *odir {
1172 Some(ref d) => d.clone(),
1173 None => Path::new(".")
1176 let mut stem = input.filestem();
1178 // If a crateid is present, we use it as the link name
1179 let crateid = attr::find_crateid(attrs);
1182 Some(crateid) => stem = crateid.name.to_str(),
1185 out_directory: dirpath,
1187 single_output_file: None,
1191 Some(ref out_file) => {
1192 let ofile = if sess.opts.output_types.len() > 1 {
1193 sess.warn("ignoring specified output filename because multiple \
1194 outputs were requested");
1197 Some(out_file.clone())
1200 sess.warn("ignoring --out-dir flag due to -o flag.");
1203 out_directory: out_file.dir_path(),
1204 out_filestem: out_file.filestem_str().unwrap().to_str(),
1205 single_output_file: ofile,
1211 pub fn early_error(msg: &str) -> ! {
1212 let mut emitter = diagnostic::EmitterWriter::stderr();
1213 emitter.emit(None, msg, diagnostic::Fatal);
1214 fail!(diagnostic::FatalError);
1217 pub fn list_metadata(sess: &Session, path: &Path,
1218 out: &mut io::Writer) -> io::IoResult<()> {
1219 metadata::loader::list_file_metadata(
1220 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out)
1226 use driver::driver::{build_configuration, build_session};
1227 use driver::driver::{build_session_options, optgroups};
1229 use getopts::getopts;
1231 use syntax::attr::AttrMetaMethods;
1233 // When the user supplies --test we should implicitly supply --cfg test
1235 fn test_switch_implies_cfg_test() {
1237 &match getopts(["--test".to_owned()], optgroups().as_slice()) {
1239 Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
1241 let sessopts = build_session_options(matches);
1242 let sess = build_session(sessopts, None);
1243 let cfg = build_configuration(&sess);
1244 assert!((attr::contains_name(cfg.as_slice(), "test")));
1247 // When the user supplies --test and --cfg test, don't implicitly add
1248 // another --cfg test
1250 fn test_switch_implies_cfg_test_unless_cfg_test() {
1252 &match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
1253 optgroups().as_slice()) {
1256 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
1260 let sessopts = build_session_options(matches);
1261 let sess = build_session(sessopts, None);
1262 let cfg = build_configuration(&sess);
1263 let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
1264 assert!(test_items.next().is_some());
1265 assert!(test_items.next().is_none());