1 // Copyright 2012 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 metadata::{creader, cstore, filesearch};
21 use middle::{trans, freevars, kind, ty, typeck, lint, astencode, reachable};
23 use util::common::time;
26 use std::hashmap::HashMap;
31 use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
32 use extra::getopts::{opt_present};
37 use syntax::attr::{AttrMetaMethods};
39 use syntax::diagnostic;
41 use syntax::parse::token;
42 use syntax::print::{pp, pprust};
50 ppm_expanded_identified
54 * The name used for source code that doesn't originate in a file
55 * (e.g. source from stdin or a string)
57 pub fn anon_src() -> @str { @"<anon>" }
59 pub fn source_name(input: &input) -> @str {
61 file_input(ref ifile) => ifile.to_str().to_managed(),
62 str_input(_) => anon_src()
66 pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
68 let (libc, tos) = match sess.targ_cfg.os {
69 session::os_win32 => (@"msvcrt.dll", @"win32"),
70 session::os_macos => (@"libc.dylib", @"macos"),
71 session::os_linux => (@"libc.so.6", @"linux"),
72 session::os_android => (@"libc.so", @"android"),
73 session::os_freebsd => (@"libc.so.7", @"freebsd")
76 // ARM is bi-endian, however using NDK seems to default
77 // to little-endian unless a flag is provided.
78 let (end,arch,wordsz) = match sess.targ_cfg.arch {
79 abi::X86 => (@"little", @"x86", @"32"),
80 abi::X86_64 => (@"little", @"x86_64", @"64"),
81 abi::Arm => (@"little", @"arm", @"32"),
82 abi::Mips => (@"big", @"mips", @"32")
85 let mk = attr::mk_name_value_item_str;
86 return ~[ // Target bindings.
87 attr::mk_word_item(os::FAMILY.to_managed()),
88 mk(@"target_os", tos),
89 mk(@"target_family", os::FAMILY.to_managed()),
90 mk(@"target_arch", arch),
91 mk(@"target_endian", end),
92 mk(@"target_word_size", wordsz),
93 mk(@"target_libc", libc),
95 mk(@"build_compiler", argv0),
96 mk(@"build_input", source_name(input))];
99 pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
100 if !cfg.iter().any(|mi| mi.name() == name) {
101 cfg.push(attr::mk_word_item(name))
105 pub fn build_configuration(sess: Session, argv0: @str, input: &input) ->
107 // Combine the configuration requested by the session (command line) with
108 // some default and generated configuration items
109 let default_cfg = default_configuration(sess, argv0, input);
110 let mut user_cfg = sess.opts.cfg.clone();
111 // If the user wants a test runner, then add the test cfg
112 if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
113 // If the user requested GC, then add the GC cfg
114 append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
115 return vec::append(user_cfg, default_cfg);
118 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
119 fn parse_cfgspecs(cfgspecs: ~[~str],
120 demitter: diagnostic::Emitter) -> ast::CrateConfig {
121 do cfgspecs.consume_iter().transform |s| {
122 let sess = parse::new_parse_sess(Some(demitter));
123 parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
124 }.collect::<ast::CrateConfig>()
128 /// Load source from file
130 /// The string is the source
131 // FIXME (#2319): Don't really want to box the source string
135 pub fn parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
138 file_input(ref file) => {
139 parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess)
142 parse::parse_crate_from_source_str(
143 anon_src(), src, cfg, sess.parse_sess)
148 /// First phase to do, last phase to do
150 pub struct compile_upto {
156 pub enum compile_phase {
158 cu_expand, // means "it's already expanded"
164 // For continuing compilation after a parsed crate has been
168 #[fixed_stack_segment]
169 pub fn compile_rest(sess: Session,
170 cfg: ast::CrateConfig,
171 phases: compile_upto,
172 outputs: Option<@OutputFilenames>,
173 curr: Option<@ast::Crate>)
174 -> (Option<@ast::Crate>, Option<ty::ctxt>) {
176 let time_passes = sess.time_passes();
178 let mut crate = curr.unwrap();
180 if phases.from == cu_parse || phases.from == cu_everything {
182 *sess.building_library = session::building_library(
183 sess.opts.crate_type, crate, sess.opts.test);
185 // strip before expansion to allow macros to depend on
186 // configuration variables e.g/ in
188 // #[macro_escape] #[cfg(foo)]
189 // mod bar { macro_rules! baz!(() => {{}}) }
191 // baz! should not use this definition unless foo is enabled.
192 crate = time(time_passes, ~"std macros injection", ||
193 syntax::ext::expand::inject_std_macros(sess.parse_sess,
197 crate = time(time_passes, ~"configuration 1", ||
198 front::config::strip_unconfigured_items(crate));
200 crate = time(time_passes, ~"expansion", ||
201 syntax::ext::expand::expand_crate(sess.parse_sess,
205 // strip again, in case expansion added anything with a #[cfg].
206 crate = time(time_passes, ~"configuration 2", ||
207 front::config::strip_unconfigured_items(crate));
210 crate = time(time_passes, ~"maybe building test harness", ||
211 front::test::modify_for_testing(sess, crate));
214 if phases.to == cu_expand {
215 return (Some(crate), None);
218 assert!(phases.from != cu_no_trans);
220 let (llcx, llmod, link_meta) = {
221 crate = time(time_passes, ~"std injection", ||
222 front::std_inject::maybe_inject_libstd_ref(sess, crate));
224 let ast_map = time(time_passes, ~"ast indexing", ||
225 syntax::ast_map::map_crate(sess.diagnostic(), crate));
227 time(time_passes, ~"external crate/lib resolution", ||
228 creader::read_crates(sess.diagnostic(), crate, sess.cstore,
230 session::sess_os_to_meta_os(sess.targ_cfg.os),
232 token::get_ident_interner()));
234 let lang_items = time(time_passes, ~"language item collection", ||
235 middle::lang_items::collect_language_items(crate, sess));
237 let middle::resolve::CrateMap {
242 time(time_passes, ~"resolution", ||
243 middle::resolve::resolve_crate(sess, lang_items, crate));
245 time(time_passes, ~"looking for entry point",
246 || middle::entry::find_entry_point(sess, crate, ast_map));
248 let freevars = time(time_passes, ~"freevar finding", ||
249 freevars::annotate_freevars(def_map, crate));
251 let region_map = time(time_passes, ~"region resolution", ||
252 middle::region::resolve_crate(sess, def_map, crate));
254 let rp_set = time(time_passes, ~"region parameterization inference", ||
255 middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
257 let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
258 region_map, rp_set, lang_items);
260 // passes are timed inside typeck
261 let (method_map, vtable_map) = typeck::check_crate(
262 ty_cx, trait_map, crate);
264 // These next two const passes can probably be merged
265 time(time_passes, ~"const marking", ||
266 middle::const_eval::process_crate(crate, ty_cx));
268 time(time_passes, ~"const checking", ||
269 middle::check_const::check_crate(sess, crate, ast_map, def_map,
272 if phases.to == cu_typeck { return (Some(crate), Some(ty_cx)); }
274 time(time_passes, ~"privacy checking", ||
275 middle::privacy::check_crate(ty_cx, &method_map, crate));
277 time(time_passes, ~"effect checking", ||
278 middle::effect::check_crate(ty_cx, method_map, crate));
280 time(time_passes, ~"loop checking", ||
281 middle::check_loop::check_crate(ty_cx, crate));
283 let middle::moves::MoveMaps {moves_map, moved_variables_set,
285 time(time_passes, ~"compute moves", ||
286 middle::moves::compute_moves(ty_cx, method_map, crate));
288 time(time_passes, ~"match checking", ||
289 middle::check_match::check_crate(ty_cx, method_map,
292 time(time_passes, ~"liveness checking", ||
293 middle::liveness::check_crate(ty_cx, method_map,
294 capture_map, crate));
296 let (root_map, write_guard_map) =
297 time(time_passes, ~"borrow checking", ||
298 middle::borrowck::check_crate(ty_cx, method_map,
299 moves_map, moved_variables_set,
300 capture_map, crate));
302 time(time_passes, ~"kind checking", ||
303 kind::check_crate(ty_cx, method_map, crate));
306 time(time_passes, ~"reachability checking", ||
307 reachable::find_reachable(ty_cx, method_map, crate));
309 time(time_passes, ~"lint checking", ||
310 lint::check_crate(ty_cx, crate));
312 if phases.to == cu_no_trans {
313 return (Some(crate), Some(ty_cx));
316 let maps = astencode::Maps {
318 method_map: method_map,
319 vtable_map: vtable_map,
320 write_guard_map: write_guard_map,
321 capture_map: capture_map
324 let outputs = outputs.get_ref();
325 time(time_passes, ~"translation", ||
326 trans::base::trans_crate(sess,
329 &outputs.obj_filename,
335 let outputs = outputs.get_ref();
336 if (sess.opts.debugging_opts & session::print_link_args) != 0 {
337 io::println(link::link_args(sess, &outputs.obj_filename,
338 &outputs.out_filename, link_meta).connect(" "));
342 if sess.targ_cfg.arch == abi::Arm &&
343 (sess.opts.output_type == link::output_type_object ||
344 sess.opts.output_type == link::output_type_exe) {
345 let output_type = link::output_type_assembly;
346 let obj_filename = outputs.obj_filename.with_filetype("s");
348 time(time_passes, ~"LLVM passes", ||
349 link::write::run_passes(sess, llcx, llmod, output_type,
352 link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
354 time(time_passes, ~"LLVM passes", ||
355 link::write::run_passes(sess, llcx, llmod, sess.opts.output_type,
356 &outputs.obj_filename));
359 let stop_after_codegen =
360 sess.opts.output_type != link::output_type_exe ||
361 (sess.opts.is_static && *sess.building_library) ||
364 if stop_after_codegen { return (None, None); }
366 time(time_passes, ~"linking", ||
367 link::link_binary(sess,
368 &outputs.obj_filename,
369 &outputs.out_filename, link_meta));
374 pub fn compile_upto(sess: Session,
375 cfg: ast::CrateConfig,
378 outputs: Option<@OutputFilenames>)
379 -> (Option<@ast::Crate>, Option<ty::ctxt>) {
380 let time_passes = sess.time_passes();
381 let crate = time(time_passes,
383 || parse_input(sess, cfg.clone(), input) );
384 if upto == cu_parse {
385 return (Some(crate), None);
398 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
399 outdir: &Option<Path>, output: &Option<Path>) {
400 let upto = if sess.opts.parse_only { cu_parse }
401 else if sess.opts.no_trans { cu_no_trans }
402 else { cu_everything };
403 let outputs = build_output_filenames(input, outdir, output, [], sess); // ???
404 compile_upto(sess, cfg, input, upto, Some(outputs));
407 pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
409 fn ann_paren_for_expr(node: pprust::ann_node) {
411 pprust::node_expr(s, _) => pprust::popen(s),
415 fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
417 pprust::node_expr(s, expr) => {
421 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
427 fn ann_identified_post(node: pprust::ann_node) {
429 pprust::node_item(s, item) => {
431 pprust::synth_comment(s, int::to_str(item.id));
433 pprust::node_block(s, ref blk) => {
435 pprust::synth_comment(
436 s, ~"block " + int::to_str(blk.id));
438 pprust::node_expr(s, expr) => {
440 pprust::synth_comment(s, int::to_str(expr.id));
443 pprust::node_pat(s, pat) => {
445 pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
450 // Because the pretty printer needs to make a pass over the source
451 // to collect comments and literals, and we need to support reading
452 // from stdin, we're going to just suck the source into a string
453 // so both the parser and pretty-printer can use it.
454 let upto = match ppm {
455 ppm_expanded | ppm_expanded_identified => cu_expand,
456 ppm_typed => cu_typeck,
459 let (crate, tcx) = compile_upto(sess, cfg, input, upto, None);
461 let ann = match ppm {
463 pprust::pp_ann {pre: ann_paren_for_expr,
464 post: |a| ann_typed_post(tcx.get(), a) }
466 ppm_identified | ppm_expanded_identified => {
467 pprust::pp_ann {pre: ann_paren_for_expr,
468 post: ann_identified_post}
470 ppm_expanded | ppm_normal => {
474 let is_expanded = upto != cu_parse;
475 let src = sess.codemap.get_filemap(source_name(input)).src;
476 do io::with_str_reader(src) |rdr| {
477 pprust::print_crate(sess.codemap, token::get_ident_interner(),
478 sess.span_diagnostic, crate.unwrap(),
480 rdr, io::stdout(), ann, is_expanded);
484 pub fn get_os(triple: &str) -> Option<session::os> {
485 for os_names.iter().advance |&(name, os)| {
486 if triple.contains(name) { return Some(os) }
490 static os_names : &'static [(&'static str, session::os)] = &'static [
491 ("mingw32", session::os_win32),
492 ("win32", session::os_win32),
493 ("darwin", session::os_macos),
494 ("android", session::os_android),
495 ("linux", session::os_linux),
496 ("freebsd", session::os_freebsd)];
498 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
499 for architecture_abis.iter().advance |&(arch, abi)| {
500 if triple.contains(arch) { return Some(abi) }
504 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
511 ("x86_64", abi::X86_64),
514 ("xscale", abi::Arm),
516 ("mips", abi::Mips)];
518 pub fn build_target_config(sopts: @session::options,
519 demitter: diagnostic::Emitter)
520 -> @session::config {
521 let os = match get_os(sopts.target_triple) {
523 None => early_error(demitter, ~"unknown operating system")
525 let arch = match get_arch(sopts.target_triple) {
527 None => early_error(demitter,
528 ~"unknown architecture: " + sopts.target_triple)
530 let (int_type, uint_type, float_type) = match arch {
531 abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
532 abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
533 abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
534 abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
536 let target_strs = match arch {
537 abi::X86 => x86::get_target_strs(os),
538 abi::X86_64 => x86_64::get_target_strs(os),
539 abi::Arm => arm::get_target_strs(os),
540 abi::Mips => mips::get_target_strs(os)
542 let target_cfg = @session::config {
545 target_strs: target_strs,
547 uint_type: uint_type,
548 float_type: float_type
553 pub fn host_triple() -> ~str {
554 // Get the host triple out of the build environment. This ensures that our
555 // idea of the host triple is the same as for the set of libraries we've
556 // actually built. We can't just take LLVM's host triple because they
557 // normalize all ix86 architectures to i386.
559 // Instead of grabbing the host triple (for the current host), we grab (at
560 // compile time) the target triple that this rustc is built with and
561 // calling that (at runtime) the host triple.
562 let ht = env!("CFG_COMPILER_TRIPLE");
566 fail!("rustc built without CFG_COMPILER_TRIPLE")
570 pub fn build_session_options(binary: @str,
571 matches: &getopts::Matches,
572 demitter: diagnostic::Emitter)
573 -> @session::options {
574 let crate_type = if opt_present(matches, "lib") {
576 } else if opt_present(matches, "bin") {
579 session::unknown_crate
581 let parse_only = opt_present(matches, "parse-only");
582 let no_trans = opt_present(matches, "no-trans");
584 let lint_levels = [lint::allow, lint::warn,
585 lint::deny, lint::forbid];
586 let mut lint_opts = ~[];
587 let lint_dict = lint::get_lint_dict();
588 for lint_levels.iter().advance |level| {
589 let level_name = lint::level_to_str(*level);
591 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
592 // to_ascii_consume and to_str_consume to not do a unnecessary copy.
593 let level_short = level_name.slice_chars(0, 1);
594 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
595 let flags = vec::append(getopts::opt_strs(matches, level_short),
596 getopts::opt_strs(matches, level_name));
597 for flags.iter().advance |lint_name| {
598 let lint_name = lint_name.replace("-", "_");
599 match lint_dict.find_equiv(&lint_name) {
601 early_error(demitter, fmt!("unknown %s flag: %s",
602 level_name, lint_name));
605 lint_opts.push((lint.lint, *level));
611 let mut debugging_opts = 0u;
612 let debug_flags = getopts::opt_strs(matches, "Z");
613 let debug_map = session::debugging_opts_map();
614 for debug_flags.iter().advance |debug_flag| {
615 let mut this_bit = 0u;
616 for debug_map.iter().advance |tuple| {
617 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
618 if name == debug_flag { this_bit = bit; break; }
621 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
623 debugging_opts |= this_bit;
625 if debugging_opts & session::debug_llvm != 0 {
627 llvm::LLVMSetDebug(1);
632 if parse_only || no_trans {
633 link::output_type_none
634 } else if opt_present(matches, "S") &&
635 opt_present(matches, "emit-llvm") {
636 link::output_type_llvm_assembly
637 } else if opt_present(matches, "S") {
638 link::output_type_assembly
639 } else if opt_present(matches, "c") {
640 link::output_type_object
641 } else if opt_present(matches, "emit-llvm") {
642 link::output_type_bitcode
643 } else { link::output_type_exe };
644 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot");
645 let sysroot_opt = sysroot_opt.map(|m| @Path(*m));
646 let target_opt = getopts::opt_maybe_str(matches, "target");
647 let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
648 let save_temps = getopts::opt_present(matches, "save-temps");
650 if (debugging_opts & session::no_opt) != 0 {
652 } else if opt_present(matches, "O") {
653 if opt_present(matches, "opt-level") {
654 early_error(demitter, ~"-O and --opt-level both provided");
657 } else if opt_present(matches, "opt-level") {
658 match getopts::opt_str(matches, "opt-level") {
664 early_error(demitter, ~"optimization level needs to be between 0-3")
669 let gc = debugging_opts & session::gc != 0;
670 let jit = debugging_opts & session::jit != 0;
671 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
672 let debuginfo = debugging_opts & session::debug_info != 0 ||
674 let statik = debugging_opts & session::statik != 0;
677 None => host_triple(),
680 let target_feature = match target_feature_opt {
685 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
686 let linker = getopts::opt_maybe_str(matches, "linker");
687 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
688 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
691 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
692 let test = opt_present(matches, "test");
693 let android_cross_path = getopts::opt_maybe_str(
694 matches, "android-cross-path");
696 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
699 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
705 let sopts = @session::options {
706 crate_type: crate_type,
710 custom_passes: custom_passes,
711 debuginfo: debuginfo,
712 extra_debuginfo: extra_debuginfo,
713 lint_opts: lint_opts,
714 save_temps: save_temps,
716 output_type: output_type,
717 addl_lib_search_paths: @mut addl_lib_search_paths,
719 linker_args: linker_args,
720 maybe_sysroot: sysroot_opt,
721 target_triple: target,
722 target_feature: target_feature,
726 parse_only: parse_only,
728 debugging_opts: debugging_opts,
729 android_cross_path: android_cross_path
734 pub fn build_session(sopts: @session::options,
735 demitter: diagnostic::Emitter) -> Session {
736 let codemap = @codemap::CodeMap::new();
737 let diagnostic_handler =
738 diagnostic::mk_handler(Some(demitter));
739 let span_diagnostic_handler =
740 diagnostic::mk_span_handler(diagnostic_handler, codemap);
741 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
744 pub fn build_session_(sopts: @session::options,
745 cm: @codemap::CodeMap,
746 demitter: diagnostic::Emitter,
747 span_diagnostic_handler: @diagnostic::span_handler)
749 let target_cfg = build_target_config(sopts, demitter);
750 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
752 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
753 let filesearch = filesearch::mk_filesearch(
754 &sopts.maybe_sysroot,
756 sopts.addl_lib_search_paths);
758 targ_cfg: target_cfg,
763 // For a library crate, this is always none
765 entry_type: @mut None,
766 span_diagnostic: span_diagnostic_handler,
767 filesearch: filesearch,
768 building_library: @mut false,
769 working_dir: os::getcwd(),
770 lints: @mut HashMap::new(),
774 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
776 &"normal" => ppm_normal,
777 &"expanded" => ppm_expanded,
778 &"typed" => ppm_typed,
779 &"expanded,identified" => ppm_expanded_identified,
780 &"identified" => ppm_identified,
782 sess.fatal("argument to `pretty` must be one of `normal`, \
783 `expanded`, `typed`, `identified`, \
784 or `expanded,identified`");
789 // rustc command line options
790 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
792 optflag("", "bin", "Compile an executable crate (default)"),
793 optflag("c", "", "Compile and assemble, but do not link"),
794 optmulti("", "cfg", "Configure the compilation
795 environment", "SPEC"),
796 optflag("", "emit-llvm",
797 "Produce an LLVM bitcode file"),
798 optflag("h", "help","Display this message"),
799 optmulti("L", "", "Add a directory to the library search path",
801 optflag("", "lib", "Compile a library crate"),
802 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
803 optmulti("", "link-args", "FLAGS is a space-separated list of flags
804 passed to the linker", "FLAGS"),
805 optflag("", "ls", "List the symbols defined by a library crate"),
806 optflag("", "no-trans",
807 "Run all passes except translation; no output"),
808 optflag("O", "", "Equivalent to --opt-level=2"),
809 optopt("o", "", "Write output to <filename>", "FILENAME"),
810 optopt("", "opt-level",
811 "Optimize with possible levels 0-3", "LEVEL"),
812 optopt("", "passes", "Comma or space separated list of pass names to use. \
813 Overrides the default passes for optimization levels,\n\
814 a value of \"list\" will list the available passes.", "NAMES"),
815 optopt( "", "out-dir",
816 "Write output to compiler-chosen filename
818 optflag("", "parse-only",
819 "Parse only; do not compile, assemble, or link"),
820 optflagopt("", "pretty",
821 "Pretty-print the input instead of compiling;
822 valid types are: normal (un-annotated source),
823 expanded (crates expanded),
824 typed (crates expanded, with type annotations),
825 or identified (fully parenthesized,
826 AST nodes and blocks with IDs)", "TYPE"),
827 optflag("S", "", "Compile only; do not assemble or link"),
828 optflag("", "save-temps",
829 "Write intermediate files (.bc, .opt.bc, .o)
830 in addition to normal output"),
831 optopt("", "sysroot",
832 "Override the system root", "PATH"),
833 optflag("", "test", "Build a test harness"),
835 "Target triple cpu-manufacturer-kernel[-os]
836 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
837 for detail)", "TRIPLE"),
838 optopt("", "target-feature",
839 "Target specific attributes (llc -mattr=help
840 for detail)", "FEATURE"),
841 optopt("", "android-cross-path",
842 "The path to the Android NDK", "PATH"),
843 optflagopt("W", "warn",
844 "Set lint warnings", "OPT"),
845 optmulti("A", "allow",
846 "Set lint allowed", "OPT"),
847 optmulti("D", "deny",
848 "Set lint denied", "OPT"),
849 optmulti("F", "forbid",
850 "Set lint forbidden", "OPT"),
851 optmulti("Z", "", "Set internal debugging options", "FLAG"),
852 optflag( "v", "version",
853 "Print version info and exit"),
857 pub struct OutputFilenames {
862 pub fn build_output_filenames(input: &input,
864 ofile: &Option<Path>,
865 attrs: &[ast::Attribute],
867 -> @OutputFilenames {
870 let sopts = sess.opts;
871 let stop_after_codegen =
872 sopts.output_type != link::output_type_exe ||
873 sopts.is_static && *sess.building_library;
876 match sopts.output_type {
877 link::output_type_none => ~"none",
878 link::output_type_bitcode => ~"bc",
879 link::output_type_assembly => ~"s",
880 link::output_type_llvm_assembly => ~"ll",
881 // Object and exe output both use the '.o' extension here
882 link::output_type_object | link::output_type_exe => ~"o"
887 // "-" as input file will cause the parser to read from stdin so we
888 // have to make up a name
889 // We want to toss everything after the final '.'
890 let dirpath = match *odir {
891 Some(ref d) => (*d).clone(),
892 None => match *input {
893 str_input(_) => os::getcwd(),
894 file_input(ref ifile) => (*ifile).dir_path()
898 let mut stem = match *input {
899 file_input(ref ifile) => (*ifile).filestem().get().to_managed(),
900 str_input(_) => @"rust_out"
903 // If a linkage name meta is present, we use it as the link name
904 let linkage_metas = attr::find_linkage_metas(attrs);
905 if !linkage_metas.is_empty() {
906 // But if a linkage meta is present, that overrides
907 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
908 match maybe_name.chain(|m| m.value_str()) {
912 // If the name is missing, we just default to the filename
916 if *sess.building_library {
917 out_path = dirpath.push(os::dll_filename(stem));
918 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
920 out_path = dirpath.push(stem);
921 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
925 Some(ref out_file) => {
926 out_path = (*out_file).clone();
927 obj_path = if stop_after_codegen {
930 (*out_file).with_filetype(obj_suffix)
933 if *sess.building_library {
934 // FIXME (#2401): We might want to warn here; we're actually not
935 // going to respect the user's choice of library name when it
936 // comes time to link, we'll be linking to
937 // lib<basename>-<hash>-<version>.so no matter what.
941 sess.warn("ignoring --out-dir flag due to -o flag.");
947 out_filename: out_path,
948 obj_filename: obj_path
952 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
953 emitter(None, msg, diagnostic::fatal);
957 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
958 metadata::loader::list_file_metadata(
959 token::get_ident_interner(),
960 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
966 use driver::driver::{build_configuration, build_session};
967 use driver::driver::{build_session_options, optgroups, str_input};
969 use extra::getopts::groups::getopts;
972 use syntax::diagnostic;
974 // When the user supplies --test we should implicitly supply --cfg test
976 fn test_switch_implies_cfg_test() {
978 &match getopts([~"--test"], optgroups()) {
980 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
982 let sessopts = build_session_options(
983 @"rustc", matches, diagnostic::emit);
984 let sess = build_session(sessopts, diagnostic::emit);
985 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
986 assert!((attr::contains_name(cfg, "test")));
989 // When the user supplies --test and --cfg test, don't implicitly add
990 // another --cfg test
992 fn test_switch_implies_cfg_test_unless_cfg_test() {
994 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
997 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1000 let sessopts = build_session_options(
1001 @"rustc", matches, diagnostic::emit);
1002 let sess = build_session(sessopts, diagnostic::emit);
1003 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1004 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1005 assert!(test_items.next().is_some());
1006 assert!(test_items.next().is_none());