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};
15 use driver::session::{Session, Session_, No, Less, Default};
19 use lib::llvm::{ContextRef, ModuleRef};
20 use metadata::common::LinkMeta;
21 use metadata::{creader, cstore, filesearch};
23 use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
25 use util::common::time;
28 use std::hashmap::{HashMap,HashSet};
33 use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
34 use extra::getopts::{opt_present};
39 use syntax::attr::{AttrMetaMethods};
41 use syntax::diagnostic;
43 use syntax::parse::token;
44 use syntax::print::{pp, pprust};
52 ppm_expanded_identified
56 * The name used for source code that doesn't originate in a file
57 * (e.g. source from stdin or a string)
59 pub fn anon_src() -> @str { @"<anon>" }
61 pub fn source_name(input: &input) -> @str {
63 file_input(ref ifile) => ifile.to_str().to_managed(),
64 str_input(_) => anon_src()
68 pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
70 let (libc, tos) = match sess.targ_cfg.os {
71 session::os_win32 => (@"msvcrt.dll", @"win32"),
72 session::os_macos => (@"libc.dylib", @"macos"),
73 session::os_linux => (@"libc.so.6", @"linux"),
74 session::os_android => (@"libc.so", @"android"),
75 session::os_freebsd => (@"libc.so.7", @"freebsd")
78 // ARM is bi-endian, however using NDK seems to default
79 // to little-endian unless a flag is provided.
80 let (end,arch,wordsz) = match sess.targ_cfg.arch {
81 abi::X86 => (@"little", @"x86", @"32"),
82 abi::X86_64 => (@"little", @"x86_64", @"64"),
83 abi::Arm => (@"little", @"arm", @"32"),
84 abi::Mips => (@"big", @"mips", @"32")
87 let mk = attr::mk_name_value_item_str;
88 return ~[ // Target bindings.
89 attr::mk_word_item(os::FAMILY.to_managed()),
90 mk(@"target_os", tos),
91 mk(@"target_family", os::FAMILY.to_managed()),
92 mk(@"target_arch", arch),
93 mk(@"target_endian", end),
94 mk(@"target_word_size", wordsz),
95 mk(@"target_libc", libc),
97 mk(@"build_compiler", argv0),
98 mk(@"build_input", source_name(input))];
101 pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
102 if !cfg.iter().any(|mi| mi.name() == name) {
103 cfg.push(attr::mk_word_item(name))
107 pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
109 // Combine the configuration requested by the session (command line) with
110 // some default and generated configuration items
111 let default_cfg = default_configuration(sess, argv0, input);
112 let mut user_cfg = sess.opts.cfg.clone();
113 // If the user wants a test runner, then add the test cfg
114 if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
115 // If the user requested GC, then add the GC cfg
116 append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
117 return vec::append(user_cfg, default_cfg);
120 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
121 fn parse_cfgspecs(cfgspecs: ~[~str],
122 demitter: diagnostic::Emitter) -> ast::CrateConfig {
123 do cfgspecs.consume_iter().transform |s| {
124 let sess = parse::new_parse_sess(Some(demitter));
125 parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
126 }.collect::<ast::CrateConfig>()
130 /// Load source from file
132 /// The string is the source
133 // FIXME (#2319): Don't really want to box the source string
137 pub fn phase_1_parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
139 time(sess.time_passes(), ~"parsing", || {
141 file_input(ref file) => {
142 parse::parse_crate_from_file(&(*file), cfg.clone(), sess.parse_sess)
145 parse::parse_crate_from_source_str(
146 anon_src(), src, cfg.clone(), sess.parse_sess)
152 // For continuing compilation after a parsed crate has been
155 /// Run the "early phases" of the compiler: initial `cfg` processing,
156 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
157 /// harness if one is to be provided and injection of a dependency on the
158 /// standard library and prelude.
159 pub fn phase_2_configure_and_expand(sess: Session,
160 cfg: ast::CrateConfig,
161 mut crate: @ast::Crate) -> @ast::Crate {
162 let time_passes = sess.time_passes();
164 *sess.building_library = session::building_library(sess.opts.crate_type,
165 crate, sess.opts.test);
168 // strip before expansion to allow macros to depend on
169 // configuration variables e.g/ in
171 // #[macro_escape] #[cfg(foo)]
172 // mod bar { macro_rules! baz!(() => {{}}) }
174 // baz! should not use this definition unless foo is enabled.
175 crate = time(time_passes, ~"std macros injection", ||
176 syntax::ext::expand::inject_std_macros(sess.parse_sess,
180 crate = time(time_passes, ~"configuration 1", ||
181 front::config::strip_unconfigured_items(crate));
183 crate = time(time_passes, ~"expansion", ||
184 syntax::ext::expand::expand_crate(sess.parse_sess, cfg.clone(),
187 // strip again, in case expansion added anything with a #[cfg].
188 crate = time(time_passes, ~"configuration 2", ||
189 front::config::strip_unconfigured_items(crate));
191 crate = time(time_passes, ~"maybe building test harness", ||
192 front::test::modify_for_testing(sess, crate));
194 crate = time(time_passes, ~"std injection", ||
195 front::std_inject::maybe_inject_libstd_ref(sess, crate));
200 pub struct CrateAnalysis {
201 exp_map2: middle::resolve::ExportMap2,
203 maps: astencode::Maps,
204 reachable: @mut HashSet<ast::NodeId>
207 /// Run the resolution, typechecking, region checking and other
208 /// miscellaneous analysis passes on the crate. Return various
209 /// structures carrying the results of the analysis.
210 pub fn phase_3_run_analysis_passes(sess: Session,
211 crate: @ast::Crate) -> CrateAnalysis {
213 let time_passes = sess.time_passes();
214 let ast_map = time(time_passes, ~"ast indexing", ||
215 syntax::ast_map::map_crate(sess.diagnostic(), crate));
217 time(time_passes, ~"external crate/lib resolution", ||
218 creader::read_crates(sess.diagnostic(), crate, sess.cstore,
220 session::sess_os_to_meta_os(sess.targ_cfg.os),
222 token::get_ident_interner()));
224 let lang_items = time(time_passes, ~"language item collection", ||
225 middle::lang_items::collect_language_items(crate, sess));
227 let middle::resolve::CrateMap {
232 time(time_passes, ~"resolution", ||
233 middle::resolve::resolve_crate(sess, lang_items, crate));
235 time(time_passes, ~"looking for entry point",
236 || middle::entry::find_entry_point(sess, crate, ast_map));
238 let freevars = time(time_passes, ~"freevar finding", ||
239 freevars::annotate_freevars(def_map, crate));
241 let region_map = time(time_passes, ~"region resolution", ||
242 middle::region::resolve_crate(sess, def_map, crate));
244 let rp_set = time(time_passes, ~"region parameterization inference", ||
245 middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
247 let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
248 region_map, rp_set, lang_items);
250 // passes are timed inside typeck
251 let (method_map, vtable_map) = typeck::check_crate(
252 ty_cx, trait_map, crate);
254 // These next two const passes can probably be merged
255 time(time_passes, ~"const marking", ||
256 middle::const_eval::process_crate(crate, ty_cx));
258 time(time_passes, ~"const checking", ||
259 middle::check_const::check_crate(sess, crate, ast_map, def_map,
262 time(time_passes, ~"privacy checking", ||
263 middle::privacy::check_crate(ty_cx, &method_map, crate));
265 time(time_passes, ~"effect checking", ||
266 middle::effect::check_crate(ty_cx, method_map, crate));
268 time(time_passes, ~"loop checking", ||
269 middle::check_loop::check_crate(ty_cx, crate));
271 let middle::moves::MoveMaps {moves_map, moved_variables_set,
273 time(time_passes, ~"compute moves", ||
274 middle::moves::compute_moves(ty_cx, method_map, crate));
276 time(time_passes, ~"match checking", ||
277 middle::check_match::check_crate(ty_cx, method_map,
280 time(time_passes, ~"liveness checking", ||
281 middle::liveness::check_crate(ty_cx, method_map,
282 capture_map, crate));
284 let (root_map, write_guard_map) =
285 time(time_passes, ~"borrow checking", ||
286 middle::borrowck::check_crate(ty_cx, method_map,
287 moves_map, moved_variables_set,
288 capture_map, crate));
290 time(time_passes, ~"kind checking", ||
291 kind::check_crate(ty_cx, method_map, crate));
294 time(time_passes, ~"reachability checking", ||
295 reachable::find_reachable(ty_cx, method_map, crate));
297 time(time_passes, ~"lint checking", ||
298 lint::check_crate(ty_cx, crate));
303 maps: astencode::Maps {
305 method_map: method_map,
306 vtable_map: vtable_map,
307 write_guard_map: write_guard_map,
308 capture_map: capture_map
310 reachable: reachable_map
314 pub struct CrateTranslation {
320 /// Run the translation phase to LLVM, after which the AST and analysis can
322 pub fn phase_4_translate_to_llvm(sess: Session,
324 analysis: &CrateAnalysis,
325 outputs: &OutputFilenames) -> CrateTranslation {
326 time(sess.time_passes(), ~"translation", ||
327 trans::base::trans_crate(sess, crate, analysis,
328 &outputs.obj_filename))
331 /// Run LLVM itself, producing a bitcode file, assembly file or object file
332 /// as a side effect.
333 pub fn phase_5_run_llvm_passes(sess: Session,
334 trans: &CrateTranslation,
335 outputs: &OutputFilenames) {
338 if sess.targ_cfg.os == session::os_android &&
339 (sess.opts.output_type == link::output_type_object ||
340 sess.opts.output_type == link::output_type_exe) {
341 let output_type = link::output_type_assembly;
342 let obj_filename = outputs.obj_filename.with_filetype("s");
344 time(sess.time_passes(), ~"LLVM passes", ||
345 link::write::run_passes(sess,
351 link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
353 time(sess.time_passes(), ~"LLVM passes", ||
354 link::write::run_passes(sess,
357 sess.opts.output_type,
358 &outputs.obj_filename));
362 /// Run the linker on any artifacts that resulted from the LLVM run.
363 /// This should produce either a finished executable or library.
364 pub fn phase_6_link_output(sess: Session,
365 trans: &CrateTranslation,
366 outputs: &OutputFilenames) {
367 time(sess.time_passes(), ~"linking", ||
368 link::link_binary(sess,
369 &outputs.obj_filename,
370 &outputs.out_filename,
374 pub fn stop_after_phase_3(sess: Session) -> bool {
375 if sess.opts.no_trans {
376 debug!("invoked with --no-trans, returning early from compile_input");
382 pub fn stop_after_phase_1(sess: Session) -> bool {
383 if sess.opts.parse_only {
384 debug!("invoked with --parse-only, returning early from compile_input");
390 pub fn stop_after_phase_5(sess: Session) -> bool {
391 if sess.opts.output_type != link::output_type_exe {
392 debug!("not building executable, returning early from compile_input");
396 if sess.opts.is_static && *sess.building_library {
397 debug!("building static library, returning early from compile_input");
402 debug!("running JIT, returning early from compile_input");
408 #[fixed_stack_segment]
409 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
410 outdir: &Option<Path>, output: &Option<Path>) {
411 // We need nested scopes here, because the intermediate results can keep
412 // large chunks of memory alive and we want to free them as soon as
413 // possible to keep the peak memory usage low
414 let (outputs, trans) = {
415 let expanded_crate = {
416 let crate = phase_1_parse_input(sess, cfg.clone(), input);
417 if stop_after_phase_1(sess) { return; }
418 phase_2_configure_and_expand(sess, cfg, crate)
420 let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
421 if stop_after_phase_3(sess) { return; }
422 let outputs = build_output_filenames(input, outdir, output, [], sess);
423 let trans = phase_4_translate_to_llvm(sess, expanded_crate,
427 phase_5_run_llvm_passes(sess, &trans, outputs);
428 if stop_after_phase_5(sess) { return; }
429 phase_6_link_output(sess, &trans, outputs);
432 pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
435 fn ann_paren_for_expr(node: pprust::ann_node) {
437 pprust::node_expr(s, _) => pprust::popen(s),
441 fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
443 pprust::node_expr(s, expr) => {
447 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
453 fn ann_identified_post(node: pprust::ann_node) {
455 pprust::node_item(s, item) => {
457 pprust::synth_comment(s, int::to_str(item.id));
459 pprust::node_block(s, ref blk) => {
461 pprust::synth_comment(
462 s, ~"block " + int::to_str(blk.id));
464 pprust::node_expr(s, expr) => {
466 pprust::synth_comment(s, int::to_str(expr.id));
469 pprust::node_pat(s, pat) => {
471 pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
476 let crate = phase_1_parse_input(sess, cfg.clone(), input);
478 let (crate, is_expanded) = match ppm {
479 ppm_expanded | ppm_expanded_identified | ppm_typed => {
480 (phase_2_configure_and_expand(sess, cfg, crate), true)
485 let annotation = match ppm {
486 ppm_identified | ppm_expanded_identified => {
488 pre: ann_paren_for_expr,
489 post: ann_identified_post
493 let analysis = phase_3_run_analysis_passes(sess, crate);
495 pre: ann_paren_for_expr,
496 post: |a| ann_typed_post(analysis.ty_cx, a)
499 _ => pprust::no_ann()
502 let src = sess.codemap.get_filemap(source_name(input)).src;
503 do io::with_str_reader(src) |rdr| {
504 pprust::print_crate(sess.codemap, token::get_ident_interner(),
505 sess.span_diagnostic, crate,
508 annotation, is_expanded);
512 pub fn get_os(triple: &str) -> Option<session::os> {
513 for &(name, os) in os_names.iter() {
514 if triple.contains(name) { return Some(os) }
518 static os_names : &'static [(&'static str, session::os)] = &'static [
519 ("mingw32", session::os_win32),
520 ("win32", session::os_win32),
521 ("darwin", session::os_macos),
522 ("android", session::os_android),
523 ("linux", session::os_linux),
524 ("freebsd", session::os_freebsd)];
526 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
527 for &(arch, abi) in architecture_abis.iter() {
528 if triple.contains(arch) { return Some(abi) }
532 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
539 ("x86_64", abi::X86_64),
542 ("xscale", abi::Arm),
544 ("mips", abi::Mips)];
546 pub fn build_target_config(sopts: @session::options,
547 demitter: diagnostic::Emitter)
548 -> @session::config {
549 let os = match get_os(sopts.target_triple) {
551 None => early_error(demitter, ~"unknown operating system")
553 let arch = match get_arch(sopts.target_triple) {
555 None => early_error(demitter,
556 ~"unknown architecture: " + sopts.target_triple)
558 let (int_type, uint_type, float_type) = match arch {
559 abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
560 abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
561 abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
562 abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
564 let target_strs = match arch {
565 abi::X86 => x86::get_target_strs(os),
566 abi::X86_64 => x86_64::get_target_strs(os),
567 abi::Arm => arm::get_target_strs(os),
568 abi::Mips => mips::get_target_strs(os)
570 let target_cfg = @session::config {
573 target_strs: target_strs,
575 uint_type: uint_type,
576 float_type: float_type
582 pub fn host_triple() -> ~str {
583 // Get the host triple out of the build environment. This ensures that our
584 // idea of the host triple is the same as for the set of libraries we've
585 // actually built. We can't just take LLVM's host triple because they
586 // normalize all ix86 architectures to i386.
588 // Instead of grabbing the host triple (for the current host), we grab (at
589 // compile time) the target triple that this rustc is built with and
590 // calling that (at runtime) the host triple.
591 let ht = env!("CFG_COMPILER_TRIPLE");
595 fail!("rustc built without CFG_COMPILER_TRIPLE")
600 pub fn host_triple() -> ~str {
601 // Get the host triple out of the build environment. This ensures that our
602 // idea of the host triple is the same as for the set of libraries we've
603 // actually built. We can't just take LLVM's host triple because they
604 // normalize all ix86 architectures to i386.
606 // Instead of grabbing the host triple (for the current host), we grab (at
607 // compile time) the target triple that this rustc is built with and
608 // calling that (at runtime) the host triple.
609 (env!("CFG_COMPILER_TRIPLE")).to_owned()
612 pub fn build_session_options(binary: @str,
613 matches: &getopts::Matches,
614 demitter: diagnostic::Emitter)
615 -> @session::options {
616 let crate_type = if opt_present(matches, "lib") {
618 } else if opt_present(matches, "bin") {
621 session::unknown_crate
623 let parse_only = opt_present(matches, "parse-only");
624 let no_trans = opt_present(matches, "no-trans");
626 let lint_levels = [lint::allow, lint::warn,
627 lint::deny, lint::forbid];
628 let mut lint_opts = ~[];
629 let lint_dict = lint::get_lint_dict();
630 for level in lint_levels.iter() {
631 let level_name = lint::level_to_str(*level);
633 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
634 // to_ascii_consume and to_str_consume to not do a unnecessary copy.
635 let level_short = level_name.slice_chars(0, 1);
636 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
637 let flags = vec::append(getopts::opt_strs(matches, level_short),
638 getopts::opt_strs(matches, level_name));
639 for lint_name in flags.iter() {
640 let lint_name = lint_name.replace("-", "_");
641 match lint_dict.find_equiv(&lint_name) {
643 early_error(demitter, fmt!("unknown %s flag: %s",
644 level_name, lint_name));
647 lint_opts.push((lint.lint, *level));
653 let mut debugging_opts = 0u;
654 let debug_flags = getopts::opt_strs(matches, "Z");
655 let debug_map = session::debugging_opts_map();
656 for debug_flag in debug_flags.iter() {
657 let mut this_bit = 0u;
658 for tuple in debug_map.iter() {
659 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
660 if name == debug_flag { this_bit = bit; break; }
663 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
665 debugging_opts |= this_bit;
667 if debugging_opts & session::debug_llvm != 0 {
669 llvm::LLVMSetDebug(1);
674 if parse_only || no_trans {
675 link::output_type_none
676 } else if opt_present(matches, "S") &&
677 opt_present(matches, "emit-llvm") {
678 link::output_type_llvm_assembly
679 } else if opt_present(matches, "S") {
680 link::output_type_assembly
681 } else if opt_present(matches, "c") {
682 link::output_type_object
683 } else if opt_present(matches, "emit-llvm") {
684 link::output_type_bitcode
685 } else { link::output_type_exe };
686 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
687 let target = getopts::opt_maybe_str(matches, "target").unwrap_or_default(host_triple());
688 let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or_default(~"generic");
689 let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or_default(~"");
690 let save_temps = getopts::opt_present(matches, "save-temps");
692 if (debugging_opts & session::no_opt) != 0 {
694 } else if opt_present(matches, "O") {
695 if opt_present(matches, "opt-level") {
696 early_error(demitter, ~"-O and --opt-level both provided");
699 } else if opt_present(matches, "opt-level") {
700 match getopts::opt_str(matches, "opt-level") {
706 early_error(demitter, ~"optimization level needs to be between 0-3")
711 let gc = debugging_opts & session::gc != 0;
712 let jit = debugging_opts & session::jit != 0;
713 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
714 let debuginfo = debugging_opts & session::debug_info != 0 ||
716 let statik = debugging_opts & session::statik != 0;
718 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
719 let linker = getopts::opt_maybe_str(matches, "linker");
720 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
721 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
724 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
725 let test = opt_present(matches, "test");
726 let android_cross_path = getopts::opt_maybe_str(
727 matches, "android-cross-path");
729 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
732 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
738 let sopts = @session::options {
739 crate_type: crate_type,
743 custom_passes: custom_passes,
744 debuginfo: debuginfo,
745 extra_debuginfo: extra_debuginfo,
746 lint_opts: lint_opts,
747 save_temps: save_temps,
749 output_type: output_type,
750 addl_lib_search_paths: @mut addl_lib_search_paths,
752 linker_args: linker_args,
753 maybe_sysroot: sysroot_opt,
754 target_triple: target,
755 target_cpu: target_cpu,
756 target_feature: target_feature,
760 parse_only: parse_only,
762 debugging_opts: debugging_opts,
763 android_cross_path: android_cross_path
768 pub fn build_session(sopts: @session::options,
769 demitter: diagnostic::Emitter) -> Session {
770 let codemap = @codemap::CodeMap::new();
771 let diagnostic_handler =
772 diagnostic::mk_handler(Some(demitter));
773 let span_diagnostic_handler =
774 diagnostic::mk_span_handler(diagnostic_handler, codemap);
775 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
778 pub fn build_session_(sopts: @session::options,
779 cm: @codemap::CodeMap,
780 demitter: diagnostic::Emitter,
781 span_diagnostic_handler: @diagnostic::span_handler)
783 let target_cfg = build_target_config(sopts, demitter);
784 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
786 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
787 let filesearch = filesearch::mk_filesearch(
788 &sopts.maybe_sysroot,
790 sopts.addl_lib_search_paths);
792 targ_cfg: target_cfg,
797 // For a library crate, this is always none
799 entry_type: @mut None,
800 span_diagnostic: span_diagnostic_handler,
801 filesearch: filesearch,
802 building_library: @mut false,
803 working_dir: os::getcwd(),
804 lints: @mut HashMap::new(),
808 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
810 &"normal" => ppm_normal,
811 &"expanded" => ppm_expanded,
812 &"typed" => ppm_typed,
813 &"expanded,identified" => ppm_expanded_identified,
814 &"identified" => ppm_identified,
816 sess.fatal("argument to `pretty` must be one of `normal`, \
817 `expanded`, `typed`, `identified`, \
818 or `expanded,identified`");
823 // rustc command line options
824 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
826 optflag("", "bin", "Compile an executable crate (default)"),
827 optflag("c", "", "Compile and assemble, but do not link"),
828 optmulti("", "cfg", "Configure the compilation
829 environment", "SPEC"),
830 optflag("", "emit-llvm",
831 "Produce an LLVM assembly file if used with -S option;
832 produce an LLVM bitcode file otherwise"),
833 optflag("h", "help","Display this message"),
834 optmulti("L", "", "Add a directory to the library search path",
836 optflag("", "lib", "Compile a library crate"),
837 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
838 optmulti("", "link-args", "FLAGS is a space-separated list of flags
839 passed to the linker", "FLAGS"),
840 optflag("", "ls", "List the symbols defined by a library crate"),
841 optflag("", "no-trans",
842 "Run all passes except translation; no output"),
843 optflag("O", "", "Equivalent to --opt-level=2"),
844 optopt("o", "", "Write output to <filename>", "FILENAME"),
845 optopt("", "opt-level",
846 "Optimize with possible levels 0-3", "LEVEL"),
847 optopt("", "passes", "Comma or space separated list of pass names to use. \
848 Overrides the default passes for optimization levels,\n\
849 a value of \"list\" will list the available passes.", "NAMES"),
850 optopt( "", "out-dir",
851 "Write output to compiler-chosen filename
853 optflag("", "parse-only",
854 "Parse only; do not compile, assemble, or link"),
855 optflagopt("", "pretty",
856 "Pretty-print the input instead of compiling;
857 valid types are: normal (un-annotated source),
858 expanded (crates expanded),
859 typed (crates expanded, with type annotations),
860 or identified (fully parenthesized,
861 AST nodes and blocks with IDs)", "TYPE"),
862 optflag("S", "", "Compile only; do not assemble or link"),
863 optflag("", "save-temps",
864 "Write intermediate files (.bc, .opt.bc, .o)
865 in addition to normal output"),
866 optopt("", "sysroot",
867 "Override the system root", "PATH"),
868 optflag("", "test", "Build a test harness"),
870 "Target triple cpu-manufacturer-kernel[-os]
871 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
872 for details)", "TRIPLE"),
873 optopt("", "target-cpu",
874 "Select target processor (llc -mcpu=help
875 for details)", "CPU"),
876 optopt("", "target-feature",
877 "Target specific attributes (llc -mattr=help
878 for details)", "FEATURE"),
879 optopt("", "android-cross-path",
880 "The path to the Android NDK", "PATH"),
881 optflagopt("W", "warn",
882 "Set lint warnings", "OPT"),
883 optmulti("A", "allow",
884 "Set lint allowed", "OPT"),
885 optmulti("D", "deny",
886 "Set lint denied", "OPT"),
887 optmulti("F", "forbid",
888 "Set lint forbidden", "OPT"),
889 optmulti("Z", "", "Set internal debugging options", "FLAG"),
890 optflag( "v", "version",
891 "Print version info and exit"),
895 pub struct OutputFilenames {
900 pub fn build_output_filenames(input: &input,
902 ofile: &Option<Path>,
903 attrs: &[ast::Attribute],
905 -> ~OutputFilenames {
908 let sopts = sess.opts;
909 let stop_after_codegen =
910 sopts.output_type != link::output_type_exe ||
911 sopts.is_static && *sess.building_library;
914 match sopts.output_type {
915 link::output_type_none => ~"none",
916 link::output_type_bitcode => ~"bc",
917 link::output_type_assembly => ~"s",
918 link::output_type_llvm_assembly => ~"ll",
919 // Object and exe output both use the '.o' extension here
920 link::output_type_object | link::output_type_exe => ~"o"
925 // "-" as input file will cause the parser to read from stdin so we
926 // have to make up a name
927 // We want to toss everything after the final '.'
928 let dirpath = match *odir {
929 Some(ref d) => (*d).clone(),
930 None => match *input {
931 str_input(_) => os::getcwd(),
932 file_input(ref ifile) => (*ifile).dir_path()
936 let mut stem = match *input {
937 file_input(ref ifile) => (*ifile).filestem().unwrap().to_managed(),
938 str_input(_) => @"rust_out"
941 // If a linkage name meta is present, we use it as the link name
942 let linkage_metas = attr::find_linkage_metas(attrs);
943 if !linkage_metas.is_empty() {
944 // But if a linkage meta is present, that overrides
945 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
946 match maybe_name.chain(|m| m.value_str()) {
950 // If the name is missing, we just default to the filename
954 if *sess.building_library {
955 out_path = dirpath.push(os::dll_filename(stem));
956 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
958 out_path = dirpath.push(stem);
959 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
963 Some(ref out_file) => {
964 out_path = (*out_file).clone();
965 obj_path = if stop_after_codegen {
968 (*out_file).with_filetype(obj_suffix)
971 if *sess.building_library {
972 sess.warn("ignoring specified output filename for library.");
976 sess.warn("ignoring --out-dir flag due to -o flag.");
982 out_filename: out_path,
983 obj_filename: obj_path
987 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
988 emitter(None, msg, diagnostic::fatal);
992 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
993 metadata::loader::list_file_metadata(
994 token::get_ident_interner(),
995 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
1001 use driver::driver::{build_configuration, build_session};
1002 use driver::driver::{build_session_options, optgroups, str_input};
1004 use extra::getopts::groups::getopts;
1007 use syntax::diagnostic;
1009 // When the user supplies --test we should implicitly supply --cfg test
1011 fn test_switch_implies_cfg_test() {
1013 &match getopts([~"--test"], optgroups()) {
1015 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
1017 let sessopts = build_session_options(
1018 @"rustc", matches, diagnostic::emit);
1019 let sess = build_session(sessopts, diagnostic::emit);
1020 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1021 assert!((attr::contains_name(cfg, "test")));
1024 // When the user supplies --test and --cfg test, don't implicitly add
1025 // another --cfg test
1027 fn test_switch_implies_cfg_test_unless_cfg_test() {
1029 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1032 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1035 let sessopts = build_session_options(
1036 @"rustc", matches, diagnostic::emit);
1037 let sess = build_session(sessopts, diagnostic::emit);
1038 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1039 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1040 assert!(test_items.next().is_some());
1041 assert!(test_items.next().is_none());