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;
42 use getopts::{optopt, optmulti, optflag, optflagopt};
47 use syntax::attr::{AttrMetaMethods};
49 use syntax::crateid::CrateId;
50 use syntax::diagnostic;
51 use syntax::diagnostic::Emitter;
52 use syntax::ext::base::CrateLoader;
54 use syntax::parse::token::InternedString;
55 use syntax::parse::token;
56 use syntax::print::{pp, pprust};
68 * The name used for source code that doesn't originate in a file
69 * (e.g. source from stdin or a string)
71 pub fn anon_src() -> ~str {
75 pub fn source_name(input: &Input) -> ~str {
77 // FIXME (#9639): This needs to handle non-utf8 paths
78 FileInput(ref ifile) => ifile.as_str().unwrap().to_str(),
79 StrInput(_) => anon_src()
83 pub fn default_configuration(sess: &Session) ->
85 let tos = match sess.targ_cfg.os {
86 abi::OsWin32 => InternedString::new("win32"),
87 abi::OsMacos => InternedString::new("macos"),
88 abi::OsLinux => InternedString::new("linux"),
89 abi::OsAndroid => InternedString::new("android"),
90 abi::OsFreebsd => InternedString::new("freebsd"),
93 // ARM is bi-endian, however using NDK seems to default
94 // to little-endian unless a flag is provided.
95 let (end,arch,wordsz) = match sess.targ_cfg.arch {
96 abi::X86 => ("little", "x86", "32"),
97 abi::X86_64 => ("little", "x86_64", "64"),
98 abi::Arm => ("little", "arm", "32"),
99 abi::Mips => ("big", "mips", "32")
102 let fam = match sess.targ_cfg.os {
103 abi::OsWin32 => InternedString::new("windows"),
104 _ => InternedString::new("unix")
107 let mk = attr::mk_name_value_item_str;
108 return vec!(// Target bindings.
109 attr::mk_word_item(fam.clone()),
110 mk(InternedString::new("target_os"), tos),
111 mk(InternedString::new("target_family"), fam),
112 mk(InternedString::new("target_arch"), InternedString::new(arch)),
113 mk(InternedString::new("target_endian"), InternedString::new(end)),
114 mk(InternedString::new("target_word_size"),
115 InternedString::new(wordsz))
119 pub fn append_configuration(cfg: &mut ast::CrateConfig,
120 name: InternedString) {
121 if !cfg.iter().any(|mi| mi.name() == name) {
122 cfg.push(attr::mk_word_item(name))
126 pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
127 // Combine the configuration requested by the session (command line) with
128 // some default and generated configuration items
129 let default_cfg = default_configuration(sess);
130 let mut user_cfg = sess.opts.cfg.clone();
131 // If the user wants a test runner, then add the test cfg
133 append_configuration(&mut user_cfg, InternedString::new("test"))
135 // If the user requested GC, then add the GC cfg
136 append_configuration(&mut user_cfg, if sess.opts.gc {
137 InternedString::new("gc")
139 InternedString::new("nogc")
141 return vec_ng::append(user_cfg.move_iter().collect(),
142 default_cfg.as_slice());
145 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
146 fn parse_cfgspecs(cfgspecs: Vec<~str> )
147 -> ast::CrateConfig {
148 cfgspecs.move_iter().map(|s| {
149 parse::parse_meta_from_source_str("cfgspec".to_str(),
152 &parse::new_parse_sess())
153 }).collect::<ast::CrateConfig>()
157 /// Load source from file
159 /// The string is the source
164 fn filestem(&self) -> ~str {
166 FileInput(ref ifile) => ifile.filestem_str().unwrap().to_str(),
167 StrInput(_) => ~"rust_out",
172 pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
174 let krate = time(sess.time_passes(), "parsing", (), |_| {
176 FileInput(ref file) => {
177 parse::parse_crate_from_file(&(*file), cfg.clone(), &sess.parse_sess)
179 StrInput(ref src) => {
180 parse::parse_crate_from_source_str(anon_src(),
188 if sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0 {
189 let mut stdout = io::BufferedWriter::new(io::stdout());
190 let mut json = json::PrettyEncoder::new(&mut stdout);
191 krate.encode(&mut json);
194 if sess.show_span() {
195 front::show_span::run(sess, &krate);
201 // For continuing compilation after a parsed crate has been
204 /// Run the "early phases" of the compiler: initial `cfg` processing,
205 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
206 /// harness if one is to be provided and injection of a dependency on the
207 /// standard library and prelude.
208 pub fn phase_2_configure_and_expand(sess: &Session,
209 loader: &mut CrateLoader,
210 mut krate: ast::Crate,
212 -> (ast::Crate, syntax::ast_map::Map) {
213 let time_passes = sess.time_passes();
215 sess.building_library.set(session::building_library(&sess.opts, &krate));
216 sess.crate_types.set(session::collect_crate_types(sess,
220 time(time_passes, "gated feature checking", (), |_|
221 front::feature_gate::check_crate(sess, &krate));
223 krate = time(time_passes, "crate injection", krate, |krate|
224 front::std_inject::maybe_inject_crates_ref(sess, krate));
226 // strip before expansion to allow macros to depend on
227 // configuration variables e.g/ in
229 // #[macro_escape] #[cfg(foo)]
230 // mod bar { macro_rules! baz!(() => {{}}) }
232 // baz! should not use this definition unless foo is enabled.
234 krate = time(time_passes, "configuration 1", krate, |krate|
235 front::config::strip_unconfigured_items(krate));
237 krate = time(time_passes, "expansion", krate, |krate| {
238 let cfg = syntax::ext::expand::ExpansionConfig {
240 deriving_hash_type_parameter: sess.features.default_type_params.get(),
241 crate_id: crate_id.clone(),
243 syntax::ext::expand::expand_crate(&sess.parse_sess,
247 // dump the syntax-time crates
250 // strip again, in case expansion added anything with a #[cfg].
251 krate = time(time_passes, "configuration 2", krate, |krate|
252 front::config::strip_unconfigured_items(krate));
254 krate = time(time_passes, "maybe building test harness", krate, |krate|
255 front::test::modify_for_testing(sess, krate));
257 krate = time(time_passes, "prelude injection", krate, |krate|
258 front::std_inject::maybe_inject_prelude(sess, krate));
260 let (krate, map) = time(time_passes, "assinging node ids and indexing ast", krate, |krate|
261 front::assign_node_ids_and_map::assign_node_ids_and_map(sess, krate));
263 if sess.opts.debugging_opts & session::AST_JSON != 0 {
264 let mut stdout = io::BufferedWriter::new(io::stdout());
265 let mut json = json::PrettyEncoder::new(&mut stdout);
266 krate.encode(&mut json);
272 pub struct CrateAnalysis {
273 exp_map2: middle::resolve::ExportMap2,
274 exported_items: middle::privacy::ExportedItems,
275 public_items: middle::privacy::PublicItems,
277 maps: astencode::Maps,
281 /// Run the resolution, typechecking, region checking and other
282 /// miscellaneous analysis passes on the crate. Return various
283 /// structures carrying the results of the analysis.
284 pub fn phase_3_run_analysis_passes(sess: Session,
286 ast_map: syntax::ast_map::Map) -> CrateAnalysis {
288 let time_passes = sess.time_passes();
290 time(time_passes, "external crate/lib resolution", (), |_|
291 creader::read_crates(&sess, krate,
292 session::sess_os_to_meta_os(sess.targ_cfg.os),
293 token::get_ident_interner()));
295 let lang_items = time(time_passes, "language item collection", (), |_|
296 middle::lang_items::collect_language_items(krate, &sess));
298 let middle::resolve::CrateMap {
301 trait_map: trait_map,
302 external_exports: external_exports,
303 last_private_map: last_private_map
305 time(time_passes, "resolution", (), |_|
306 middle::resolve::resolve_crate(&sess, lang_items, krate));
308 let named_region_map = time(time_passes, "lifetime resolution", (),
309 |_| middle::resolve_lifetime::krate(&sess, krate));
311 time(time_passes, "looking for entry point", (),
312 |_| middle::entry::find_entry_point(&sess, krate, &ast_map));
314 sess.macro_registrar_fn.with_mut(|r| *r =
315 time(time_passes, "looking for macro registrar", (), |_|
316 syntax::ext::registrar::find_macro_registrar(
317 sess.diagnostic(), krate)));
319 let freevars = time(time_passes, "freevar finding", (), |_|
320 freevars::annotate_freevars(def_map, krate));
322 let region_map = time(time_passes, "region resolution", (), |_|
323 middle::region::resolve_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 let (method_map, vtable_map) = 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, def_map, method_map, &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, &method_map, &exp_map2,
347 time(time_passes, "effect checking", (), |_|
348 middle::effect::check_crate(&ty_cx, method_map, krate));
350 time(time_passes, "loop checking", (), |_|
351 middle::check_loop::check_crate(&ty_cx, krate));
353 let middle::moves::MoveMaps {moves_map, moved_variables_set,
355 time(time_passes, "compute moves", (), |_|
356 middle::moves::compute_moves(&ty_cx, method_map, krate));
358 time(time_passes, "match checking", (), |_|
359 middle::check_match::check_crate(&ty_cx, method_map,
362 time(time_passes, "liveness checking", (), |_|
363 middle::liveness::check_crate(&ty_cx, method_map,
364 &capture_map, krate));
367 time(time_passes, "borrow checking", (), |_|
368 middle::borrowck::check_crate(&ty_cx, method_map,
369 &moves_map, &moved_variables_set,
370 &capture_map, krate));
373 drop(moved_variables_set);
375 time(time_passes, "kind checking", (), |_|
376 kind::check_crate(&ty_cx, method_map, krate));
379 time(time_passes, "reachability checking", (), |_|
380 reachable::find_reachable(&ty_cx, method_map, &exported_items));
382 time(time_passes, "death checking", (), |_| {
383 middle::dead::check_crate(&ty_cx,
390 time(time_passes, "lint checking", (), |_|
391 lint::check_crate(&ty_cx, method_map, &exported_items, krate));
396 exported_items: exported_items,
397 public_items: public_items,
398 maps: astencode::Maps {
400 method_map: method_map,
401 vtable_map: vtable_map,
402 capture_map: RefCell::new(capture_map)
404 reachable: reachable_map
408 pub struct CrateTranslation {
411 metadata_module: ModuleRef,
414 reachable: Vec<~str> ,
417 /// Run the translation phase to LLVM, after which the AST and analysis can
419 pub fn phase_4_translate_to_llvm(krate: ast::Crate,
420 analysis: CrateAnalysis,
421 outputs: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
422 // Option dance to work around the lack of stack once closures.
423 let time_passes = analysis.ty_cx.sess.time_passes();
424 let mut analysis = Some(analysis);
425 time(time_passes, "translation", krate, |krate|
426 trans::base::trans_crate(krate, analysis.take_unwrap(), outputs))
429 /// Run LLVM itself, producing a bitcode file, assembly file or object file
430 /// as a side effect.
431 pub fn phase_5_run_llvm_passes(sess: &Session,
432 trans: &CrateTranslation,
433 outputs: &OutputFilenames) {
434 if sess.opts.cg.no_integrated_as {
435 let output_type = link::OutputTypeAssembly;
437 time(sess.time_passes(), "LLVM passes", (), |_|
438 link::write::run_passes(sess, trans, [output_type], outputs));
440 link::write::run_assembler(sess, outputs);
442 // Remove assembly source, unless --save-temps was specified
443 if !sess.opts.cg.save_temps {
444 fs::unlink(&outputs.temp_path(link::OutputTypeAssembly)).unwrap();
447 time(sess.time_passes(), "LLVM passes", (), |_|
448 link::write::run_passes(sess,
450 sess.opts.output_types.as_slice(),
455 /// Run the linker on any artifacts that resulted from the LLVM run.
456 /// This should produce either a finished executable or library.
457 pub fn phase_6_link_output(sess: &Session,
458 trans: &CrateTranslation,
459 outputs: &OutputFilenames) {
460 time(sess.time_passes(), "linking", (), |_|
461 link::link_binary(sess,
464 &trans.link.crateid));
467 pub fn stop_after_phase_3(sess: &Session) -> bool {
468 if sess.opts.no_trans {
469 debug!("invoked with --no-trans, returning early from compile_input");
475 pub fn stop_after_phase_1(sess: &Session) -> bool {
476 if sess.opts.parse_only {
477 debug!("invoked with --parse-only, returning early from compile_input");
480 if sess.show_span() {
483 return sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0;
486 pub fn stop_after_phase_2(sess: &Session) -> bool {
487 if sess.opts.no_analysis {
488 debug!("invoked with --no-analysis, returning early from compile_input");
491 return sess.opts.debugging_opts & session::AST_JSON != 0;
494 pub fn stop_after_phase_5(sess: &Session) -> bool {
495 if !sess.opts.output_types.iter().any(|&i| i == link::OutputTypeExe) {
496 debug!("not building executable, returning early from compile_input");
502 fn write_out_deps(sess: &Session,
504 outputs: &OutputFilenames,
505 krate: &ast::Crate) -> io::IoResult<()> {
506 let id = link::find_crate_id(krate.attrs.as_slice(), outputs.out_filestem);
508 let mut out_filenames = Vec::new();
509 for output_type in sess.opts.output_types.iter() {
510 let file = outputs.path(*output_type);
512 link::OutputTypeExe => {
513 let crate_types = sess.crate_types.borrow();
514 for output in crate_types.get().iter() {
515 let p = link::filename_for_input(sess, *output, &id, &file);
516 out_filenames.push(p);
519 _ => { out_filenames.push(file); }
523 // Write out dependency rules to the dep-info file if requested with
525 let deps_filename = match sess.opts.write_dependency_info {
526 // Use filename from --dep-file argument if given
527 (true, Some(ref filename)) => filename.clone(),
528 // Use default filename: crate source filename with extension replaced
530 (true, None) => match *input {
531 FileInput(..) => outputs.with_extension("d"),
533 sess.warn("can not write --dep-info without a filename \
534 when compiling stdin.");
541 // Build a list of files used to compile the output and
542 // write Makefile-compatible dependency rules
543 let files: Vec<~str> = sess.codemap().files.borrow().get()
544 .iter().filter_map(|fmap| {
545 if fmap.deref().is_real_file() {
546 Some(fmap.deref().name.clone())
551 let mut file = try!(io::File::create(&deps_filename));
552 for path in out_filenames.iter() {
553 try!(write!(&mut file as &mut Writer,
554 "{}: {}\n\n", path.display(), files.connect(" ")));
559 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
560 outdir: &Option<Path>, output: &Option<Path>) {
561 // We need nested scopes here, because the intermediate results can keep
562 // large chunks of memory alive and we want to free them as soon as
563 // possible to keep the peak memory usage low
564 let (outputs, trans, sess) = {
565 let (outputs, expanded_crate, ast_map) = {
566 let krate = phase_1_parse_input(&sess, cfg, input);
567 if stop_after_phase_1(&sess) { return; }
568 let outputs = build_output_filenames(input,
571 krate.attrs.as_slice(),
573 let loader = &mut Loader::new(&sess);
574 let id = link::find_crate_id(krate.attrs.as_slice(),
575 outputs.out_filestem);
576 let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
578 (outputs, expanded_crate, ast_map)
580 write_out_deps(&sess, input, &outputs, &expanded_crate).unwrap();
582 if stop_after_phase_2(&sess) { return; }
584 let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
585 if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
586 let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
588 (outputs, trans, tcx.sess)
590 phase_5_run_llvm_passes(&sess, &trans, &outputs);
591 if stop_after_phase_5(&sess) { return; }
592 phase_6_link_output(&sess, &trans, &outputs);
595 struct IdentifiedAnnotation;
597 impl pprust::PpAnn for IdentifiedAnnotation {
599 s: &mut pprust::State<IdentifiedAnnotation>,
600 node: pprust::AnnNode) -> io::IoResult<()> {
602 pprust::NodeExpr(_) => s.popen(),
607 s: &mut pprust::State<IdentifiedAnnotation>,
608 node: pprust::AnnNode) -> io::IoResult<()> {
610 pprust::NodeItem(item) => {
611 try!(pp::space(&mut s.s));
612 s.synth_comment(item.id.to_str())
614 pprust::NodeBlock(blk) => {
615 try!(pp::space(&mut s.s));
616 s.synth_comment(~"block " + blk.id.to_str())
618 pprust::NodeExpr(expr) => {
619 try!(pp::space(&mut s.s));
620 try!(s.synth_comment(expr.id.to_str()));
623 pprust::NodePat(pat) => {
624 try!(pp::space(&mut s.s));
625 s.synth_comment(~"pat " + pat.id.to_str())
631 struct TypedAnnotation {
632 analysis: CrateAnalysis,
635 impl pprust::PpAnn for TypedAnnotation {
637 s: &mut pprust::State<TypedAnnotation>,
638 node: pprust::AnnNode) -> io::IoResult<()> {
640 pprust::NodeExpr(_) => s.popen(),
645 s: &mut pprust::State<TypedAnnotation>,
646 node: pprust::AnnNode) -> io::IoResult<()> {
647 let tcx = &self.analysis.ty_cx;
649 pprust::NodeExpr(expr) => {
650 try!(pp::space(&mut s.s));
651 try!(pp::word(&mut s.s, "as"));
652 try!(pp::space(&mut s.s));
653 try!(pp::word(&mut s.s,
654 ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr))));
662 pub fn pretty_print_input(sess: Session,
663 cfg: ast::CrateConfig,
666 let krate = phase_1_parse_input(&sess, cfg, input);
667 let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem());
669 let (krate, ast_map, is_expanded) = match ppm {
670 PpmExpanded | PpmExpandedIdentified | PpmTyped => {
671 let loader = &mut Loader::new(&sess);
672 let (krate, ast_map) = phase_2_configure_and_expand(&sess, loader,
674 (krate, Some(ast_map), true)
676 _ => (krate, None, false)
679 let src_name = source_name(input);
680 let src = sess.codemap().get_filemap(src_name).deref().src.as_bytes().to_owned();
681 let mut rdr = MemReader::new(src);
684 PpmIdentified | PpmExpandedIdentified => {
685 pprust::print_crate(sess.codemap(),
691 &IdentifiedAnnotation,
695 let ast_map = ast_map.expect("--pretty=typed missing ast_map");
696 let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map);
697 let annotation = TypedAnnotation {
700 pprust::print_crate(annotation.analysis.ty_cx.sess.codemap(),
701 annotation.analysis.ty_cx.sess.diagnostic(),
710 pprust::print_crate(sess.codemap(),
723 pub fn get_os(triple: &str) -> Option<abi::Os> {
724 for &(name, os) in os_names.iter() {
725 if triple.contains(name) { return Some(os) }
729 static os_names : &'static [(&'static str, abi::Os)] = &'static [
730 ("mingw32", abi::OsWin32),
731 ("win32", abi::OsWin32),
732 ("darwin", abi::OsMacos),
733 ("android", abi::OsAndroid),
734 ("linux", abi::OsLinux),
735 ("freebsd", abi::OsFreebsd)];
737 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
738 for &(arch, abi) in architecture_abis.iter() {
739 if triple.contains(arch) { return Some(abi) }
743 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
750 ("x86_64", abi::X86_64),
753 ("xscale", abi::Arm),
756 ("mips", abi::Mips)];
758 pub fn build_target_config(sopts: &session::Options) -> session::Config {
759 let os = match get_os(sopts.target_triple) {
761 None => early_error("unknown operating system")
763 let arch = match get_arch(sopts.target_triple) {
765 None => early_error("unknown architecture: " + sopts.target_triple)
767 let (int_type, uint_type) = match arch {
768 abi::X86 => (ast::TyI32, ast::TyU32),
769 abi::X86_64 => (ast::TyI64, ast::TyU64),
770 abi::Arm => (ast::TyI32, ast::TyU32),
771 abi::Mips => (ast::TyI32, ast::TyU32)
773 let target_triple = sopts.target_triple.clone();
774 let target_strs = match arch {
775 abi::X86 => x86::get_target_strs(target_triple, os),
776 abi::X86_64 => x86_64::get_target_strs(target_triple, os),
777 abi::Arm => arm::get_target_strs(target_triple, os),
778 abi::Mips => mips::get_target_strs(target_triple, os)
783 target_strs: target_strs,
785 uint_type: uint_type,
789 pub fn host_triple() -> ~str {
790 // Get the host triple out of the build environment. This ensures that our
791 // idea of the host triple is the same as for the set of libraries we've
792 // actually built. We can't just take LLVM's host triple because they
793 // normalize all ix86 architectures to i386.
795 // Instead of grabbing the host triple (for the current host), we grab (at
796 // compile time) the target triple that this rustc is built with and
797 // calling that (at runtime) the host triple.
798 (env!("CFG_COMPILER")).to_owned()
801 pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
802 let mut crate_types: Vec<CrateType> = Vec::new();
803 let unparsed_crate_types = matches.opt_strs("crate-type");
804 for unparsed_crate_type in unparsed_crate_types.iter() {
805 for part in unparsed_crate_type.split(',') {
806 let new_part = match part {
807 "lib" => session::default_lib_output(),
808 "rlib" => session::CrateTypeRlib,
809 "staticlib" => session::CrateTypeStaticlib,
810 "dylib" => session::CrateTypeDylib,
811 "bin" => session::CrateTypeExecutable,
812 _ => early_error(format!("unknown crate type: `{}`", part))
814 crate_types.push(new_part)
818 let parse_only = matches.opt_present("parse-only");
819 let no_trans = matches.opt_present("no-trans");
820 let no_analysis = matches.opt_present("no-analysis");
822 let lint_levels = [lint::allow, lint::warn,
823 lint::deny, lint::forbid];
824 let mut lint_opts = Vec::new();
825 let lint_dict = lint::get_lint_dict();
826 for level in lint_levels.iter() {
827 let level_name = lint::level_to_str(*level);
829 let level_short = level_name.slice_chars(0, 1);
830 let level_short = level_short.to_ascii().to_upper().into_str();
831 let flags = vec_ng::append(matches.opt_strs(level_short)
834 matches.opt_strs(level_name));
835 for lint_name in flags.iter() {
836 let lint_name = lint_name.replace("-", "_");
837 match lint_dict.find_equiv(&lint_name) {
839 early_error(format!("unknown {} flag: {}",
840 level_name, lint_name));
843 lint_opts.push((lint.lint, *level));
849 let mut debugging_opts = 0;
850 let debug_flags = matches.opt_strs("Z");
851 let debug_map = session::debugging_opts_map();
852 for debug_flag in debug_flags.iter() {
853 let mut this_bit = 0;
854 for tuple in debug_map.iter() {
855 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
856 if *name == *debug_flag { this_bit = bit; break; }
859 early_error(format!("unknown debug flag: {}", *debug_flag))
861 debugging_opts |= this_bit;
864 if debugging_opts & session::DEBUG_LLVM != 0 {
865 unsafe { llvm::LLVMSetDebug(1); }
868 let mut output_types = Vec::new();
869 if !parse_only && !no_trans {
870 let unparsed_output_types = matches.opt_strs("emit");
871 for unparsed_output_type in unparsed_output_types.iter() {
872 for part in unparsed_output_type.split(',') {
873 let output_type = match part.as_slice() {
874 "asm" => link::OutputTypeAssembly,
875 "ir" => link::OutputTypeLlvmAssembly,
876 "bc" => link::OutputTypeBitcode,
877 "obj" => link::OutputTypeObject,
878 "link" => link::OutputTypeExe,
879 _ => early_error(format!("unknown emission type: `{}`", part))
881 output_types.push(output_type)
885 output_types.as_mut_slice().sort();
886 output_types.dedup();
887 if output_types.len() == 0 {
888 output_types.push(link::OutputTypeExe);
891 let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
892 let target = matches.opt_str("target").unwrap_or(host_triple());
894 if (debugging_opts & session::NO_OPT) != 0 {
896 } else if matches.opt_present("O") {
897 if matches.opt_present("opt-level") {
898 early_error("-O and --opt-level both provided");
901 } else if matches.opt_present("opt-level") {
902 match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
906 Some("2") => Default,
907 Some("3") => Aggressive,
909 early_error(format!("optimization level needs to be between 0-3 \
910 (instead was `{}`)", arg));
917 let gc = debugging_opts & session::GC != 0;
918 let debuginfo = if matches.opt_present("g") {
919 if matches.opt_present("debuginfo") {
920 early_error("-g and --debuginfo both provided");
923 } else if matches.opt_present("debuginfo") {
924 match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
925 Some("0") => NoDebugInfo,
926 Some("1") => LimitedDebugInfo,
928 Some("2") => FullDebugInfo,
930 early_error(format!("optimization level needs to be between 0-3 \
931 (instead was `{}`)", arg));
938 let addl_lib_search_paths = matches.opt_strs("L").map(|s| {
939 Path::new(s.as_slice())
940 }).move_iter().collect();
942 let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
943 let test = matches.opt_present("test");
944 let write_dependency_info = (matches.opt_present("dep-info"),
945 matches.opt_str("dep-info").map(|p| Path::new(p)));
947 let print_metas = (matches.opt_present("crate-id"),
948 matches.opt_present("crate-name"),
949 matches.opt_present("crate-file-name"));
950 let cg = build_codegen_options(matches);
953 crate_types: crate_types,
956 debuginfo: debuginfo,
957 lint_opts: lint_opts,
958 output_types: output_types,
959 addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
960 maybe_sysroot: sysroot_opt,
961 target_triple: target,
964 parse_only: parse_only,
966 no_analysis: no_analysis,
967 debugging_opts: debugging_opts,
968 write_dependency_info: write_dependency_info,
969 print_metas: print_metas,
974 pub fn build_codegen_options(matches: &getopts::Matches)
975 -> session::CodegenOptions
977 let mut cg = session::basic_codegen_options();
978 for option in matches.opt_strs("C").move_iter() {
979 let mut iter = option.splitn('=', 1);
980 let key = iter.next().unwrap();
981 let value = iter.next();
982 let option_to_lookup = key.replace("-", "_");
983 let mut found = false;
984 for &(candidate, setter, _) in session::CG_OPTIONS.iter() {
985 if option_to_lookup.as_slice() != candidate { continue }
986 if !setter(&mut cg, value) {
988 Some(..) => early_error(format!("codegen option `{}` takes \
990 None => early_error(format!("codegen option `{0}` requires \
991 a value (-C {0}=<value>)",
999 early_error(format!("unknown codegen option: `{}`", key));
1005 pub fn build_session(sopts: session::Options,
1006 local_crate_source_file: Option<Path>)
1008 let codemap = codemap::CodeMap::new();
1009 let diagnostic_handler =
1010 diagnostic::default_handler();
1011 let span_diagnostic_handler =
1012 diagnostic::mk_span_handler(diagnostic_handler, codemap);
1014 build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
1017 pub fn build_session_(sopts: session::Options,
1018 local_crate_source_file: Option<Path>,
1019 span_diagnostic: diagnostic::SpanHandler)
1021 let target_cfg = build_target_config(&sopts);
1022 let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
1023 let default_sysroot = match sopts.maybe_sysroot {
1025 None => Some(filesearch::get_or_default_sysroot())
1028 // Make the path absolute, if necessary
1029 let local_crate_source_file = local_crate_source_file.map(|path|
1030 if path.is_absolute() {
1033 os::getcwd().join(path.clone())
1038 targ_cfg: target_cfg,
1040 cstore: CStore::new(token::get_ident_interner()),
1042 // For a library crate, this is always none
1043 entry_fn: RefCell::new(None),
1044 entry_type: Cell::new(None),
1045 macro_registrar_fn: RefCell::new(None),
1046 default_sysroot: default_sysroot,
1047 building_library: Cell::new(false),
1048 local_crate_source_file: local_crate_source_file,
1049 working_dir: os::getcwd(),
1050 lints: RefCell::new(NodeMap::new()),
1051 node_id: Cell::new(1),
1052 crate_types: RefCell::new(Vec::new()),
1053 features: front::feature_gate::Features::new(),
1054 recursion_limit: Cell::new(64),
1058 pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
1060 &"normal" => PpmNormal,
1061 &"expanded" => PpmExpanded,
1062 &"typed" => PpmTyped,
1063 &"expanded,identified" => PpmExpandedIdentified,
1064 &"identified" => PpmIdentified,
1066 sess.fatal("argument to `pretty` must be one of `normal`, \
1067 `expanded`, `typed`, `identified`, \
1068 or `expanded,identified`");
1073 // rustc command line options
1074 pub fn optgroups() -> Vec<getopts::OptGroup> {
1076 optflag("h", "help", "Display this message"),
1077 optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
1078 optmulti("L", "", "Add a directory to the library search path", "PATH"),
1079 optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit",
1080 "[bin|lib|rlib|dylib|staticlib]"),
1081 optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
1082 "[asm|bc|ir|obj|link]"),
1083 optflag("", "crate-id", "Output the crate id and exit"),
1084 optflag("", "crate-name", "Output the crate name and exit"),
1085 optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
1086 continued and exit"),
1087 optflag("", "ls", "List the symbols defined by a library crate"),
1088 optflag("g", "", "Equivalent to --debuginfo=2"),
1089 optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
1091 1 = line-tables only (for stacktraces and breakpoints),
1092 2 = full debug info with variable and type information (same as -g)", "LEVEL"),
1093 optflag("", "no-trans", "Run all passes except translation; no output"),
1094 optflag("", "no-analysis", "Parse and expand the output, but run no analysis or produce output"),
1095 optflag("O", "", "Equivalent to --opt-level=2"),
1096 optopt("o", "", "Write output to <filename>", "FILENAME"),
1097 optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
1098 optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
1099 optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
1100 optflagopt("", "pretty",
1101 "Pretty-print the input instead of compiling;
1102 valid types are: normal (un-annotated source),
1103 expanded (crates expanded),
1104 typed (crates expanded, with type annotations),
1105 or identified (fully parenthesized,
1106 AST nodes and blocks with IDs)", "TYPE"),
1107 optflagopt("", "dep-info", "Output dependency info to <filename> after compiling", "FILENAME"),
1108 optopt("", "sysroot", "Override the system root", "PATH"),
1109 optflag("", "test", "Build a test harness"),
1110 optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
1111 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
1112 for details)", "TRIPLE"),
1113 optmulti("W", "warn", "Set lint warnings", "OPT"),
1114 optmulti("A", "allow", "Set lint allowed", "OPT"),
1115 optmulti("D", "deny", "Set lint denied", "OPT"),
1116 optmulti("F", "forbid", "Set lint forbidden", "OPT"),
1117 optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1118 optmulti("Z", "", "Set internal debugging options", "FLAG"),
1119 optflag( "v", "version", "Print version info and exit"))
1122 pub struct OutputFilenames {
1123 out_directory: Path,
1125 single_output_file: Option<Path>,
1128 impl OutputFilenames {
1129 pub fn path(&self, flavor: link::OutputType) -> Path {
1130 match self.single_output_file {
1131 Some(ref path) => return path.clone(),
1134 self.temp_path(flavor)
1137 pub fn temp_path(&self, flavor: link::OutputType) -> Path {
1138 let base = self.out_directory.join(self.out_filestem.as_slice());
1140 link::OutputTypeBitcode => base.with_extension("bc"),
1141 link::OutputTypeAssembly => base.with_extension("s"),
1142 link::OutputTypeLlvmAssembly => base.with_extension("ll"),
1143 link::OutputTypeObject => base.with_extension("o"),
1144 link::OutputTypeExe => base,
1148 pub fn with_extension(&self, extension: &str) -> Path {
1149 let stem = self.out_filestem.as_slice();
1150 self.out_directory.join(stem).with_extension(extension)
1154 pub fn build_output_filenames(input: &Input,
1155 odir: &Option<Path>,
1156 ofile: &Option<Path>,
1157 attrs: &[ast::Attribute],
1159 -> OutputFilenames {
1162 // "-" as input file will cause the parser to read from stdin so we
1163 // have to make up a name
1164 // We want to toss everything after the final '.'
1165 let dirpath = match *odir {
1166 Some(ref d) => d.clone(),
1167 None => Path::new(".")
1170 let mut stem = input.filestem();
1172 // If a crateid is present, we use it as the link name
1173 let crateid = attr::find_crateid(attrs);
1176 Some(crateid) => stem = crateid.name.to_str(),
1179 out_directory: dirpath,
1181 single_output_file: None,
1185 Some(ref out_file) => {
1186 let ofile = if sess.opts.output_types.len() > 1 {
1187 sess.warn("ignoring specified output filename because multiple \
1188 outputs were requested");
1191 Some(out_file.clone())
1194 sess.warn("ignoring --out-dir flag due to -o flag.");
1197 out_directory: out_file.dir_path(),
1198 out_filestem: out_file.filestem_str().unwrap().to_str(),
1199 single_output_file: ofile,
1205 pub fn early_error(msg: &str) -> ! {
1206 let mut emitter = diagnostic::EmitterWriter::stderr();
1207 emitter.emit(None, msg, diagnostic::Fatal);
1208 fail!(diagnostic::FatalError);
1211 pub fn list_metadata(sess: &Session, path: &Path,
1212 out: &mut io::Writer) -> io::IoResult<()> {
1213 metadata::loader::list_file_metadata(
1214 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out)
1220 use driver::driver::{build_configuration, build_session};
1221 use driver::driver::{build_session_options, optgroups};
1223 use getopts::getopts;
1225 use syntax::attr::AttrMetaMethods;
1227 // When the user supplies --test we should implicitly supply --cfg test
1229 fn test_switch_implies_cfg_test() {
1231 &match getopts([~"--test"], optgroups().as_slice()) {
1233 Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
1235 let sessopts = build_session_options(matches);
1236 let sess = build_session(sessopts, None);
1237 let cfg = build_configuration(&sess);
1238 assert!((attr::contains_name(cfg.as_slice(), "test")));
1241 // When the user supplies --test and --cfg test, don't implicitly add
1242 // another --cfg test
1244 fn test_switch_implies_cfg_test_unless_cfg_test() {
1246 &match getopts([~"--test", ~"--cfg=test"],
1247 optgroups().as_slice()) {
1250 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
1254 let sessopts = build_session_options(matches);
1255 let sess = build_session(sessopts, None);
1256 let cfg = build_configuration(&sess);
1257 let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
1258 assert!(test_items.next().is_some());
1259 assert!(test_items.next().is_none());