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;
41 use getopts::{optopt, optmulti, optflag, optflagopt};
46 use syntax::attr::{AttrMetaMethods};
48 use syntax::crateid::CrateId;
49 use syntax::diagnostic;
50 use syntax::diagnostic::Emitter;
51 use syntax::ext::base::CrateLoader;
53 use syntax::parse::token::InternedString;
54 use syntax::parse::token;
55 use syntax::print::{pp, pprust};
67 * The name used for source code that doesn't originate in a file
68 * (e.g. source from stdin or a string)
70 pub fn anon_src() -> ~str {
74 pub fn source_name(input: &Input) -> ~str {
76 // FIXME (#9639): This needs to handle non-utf8 paths
77 FileInput(ref ifile) => ifile.as_str().unwrap().to_str(),
78 StrInput(_) => anon_src()
82 pub fn default_configuration(sess: &Session) ->
84 let tos = match sess.targ_cfg.os {
85 abi::OsWin32 => InternedString::new("win32"),
86 abi::OsMacos => InternedString::new("macos"),
87 abi::OsLinux => InternedString::new("linux"),
88 abi::OsAndroid => InternedString::new("android"),
89 abi::OsFreebsd => InternedString::new("freebsd"),
92 // ARM is bi-endian, however using NDK seems to default
93 // to little-endian unless a flag is provided.
94 let (end,arch,wordsz) = match sess.targ_cfg.arch {
95 abi::X86 => ("little", "x86", "32"),
96 abi::X86_64 => ("little", "x86_64", "64"),
97 abi::Arm => ("little", "arm", "32"),
98 abi::Mips => ("big", "mips", "32")
101 let fam = match sess.targ_cfg.os {
102 abi::OsWin32 => InternedString::new("windows"),
103 _ => InternedString::new("unix")
106 let mk = attr::mk_name_value_item_str;
107 return vec!(// Target bindings.
108 attr::mk_word_item(fam.clone()),
109 mk(InternedString::new("target_os"), tos),
110 mk(InternedString::new("target_family"), fam),
111 mk(InternedString::new("target_arch"), InternedString::new(arch)),
112 mk(InternedString::new("target_endian"), InternedString::new(end)),
113 mk(InternedString::new("target_word_size"),
114 InternedString::new(wordsz))
118 pub fn append_configuration(cfg: &mut ast::CrateConfig,
119 name: InternedString) {
120 if !cfg.iter().any(|mi| mi.name() == name) {
121 cfg.push(attr::mk_word_item(name))
125 pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
126 // Combine the configuration requested by the session (command line) with
127 // some default and generated configuration items
128 let default_cfg = default_configuration(sess);
129 let mut user_cfg = sess.opts.cfg.clone();
130 // If the user wants a test runner, then add the test cfg
132 append_configuration(&mut user_cfg, InternedString::new("test"))
134 // If the user requested GC, then add the GC cfg
135 append_configuration(&mut user_cfg, if sess.opts.gc {
136 InternedString::new("gc")
138 InternedString::new("nogc")
140 return vec::append(user_cfg.move_iter().collect(),
141 default_cfg.as_slice());
144 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
145 fn parse_cfgspecs(cfgspecs: Vec<~str> )
146 -> ast::CrateConfig {
147 cfgspecs.move_iter().map(|s| {
148 parse::parse_meta_from_source_str("cfgspec".to_str(),
151 &parse::new_parse_sess())
152 }).collect::<ast::CrateConfig>()
156 /// Load source from file
158 /// The string is the source
163 fn filestem(&self) -> ~str {
165 FileInput(ref ifile) => ifile.filestem_str().unwrap().to_str(),
166 StrInput(_) => ~"rust_out",
171 pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
173 let krate = time(sess.time_passes(), "parsing", (), |_| {
175 FileInput(ref file) => {
176 parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
178 StrInput(ref src) => {
179 parse::parse_crate_from_source_str(anon_src(),
187 if sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0 {
188 let mut stdout = io::BufferedWriter::new(io::stdout());
189 let mut json = json::PrettyEncoder::new(&mut stdout);
190 krate.encode(&mut json);
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.set(session::collect_crate_types(sess,
219 time(time_passes, "gated feature checking", (), |_|
220 front::feature_gate::check_crate(sess, &krate));
222 krate = time(time_passes, "crate injection", krate, |krate|
223 front::std_inject::maybe_inject_crates_ref(sess, krate));
225 // strip before expansion to allow macros to depend on
226 // configuration variables e.g/ in
228 // #[macro_escape] #[cfg(foo)]
229 // mod bar { macro_rules! baz!(() => {{}}) }
231 // baz! should not use this definition unless foo is enabled.
233 krate = time(time_passes, "configuration 1", krate, |krate|
234 front::config::strip_unconfigured_items(krate));
236 krate = time(time_passes, "expansion", krate, |krate| {
237 let cfg = syntax::ext::expand::ExpansionConfig {
239 deriving_hash_type_parameter: sess.features.default_type_params.get(),
240 crate_id: crate_id.clone(),
242 syntax::ext::expand::expand_crate(&sess.parse_sess,
246 // dump the syntax-time crates
249 // strip again, in case expansion added anything with a #[cfg].
250 krate = time(time_passes, "configuration 2", krate, |krate|
251 front::config::strip_unconfigured_items(krate));
253 krate = time(time_passes, "maybe building test harness", krate, |krate|
254 front::test::modify_for_testing(sess, krate));
256 krate = time(time_passes, "prelude injection", krate, |krate|
257 front::std_inject::maybe_inject_prelude(sess, krate));
259 let (krate, map) = time(time_passes, "assinging node ids and indexing ast", krate, |krate|
260 front::assign_node_ids_and_map::assign_node_ids_and_map(sess, krate));
262 if sess.opts.debugging_opts & session::AST_JSON != 0 {
263 let mut stdout = io::BufferedWriter::new(io::stdout());
264 let mut json = json::PrettyEncoder::new(&mut stdout);
265 krate.encode(&mut json);
271 pub struct CrateAnalysis {
272 exp_map2: middle::resolve::ExportMap2,
273 exported_items: middle::privacy::ExportedItems,
274 public_items: middle::privacy::PublicItems,
276 maps: astencode::Maps,
280 /// Run the resolution, typechecking, region checking and other
281 /// miscellaneous analysis passes on the crate. Return various
282 /// structures carrying the results of the analysis.
283 pub fn phase_3_run_analysis_passes(sess: Session,
285 ast_map: syntax::ast_map::Map) -> CrateAnalysis {
287 let time_passes = sess.time_passes();
289 time(time_passes, "external crate/lib resolution", (), |_|
290 creader::read_crates(&sess, krate,
291 session::sess_os_to_meta_os(sess.targ_cfg.os),
292 token::get_ident_interner()));
294 let lang_items = time(time_passes, "language item collection", (), |_|
295 middle::lang_items::collect_language_items(krate, &sess));
297 let middle::resolve::CrateMap {
300 trait_map: trait_map,
301 external_exports: external_exports,
302 last_private_map: last_private_map
304 time(time_passes, "resolution", (), |_|
305 middle::resolve::resolve_crate(&sess, lang_items, krate));
307 // Discard MTWT tables that aren't required past resolution.
308 syntax::ext::mtwt::clear_tables();
310 let named_region_map = time(time_passes, "lifetime resolution", (),
311 |_| middle::resolve_lifetime::krate(&sess, krate));
313 time(time_passes, "looking for entry point", (),
314 |_| middle::entry::find_entry_point(&sess, krate, &ast_map));
316 *sess.macro_registrar_fn.borrow_mut() =
317 time(time_passes, "looking for macro registrar", (), |_|
318 syntax::ext::registrar::find_macro_registrar(
319 sess.diagnostic(), krate));
321 let freevars = time(time_passes, "freevar finding", (), |_|
322 freevars::annotate_freevars(def_map, krate));
324 let region_map = time(time_passes, "region resolution", (), |_|
325 middle::region::resolve_crate(&sess, krate));
327 let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map,
328 freevars, region_map, lang_items);
330 // passes are timed inside typeck
331 let (method_map, vtable_map) = typeck::check_crate(&ty_cx, trait_map, krate);
333 time(time_passes, "check static items", (), |_|
334 middle::check_static::check_crate(&ty_cx, krate));
336 // These next two const passes can probably be merged
337 time(time_passes, "const marking", (), |_|
338 middle::const_eval::process_crate(krate, &ty_cx));
340 time(time_passes, "const checking", (), |_|
341 middle::check_const::check_crate(krate, def_map, method_map, &ty_cx));
343 let maps = (external_exports, last_private_map);
344 let (exported_items, public_items) =
345 time(time_passes, "privacy checking", maps, |(a, b)|
346 middle::privacy::check_crate(&ty_cx, &method_map, &exp_map2,
349 time(time_passes, "effect checking", (), |_|
350 middle::effect::check_crate(&ty_cx, method_map, krate));
352 time(time_passes, "loop checking", (), |_|
353 middle::check_loop::check_crate(&ty_cx, krate));
355 let middle::moves::MoveMaps {moves_map, moved_variables_set,
357 time(time_passes, "compute moves", (), |_|
358 middle::moves::compute_moves(&ty_cx, method_map, krate));
360 time(time_passes, "match checking", (), |_|
361 middle::check_match::check_crate(&ty_cx, method_map,
364 time(time_passes, "liveness checking", (), |_|
365 middle::liveness::check_crate(&ty_cx, method_map,
366 &capture_map, krate));
369 time(time_passes, "borrow checking", (), |_|
370 middle::borrowck::check_crate(&ty_cx, method_map,
371 &moves_map, &moved_variables_set,
372 &capture_map, krate));
375 drop(moved_variables_set);
377 time(time_passes, "kind checking", (), |_|
378 kind::check_crate(&ty_cx, method_map, krate));
381 time(time_passes, "reachability checking", (), |_|
382 reachable::find_reachable(&ty_cx, method_map, &exported_items));
384 time(time_passes, "death checking", (), |_| {
385 middle::dead::check_crate(&ty_cx,
392 time(time_passes, "lint checking", (), |_|
393 lint::check_crate(&ty_cx, method_map, &exported_items, krate));
398 exported_items: exported_items,
399 public_items: public_items,
400 maps: astencode::Maps {
402 method_map: method_map,
403 vtable_map: vtable_map,
404 capture_map: RefCell::new(capture_map)
406 reachable: reachable_map
410 pub struct CrateTranslation {
413 metadata_module: ModuleRef,
416 reachable: Vec<~str> ,
419 /// Run the translation phase to LLVM, after which the AST and analysis can
421 pub fn phase_4_translate_to_llvm(krate: ast::Crate,
422 analysis: CrateAnalysis,
423 outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
424 // Option dance to work around the lack of stack once closures.
425 let time_passes = analysis.ty_cx.sess.time_passes();
426 let mut analysis = Some(analysis);
427 time(time_passes, "translation", krate, |krate|
428 trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
431 /// Run LLVM itself, producing a bitcode file, assembly file or object file
432 /// as a side effect.
433 pub fn phase_5_run_llvm_passes(sess: &Session,
434 trans: &CrateTranslation,
435 outputs: &OutputFilenames) {
436 if sess.opts.cg.no_integrated_as {
437 let output_type = link::OutputTypeAssembly;
439 time(sess.time_passes(), "LLVM passes", (), |_|
440 link::write::run_passes(sess, trans, [output_type], outputs));
442 link::write::run_assembler(sess, outputs);
444 // Remove assembly source, unless --save-temps was specified
445 if !sess.opts.cg.save_temps {
446 fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
449 time(sess.time_passes(), "LLVM passes", (), |_|
450 link::write::run_passes(sess,
452 sess.opts.output_types.as_slice(),
457 /// Run the linker on any artifacts that resulted from the LLVM run.
458 /// This should produce either a finished executable or library.
459 pub fn phase_6_link_output(sess: &Session,
460 trans: &CrateTranslation,
461 outputs: &OutputFilenames) {
462 time(sess.time_passes(), "linking", (), |_|
463 link::link_binary(sess,
466 &trans.link.crateid));
469 pub fn stop_after_phase_3(sess: &Session) -> bool {
470 if sess.opts.no_trans {
471 debug!("invoked with --no-trans, returning early from compile_input");
477 pub fn stop_after_phase_1(sess: &Session) -> bool {
478 if sess.opts.parse_only {
479 debug!("invoked with --parse-only, returning early from compile_input");
482 if sess.show_span() {
485 return sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0;
488 pub fn stop_after_phase_2(sess: &Session) -> bool {
489 if sess.opts.no_analysis {
490 debug!("invoked with --no-analysis, returning early from compile_input");
493 return sess.opts.debugging_opts & session::AST_JSON != 0;
496 pub fn stop_after_phase_5(sess: &Session) -> bool {
497 if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) {
498 debug!("not building executable, returning early from compile_input");
504 fn write_out_deps(sess: &Session,
506 outputs: &OutputFilenames,
507 krate: &ast::Crate) -> io::IoResult<()> {
508 let id = link::find_crate_id(krate.attrs.as_slice(), outputs.out_filestem);
510 let mut out_filenames = Vec::new();
511 for output_type in sess.opts.output_types.iter() {
512 let file = outputs.path(*output_type);
514 link::OutputTypeExe => {
515 let crate_types = sess.crate_types.borrow();
516 for output in crate_types.get().iter() {
517 let p = link::filename_for_input(sess, *output, &id, &file);
518 out_filenames.push(p);
521 _ => { out_filenames.push(file); }
525 // Write out dependency rules to the dep-info file if requested with
527 let deps_filename = match sess.opts.write_dependency_info {
528 // Use filename from --dep-file argument if given
529 (true, Some(ref filename)) => filename.clone(),
530 // Use default filename: crate source filename with extension replaced
532 (true, None) => match *input {
533 FileInput(..) => outputs.with_extension("d"),
535 sess.warn("can not write --dep-info without a filename \
536 when compiling stdin.");
543 // Build a list of files used to compile the output and
544 // write Makefile-compatible dependency rules
545 let files: Vec<~str> = sess.codemap().files.borrow().get()
546 .iter().filter_map(|fmap| {
547 if fmap.deref().is_real_file() {
548 Some(fmap.deref().name.clone())
553 let mut file = try!(io::File::create(&deps_filename));
554 for path in out_filenames.iter() {
555 try!(write!(&mut file as &mut Writer,
556 "{}: {}\n\n", path.display(), files.connect(" ")));
561 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
562 outdir: &Option<Path>, output: &Option<Path>) {
563 // We need nested scopes here, because the intermediate results can keep
564 // large chunks of memory alive and we want to free them as soon as
565 // possible to keep the peak memory usage low
566 let (outputs, trans, sess) = {
567 let (outputs, expanded_crate, ast_map) = {
568 let krate = phase_1_parse_input(&sess, cfg, input);
569 if stop_after_phase_1(&sess) { return; }
570 let outputs = build_output_filenames(input,
573 krate.attrs.as_slice(),
575 let loader = &mut Loader::new(&sess);
576 let id = link::find_crate_id(krate.attrs.as_slice(),
577 outputs.out_filestem);
578 let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
580 (outputs, expanded_crate, ast_map)
582 write_out_deps(&sess, input, &outputs, &expanded_crate).unwrap();
584 if stop_after_phase_2(&sess) { return; }
586 let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
587 if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
588 let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
591 // Discard interned strings as they are no longer required.
592 token::get_ident_interner().clear();
594 (outputs, trans, tcx.sess)
596 phase_5_run_llvm_passes(&sess, &trans, &outputs);
597 if stop_after_phase_5(&sess) { return; }
598 phase_6_link_output(&sess, &trans, &outputs);
601 struct IdentifiedAnnotation;
603 impl pprust::PpAnn for IdentifiedAnnotation {
605 s: &mut pprust::State,
606 node: pprust::AnnNode) -> io::IoResult<()> {
608 pprust::NodeExpr(_) => s.popen(),
613 s: &mut pprust::State,
614 node: pprust::AnnNode) -> io::IoResult<()> {
616 pprust::NodeItem(item) => {
617 try!(pp::space(&mut s.s));
618 s.synth_comment(item.id.to_str())
620 pprust::NodeBlock(blk) => {
621 try!(pp::space(&mut s.s));
622 s.synth_comment(~"block " + blk.id.to_str())
624 pprust::NodeExpr(expr) => {
625 try!(pp::space(&mut s.s));
626 try!(s.synth_comment(expr.id.to_str()));
629 pprust::NodePat(pat) => {
630 try!(pp::space(&mut s.s));
631 s.synth_comment(~"pat " + pat.id.to_str())
637 struct TypedAnnotation {
638 analysis: CrateAnalysis,
641 impl pprust::PpAnn for TypedAnnotation {
643 s: &mut pprust::State,
644 node: pprust::AnnNode) -> io::IoResult<()> {
646 pprust::NodeExpr(_) => s.popen(),
651 s: &mut pprust::State,
652 node: pprust::AnnNode) -> io::IoResult<()> {
653 let tcx = &self.analysis.ty_cx;
655 pprust::NodeExpr(expr) => {
656 try!(pp::space(&mut s.s));
657 try!(pp::word(&mut s.s, "as"));
658 try!(pp::space(&mut s.s));
659 try!(pp::word(&mut s.s,
660 ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))));
668 pub fn pretty_print_input(sess: Session,
669 cfg: ast::CrateConfig,
672 let krate = phase_1_parse_input(&sess, cfg, input);
673 let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem());
675 let (krate, ast_map, is_expanded) = match ppm {
676 PpmExpanded | PpmExpandedIdentified | PpmTyped => {
677 let loader = &mut Loader::new(&sess);
678 let (krate, ast_map) = phase_2_configure_and_expand(&sess, loader,
680 (krate, Some(ast_map), true)
682 _ => (krate, None, false)
685 let src_name = source_name(input);
686 let src = sess.codemap().get_filemap(src_name).deref().src.as_bytes().to_owned();
687 let mut rdr = MemReader::new(src);
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() -> ~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")).to_owned()
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 = vec::append(matches.opt_strs(level_short)
840 matches.opt_strs(level_name).as_slice());
841 for lint_name in flags.iter() {
842 let lint_name = lint_name.replace("-", "_");
843 match lint_dict.find_equiv(&lint_name) {
845 early_error(format!("unknown {} flag: {}",
846 level_name, lint_name));
849 lint_opts.push((lint.lint, *level));
855 let mut debugging_opts = 0;
856 let debug_flags = matches.opt_strs("Z");
857 let debug_map = session::debugging_opts_map();
858 for debug_flag in debug_flags.iter() {
859 let mut this_bit = 0;
860 for tuple in debug_map.iter() {
861 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
862 if *name == *debug_flag { this_bit = bit; break; }
865 early_error(format!("unknown debug flag: {}", *debug_flag))
867 debugging_opts |= this_bit;
870 if debugging_opts & session::DEBUG_LLVM != 0 {
871 unsafe { llvm::LLVMSetDebug(1); }
874 let mut output_types = Vec::new();
875 if !parse_only && !no_trans {
876 let unparsed_output_types = matches.opt_strs("emit");
877 for unparsed_output_type in unparsed_output_types.iter() {
878 for part in unparsed_output_type.split(',') {
879 let output_type = match part.as_slice() {
880 "asm" => link::OutputTypeAssembly,
881 "ir" => link::OutputTypeLlvmAssembly,
882 "bc" => link::OutputTypeBitcode,
883 "obj" => link::OutputTypeObject,
884 "link" => link::OutputTypeExe,
885 _ => early_error(format!("unknown emission type: `{}`", part))
887 output_types.push(output_type)
891 output_types.as_mut_slice().sort();
892 output_types.dedup();
893 if output_types.len() == 0 {
894 output_types.push(link::OutputTypeExe);
897 let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
898 let target = matches.opt_str("target").unwrap_or(host_triple());
900 if (debugging_opts & session::NO_OPT) != 0 {
902 } else if matches.opt_present("O") {
903 if matches.opt_present("opt-level") {
904 early_error("-O and --opt-level both provided");
907 } else if matches.opt_present("opt-level") {
908 match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
912 Some("2") => Default,
913 Some("3") => Aggressive,
915 early_error(format!("optimization level needs to be between 0-3 \
916 (instead was `{}`)", arg));
923 let gc = debugging_opts & session::GC != 0;
924 let debuginfo = if matches.opt_present("g") {
925 if matches.opt_present("debuginfo") {
926 early_error("-g and --debuginfo both provided");
929 } else if matches.opt_present("debuginfo") {
930 match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
931 Some("0") => NoDebugInfo,
932 Some("1") => LimitedDebugInfo,
934 Some("2") => FullDebugInfo,
936 early_error(format!("optimization level needs to be between 0-3 \
937 (instead was `{}`)", arg));
944 let addl_lib_search_paths = matches.opt_strs("L").map(|s| {
945 Path::new(s.as_slice())
946 }).move_iter().collect();
948 let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
949 let test = matches.opt_present("test");
950 let write_dependency_info = (matches.opt_present("dep-info"),
951 matches.opt_str("dep-info").map(|p| Path::new(p)));
953 let print_metas = (matches.opt_present("crate-id"),
954 matches.opt_present("crate-name"),
955 matches.opt_present("crate-file-name"));
956 let cg = build_codegen_options(matches);
959 crate_types: crate_types,
962 debuginfo: debuginfo,
963 lint_opts: lint_opts,
964 output_types: output_types,
965 addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
966 maybe_sysroot: sysroot_opt,
967 target_triple: target,
970 parse_only: parse_only,
972 no_analysis: no_analysis,
973 debugging_opts: debugging_opts,
974 write_dependency_info: write_dependency_info,
975 print_metas: print_metas,
980 pub fn build_codegen_options(matches: &getopts::Matches)
981 -> session::CodegenOptions
983 let mut cg = session::basic_codegen_options();
984 for option in matches.opt_strs("C").move_iter() {
985 let mut iter = option.splitn('=', 1);
986 let key = iter.next().unwrap();
987 let value = iter.next();
988 let option_to_lookup = key.replace("-", "_");
989 let mut found = false;
990 for &(candidate, setter, _) in session::CG_OPTIONS.iter() {
991 if option_to_lookup.as_slice() != candidate { continue }
992 if !setter(&mut cg, value) {
994 Some(..) => early_error(format!("codegen option `{}` takes \
996 None => early_error(format!("codegen option `{0}` requires \
997 a value (-C {0}=<value>)",
1005 early_error(format!("unknown codegen option: `{}`", key));
1011 pub fn build_session(sopts: session::Options,
1012 local_crate_source_file: Option<Path>)
1014 let codemap = codemap::CodeMap::new();
1015 let diagnostic_handler =
1016 diagnostic::default_handler();
1017 let span_diagnostic_handler =
1018 diagnostic::mk_span_handler(diagnostic_handler, codemap);
1020 build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
1023 pub fn build_session_(sopts: session::Options,
1024 local_crate_source_file: Option<Path>,
1025 span_diagnostic: diagnostic::SpanHandler)
1027 let target_cfg = build_target_config(&sopts);
1028 let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
1029 let default_sysroot = match sopts.maybe_sysroot {
1031 None => Some(filesearch::get_or_default_sysroot())
1034 // Make the path absolute, if necessary
1035 let local_crate_source_file = local_crate_source_file.map(|path|
1036 if path.is_absolute() {
1039 os::getcwd().join(path.clone())
1044 targ_cfg: target_cfg,
1046 cstore: CStore::new(token::get_ident_interner()),
1048 // For a library crate, this is always none
1049 entry_fn: RefCell::new(None),
1050 entry_type: Cell::new(None),
1051 macro_registrar_fn: RefCell::new(None),
1052 default_sysroot: default_sysroot,
1053 building_library: Cell::new(false),
1054 local_crate_source_file: local_crate_source_file,
1055 working_dir: os::getcwd(),
1056 lints: RefCell::new(NodeMap::new()),
1057 node_id: Cell::new(1),
1058 crate_types: RefCell::new(Vec::new()),
1059 features: front::feature_gate::Features::new(),
1060 recursion_limit: Cell::new(64),
1064 pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
1066 &"normal" => PpmNormal,
1067 &"expanded" => PpmExpanded,
1068 &"typed" => PpmTyped,
1069 &"expanded,identified" => PpmExpandedIdentified,
1070 &"identified" => PpmIdentified,
1072 sess.fatal("argument to `pretty` must be one of `normal`, \
1073 `expanded`, `typed`, `identified`, \
1074 or `expanded,identified`");
1079 // rustc command line options
1080 pub fn optgroups() -> Vec<getopts::OptGroup> {
1082 optflag("h", "help", "Display this message"),
1083 optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
1084 optmulti("L", "", "Add a directory to the library search path", "PATH"),
1085 optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit",
1086 "[bin|lib|rlib|dylib|staticlib]"),
1087 optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
1088 "[asm|bc|ir|obj|link]"),
1089 optflag("", "crate-id", "Output the crate id and exit"),
1090 optflag("", "crate-name", "Output the crate name and exit"),
1091 optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
1092 continued and exit"),
1093 optflag("", "ls", "List the symbols defined by a library crate"),
1094 optflag("g", "", "Equivalent to --debuginfo=2"),
1095 optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
1097 1 = line-tables only (for stacktraces and breakpoints),
1098 2 = full debug info with variable and type information (same as -g)", "LEVEL"),
1099 optflag("", "no-trans", "Run all passes except translation; no output"),
1100 optflag("", "no-analysis", "Parse and expand the output, but run no analysis or produce output"),
1101 optflag("O", "", "Equivalent to --opt-level=2"),
1102 optopt("o", "", "Write output to <filename>", "FILENAME"),
1103 optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
1104 optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
1105 optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
1106 optflagopt("", "pretty",
1107 "Pretty-print the input instead of compiling;
1108 valid types are: normal (un-annotated source),
1109 expanded (crates expanded),
1110 typed (crates expanded, with type annotations),
1111 or identified (fully parenthesized,
1112 AST nodes and blocks with IDs)", "TYPE"),
1113 optflagopt("", "dep-info", "Output dependency info to <filename> after compiling", "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 out_directory: Path,
1131 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"], 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", ~"--cfg=test"],
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());