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};
38 use syntax::diagnostic;
40 use syntax::parse::token;
41 use syntax::print::{pp, pprust};
49 ppm_expanded_identified
53 * The name used for source code that doesn't originate in a file
54 * (e.g. source from stdin or a string)
56 pub fn anon_src() -> @str { @"<anon>" }
58 pub fn source_name(input: &input) -> @str {
60 file_input(ref ifile) => ifile.to_str().to_managed(),
61 str_input(_) => anon_src()
65 pub fn default_configuration(sess: Session, argv0: @str, input: &input) ->
67 let (libc, tos) = match sess.targ_cfg.os {
68 session::os_win32 => (@"msvcrt.dll", @"win32"),
69 session::os_macos => (@"libc.dylib", @"macos"),
70 session::os_linux => (@"libc.so.6", @"linux"),
71 session::os_android => (@"libc.so", @"android"),
72 session::os_freebsd => (@"libc.so.7", @"freebsd")
75 // ARM is bi-endian, however using NDK seems to default
76 // to little-endian unless a flag is provided.
77 let (end,arch,wordsz) = match sess.targ_cfg.arch {
78 abi::X86 => (@"little", @"x86", @"32"),
79 abi::X86_64 => (@"little", @"x86_64", @"64"),
80 abi::Arm => (@"little", @"arm", @"32"),
81 abi::Mips => (@"big", @"mips", @"32")
84 let mk = attr::mk_name_value_item_str;
85 return ~[ // Target bindings.
86 attr::mk_word_item(os::FAMILY.to_managed()),
87 mk(@"target_os", tos),
88 mk(@"target_family", os::FAMILY.to_managed()),
89 mk(@"target_arch", arch),
90 mk(@"target_endian", end),
91 mk(@"target_word_size", wordsz),
92 mk(@"target_libc", libc),
94 mk(@"build_compiler", argv0),
95 mk(@"build_input", source_name(input))];
98 pub fn append_configuration(cfg: ast::crate_cfg, name: @str)
100 if attr::contains_name(cfg, name) {
103 vec::append_one(cfg, 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 user_cfg = sess.opts.cfg.clone();
113 // If the user wants a test runner, then add the test cfg
114 let user_cfg = if sess.opts.test {
115 append_configuration(user_cfg, @"test")
120 // If the user requested GC, then add the GC cfg
121 let user_cfg = append_configuration(
123 if sess.opts.gc { @"gc" } else { @"nogc" });
124 return vec::append(user_cfg, default_cfg);
127 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
128 fn parse_cfgspecs(cfgspecs: ~[~str],
129 demitter: diagnostic::Emitter) -> ast::crate_cfg {
130 do cfgspecs.consume_iter().transform |s| {
131 let sess = parse::new_parse_sess(Some(demitter));
132 parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
137 /// Load source from file
139 /// The string is the source
140 // FIXME (#2319): Don't really want to box the source string
144 pub fn parse_input(sess: Session, cfg: ast::crate_cfg, input: &input)
147 file_input(ref file) => {
148 parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess)
151 parse::parse_crate_from_source_str(
152 anon_src(), src, cfg, sess.parse_sess)
157 /// First phase to do, last phase to do
159 pub struct compile_upto {
165 pub enum compile_phase {
167 cu_expand, // means "it's already expanded"
173 // For continuing compilation after a parsed crate has been
177 #[fixed_stack_segment]
178 pub fn compile_rest(sess: Session,
180 phases: compile_upto,
181 outputs: Option<@OutputFilenames>,
182 curr: Option<@ast::crate>)
183 -> (Option<@ast::crate>, Option<ty::ctxt>) {
185 let time_passes = sess.time_passes();
187 let mut crate = curr.unwrap();
189 if phases.from == cu_parse || phases.from == cu_everything {
191 *sess.building_library = session::building_library(
192 sess.opts.crate_type, crate, sess.opts.test);
194 // strip before expansion to allow macros to depend on
195 // configuration variables e.g/ in
197 // #[macro_escape] #[cfg(foo)]
198 // mod bar { macro_rules! baz!(() => {{}}) }
200 // baz! should not use this definition unless foo is enabled.
201 crate = time(time_passes, ~"std macros injection", ||
202 syntax::ext::expand::inject_std_macros(sess.parse_sess,
206 crate = time(time_passes, ~"configuration 1", ||
207 front::config::strip_unconfigured_items(crate));
209 crate = time(time_passes, ~"expansion", ||
210 syntax::ext::expand::expand_crate(sess.parse_sess,
214 // strip again, in case expansion added anything with a #[cfg].
215 crate = time(time_passes, ~"configuration 2", ||
216 front::config::strip_unconfigured_items(crate));
218 crate = time(time_passes, ~"maybe building test harness", ||
219 front::test::modify_for_testing(sess, crate));
222 if phases.to == cu_expand {
223 return (Some(crate), None);
226 assert!(phases.from != cu_no_trans);
228 let (llcx, llmod, link_meta) = {
229 crate = time(time_passes, ~"std injection", ||
230 front::std_inject::maybe_inject_libstd_ref(sess, crate));
232 let ast_map = time(time_passes, ~"ast indexing", ||
233 syntax::ast_map::map_crate(sess.diagnostic(), crate));
235 time(time_passes, ~"external crate/lib resolution", ||
236 creader::read_crates(sess.diagnostic(), crate, sess.cstore,
238 session::sess_os_to_meta_os(sess.targ_cfg.os),
240 token::get_ident_interner()));
242 let lang_items = time(time_passes, ~"language item collection", ||
243 middle::lang_items::collect_language_items(crate, sess));
245 let middle::resolve::CrateMap {
250 time(time_passes, ~"resolution", ||
251 middle::resolve::resolve_crate(sess, lang_items, crate));
253 time(time_passes, ~"looking for entry point",
254 || middle::entry::find_entry_point(sess, crate, ast_map));
256 let freevars = time(time_passes, ~"freevar finding", ||
257 freevars::annotate_freevars(def_map, crate));
259 let region_map = time(time_passes, ~"region resolution", ||
260 middle::region::resolve_crate(sess, def_map, crate));
262 let rp_set = time(time_passes, ~"region parameterization inference", ||
263 middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
265 let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
266 region_map, rp_set, lang_items);
268 // passes are timed inside typeck
269 let (method_map, vtable_map) = typeck::check_crate(
270 ty_cx, trait_map, crate);
272 // These next two const passes can probably be merged
273 time(time_passes, ~"const marking", ||
274 middle::const_eval::process_crate(crate, ty_cx));
276 time(time_passes, ~"const checking", ||
277 middle::check_const::check_crate(sess, crate, ast_map, def_map,
280 if phases.to == cu_typeck { return (Some(crate), Some(ty_cx)); }
282 time(time_passes, ~"privacy checking", ||
283 middle::privacy::check_crate(ty_cx, &method_map, crate));
285 time(time_passes, ~"effect checking", ||
286 middle::effect::check_crate(ty_cx, method_map, crate));
288 time(time_passes, ~"loop checking", ||
289 middle::check_loop::check_crate(ty_cx, crate));
291 let middle::moves::MoveMaps {moves_map, moved_variables_set,
293 time(time_passes, ~"compute moves", ||
294 middle::moves::compute_moves(ty_cx, method_map, crate));
296 time(time_passes, ~"match checking", ||
297 middle::check_match::check_crate(ty_cx, method_map,
300 time(time_passes, ~"liveness checking", ||
301 middle::liveness::check_crate(ty_cx, method_map,
302 capture_map, crate));
304 let (root_map, write_guard_map) =
305 time(time_passes, ~"borrow checking", ||
306 middle::borrowck::check_crate(ty_cx, method_map,
307 moves_map, moved_variables_set,
308 capture_map, crate));
310 time(time_passes, ~"kind checking", ||
311 kind::check_crate(ty_cx, method_map, crate));
314 time(time_passes, ~"reachability checking", ||
315 reachable::find_reachable(ty_cx, method_map, crate));
317 time(time_passes, ~"lint checking", ||
318 lint::check_crate(ty_cx, crate));
320 if phases.to == cu_no_trans {
321 return (Some(crate), Some(ty_cx));
324 let maps = astencode::Maps {
326 method_map: method_map,
327 vtable_map: vtable_map,
328 write_guard_map: write_guard_map,
329 capture_map: capture_map
332 let outputs = outputs.get_ref();
333 time(time_passes, ~"translation", ||
334 trans::base::trans_crate(sess,
337 &outputs.obj_filename,
343 let outputs = outputs.get_ref();
344 if (sess.opts.debugging_opts & session::print_link_args) != 0 {
345 io::println(link::link_args(sess, &outputs.obj_filename,
346 &outputs.out_filename, link_meta).connect(" "));
350 if sess.targ_cfg.arch == abi::Arm &&
351 (sess.opts.output_type == link::output_type_object ||
352 sess.opts.output_type == link::output_type_exe) {
353 let output_type = link::output_type_assembly;
354 let obj_filename = outputs.obj_filename.with_filetype("s");
356 time(time_passes, ~"LLVM passes", ||
357 link::write::run_passes(sess, llcx, llmod, output_type,
360 link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
362 time(time_passes, ~"LLVM passes", ||
363 link::write::run_passes(sess, llcx, llmod, sess.opts.output_type,
364 &outputs.obj_filename));
367 let stop_after_codegen =
368 sess.opts.output_type != link::output_type_exe ||
369 (sess.opts.is_static && *sess.building_library) ||
372 if stop_after_codegen { return (None, None); }
374 time(time_passes, ~"linking", ||
375 link::link_binary(sess,
376 &outputs.obj_filename,
377 &outputs.out_filename, link_meta));
382 pub fn compile_upto(sess: Session,
386 outputs: Option<@OutputFilenames>)
387 -> (Option<@ast::crate>, Option<ty::ctxt>) {
388 let time_passes = sess.time_passes();
389 let crate = time(time_passes,
391 || parse_input(sess, cfg.clone(), input) );
392 if upto == cu_parse {
393 return (Some(crate), None);
406 pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input,
407 outdir: &Option<Path>, output: &Option<Path>) {
408 let upto = if sess.opts.parse_only { cu_parse }
409 else if sess.opts.no_trans { cu_no_trans }
410 else { cu_everything };
411 let outputs = build_output_filenames(input, outdir, output, [], sess); // ???
412 compile_upto(sess, cfg, input, upto, Some(outputs));
415 pub fn pretty_print_input(sess: Session, cfg: ast::crate_cfg, input: &input,
417 fn ann_paren_for_expr(node: pprust::ann_node) {
419 pprust::node_expr(s, _) => pprust::popen(s),
423 fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
425 pprust::node_expr(s, expr) => {
429 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
435 fn ann_identified_post(node: pprust::ann_node) {
437 pprust::node_item(s, item) => {
439 pprust::synth_comment(s, int::to_str(item.id));
441 pprust::node_block(s, ref blk) => {
443 pprust::synth_comment(
444 s, ~"block " + int::to_str(blk.id));
446 pprust::node_expr(s, expr) => {
448 pprust::synth_comment(s, int::to_str(expr.id));
451 pprust::node_pat(s, pat) => {
453 pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
458 // Because the pretty printer needs to make a pass over the source
459 // to collect comments and literals, and we need to support reading
460 // from stdin, we're going to just suck the source into a string
461 // so both the parser and pretty-printer can use it.
462 let upto = match ppm {
463 ppm_expanded | ppm_expanded_identified => cu_expand,
464 ppm_typed => cu_typeck,
467 let (crate, tcx) = compile_upto(sess, cfg, input, upto, None);
469 let ann = match ppm {
471 pprust::pp_ann {pre: ann_paren_for_expr,
472 post: |a| ann_typed_post(tcx.get(), a) }
474 ppm_identified | ppm_expanded_identified => {
475 pprust::pp_ann {pre: ann_paren_for_expr,
476 post: ann_identified_post}
478 ppm_expanded | ppm_normal => {
482 let is_expanded = upto != cu_parse;
483 let src = sess.codemap.get_filemap(source_name(input)).src;
484 do io::with_str_reader(src) |rdr| {
485 pprust::print_crate(sess.codemap, token::get_ident_interner(),
486 sess.span_diagnostic, crate.unwrap(),
488 rdr, io::stdout(), ann, is_expanded);
492 pub fn get_os(triple: &str) -> Option<session::os> {
493 for os_names.iter().advance |&(name, os)| {
494 if triple.contains(name) { return Some(os) }
498 static os_names : &'static [(&'static str, session::os)] = &'static [
499 ("mingw32", session::os_win32),
500 ("win32", session::os_win32),
501 ("darwin", session::os_macos),
502 ("android", session::os_android),
503 ("linux", session::os_linux),
504 ("freebsd", session::os_freebsd)];
506 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
507 for architecture_abis.iter().advance |&(arch, abi)| {
508 if triple.contains(arch) { return Some(abi) }
512 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
519 ("x86_64", abi::X86_64),
522 ("xscale", abi::Arm),
524 ("mips", abi::Mips)];
526 pub fn build_target_config(sopts: @session::options,
527 demitter: diagnostic::Emitter)
528 -> @session::config {
529 let os = match get_os(sopts.target_triple) {
531 None => early_error(demitter, ~"unknown operating system")
533 let arch = match get_arch(sopts.target_triple) {
535 None => early_error(demitter,
536 ~"unknown architecture: " + sopts.target_triple)
538 let (int_type, uint_type, float_type) = match arch {
539 abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
540 abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
541 abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
542 abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
544 let target_strs = match arch {
545 abi::X86 => x86::get_target_strs(os),
546 abi::X86_64 => x86_64::get_target_strs(os),
547 abi::Arm => arm::get_target_strs(os),
548 abi::Mips => mips::get_target_strs(os)
550 let target_cfg = @session::config {
553 target_strs: target_strs,
555 uint_type: uint_type,
556 float_type: float_type
561 pub fn host_triple() -> ~str {
562 // Get the host triple out of the build environment. This ensures that our
563 // idea of the host triple is the same as for the set of libraries we've
564 // actually built. We can't just take LLVM's host triple because they
565 // normalize all ix86 architectures to i386.
567 // Instead of grabbing the host triple (for the current host), we grab (at
568 // compile time) the target triple that this rustc is built with and
569 // calling that (at runtime) the host triple.
570 let ht = env!("CFG_COMPILER_TRIPLE");
574 fail!("rustc built without CFG_COMPILER_TRIPLE")
578 pub fn build_session_options(binary: @str,
579 matches: &getopts::Matches,
580 demitter: diagnostic::Emitter)
581 -> @session::options {
582 let crate_type = if opt_present(matches, "lib") {
584 } else if opt_present(matches, "bin") {
587 session::unknown_crate
589 let parse_only = opt_present(matches, "parse-only");
590 let no_trans = opt_present(matches, "no-trans");
592 let lint_levels = [lint::allow, lint::warn,
593 lint::deny, lint::forbid];
594 let mut lint_opts = ~[];
595 let lint_dict = lint::get_lint_dict();
596 for lint_levels.iter().advance |level| {
597 let level_name = lint::level_to_str(*level);
599 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
600 // to_ascii_consume and to_str_consume to not do a unnecessary copy.
601 let level_short = level_name.slice_chars(0, 1);
602 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
603 let flags = vec::append(getopts::opt_strs(matches, level_short),
604 getopts::opt_strs(matches, level_name));
605 for flags.iter().advance |lint_name| {
606 let lint_name = lint_name.replace("-", "_");
607 match lint_dict.find_equiv(&lint_name) {
609 early_error(demitter, fmt!("unknown %s flag: %s",
610 level_name, lint_name));
613 lint_opts.push((lint.lint, *level));
619 let mut debugging_opts = 0u;
620 let debug_flags = getopts::opt_strs(matches, "Z");
621 let debug_map = session::debugging_opts_map();
622 for debug_flags.iter().advance |debug_flag| {
623 let mut this_bit = 0u;
624 for debug_map.iter().advance |tuple| {
625 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
626 if name == debug_flag { this_bit = bit; break; }
629 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
631 debugging_opts |= this_bit;
633 if debugging_opts & session::debug_llvm != 0 {
635 llvm::LLVMSetDebug(1);
640 if parse_only || no_trans {
641 link::output_type_none
642 } else if opt_present(matches, "S") &&
643 opt_present(matches, "emit-llvm") {
644 link::output_type_llvm_assembly
645 } else if opt_present(matches, "S") {
646 link::output_type_assembly
647 } else if opt_present(matches, "c") {
648 link::output_type_object
649 } else if opt_present(matches, "emit-llvm") {
650 link::output_type_bitcode
651 } else { link::output_type_exe };
652 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot");
653 let sysroot_opt = sysroot_opt.map(|m| @Path(*m));
654 let target_opt = getopts::opt_maybe_str(matches, "target");
655 let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
656 let save_temps = getopts::opt_present(matches, "save-temps");
658 if (debugging_opts & session::no_opt) != 0 {
660 } else if opt_present(matches, "O") {
661 if opt_present(matches, "opt-level") {
662 early_error(demitter, ~"-O and --opt-level both provided");
665 } else if opt_present(matches, "opt-level") {
666 match getopts::opt_str(matches, "opt-level") {
672 early_error(demitter, ~"optimization level needs to be between 0-3")
677 let gc = debugging_opts & session::gc != 0;
678 let jit = debugging_opts & session::jit != 0;
679 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
680 let debuginfo = debugging_opts & session::debug_info != 0 ||
682 let statik = debugging_opts & session::statik != 0;
685 None => host_triple(),
688 let target_feature = match target_feature_opt {
693 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
694 let linker = getopts::opt_maybe_str(matches, "linker");
695 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
696 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
699 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
700 let test = opt_present(matches, "test");
701 let android_cross_path = getopts::opt_maybe_str(
702 matches, "android-cross-path");
704 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
707 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
713 let sopts = @session::options {
714 crate_type: crate_type,
718 custom_passes: custom_passes,
719 debuginfo: debuginfo,
720 extra_debuginfo: extra_debuginfo,
721 lint_opts: lint_opts,
722 save_temps: save_temps,
724 output_type: output_type,
725 addl_lib_search_paths: @mut addl_lib_search_paths,
727 linker_args: linker_args,
728 maybe_sysroot: sysroot_opt,
729 target_triple: target,
730 target_feature: target_feature,
734 parse_only: parse_only,
736 debugging_opts: debugging_opts,
737 android_cross_path: android_cross_path
742 pub fn build_session(sopts: @session::options,
743 demitter: diagnostic::Emitter) -> Session {
744 let codemap = @codemap::CodeMap::new();
745 let diagnostic_handler =
746 diagnostic::mk_handler(Some(demitter));
747 let span_diagnostic_handler =
748 diagnostic::mk_span_handler(diagnostic_handler, codemap);
749 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
752 pub fn build_session_(sopts: @session::options,
753 cm: @codemap::CodeMap,
754 demitter: diagnostic::Emitter,
755 span_diagnostic_handler: @diagnostic::span_handler)
757 let target_cfg = build_target_config(sopts, demitter);
758 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
760 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
761 let filesearch = filesearch::mk_filesearch(
762 &sopts.maybe_sysroot,
764 sopts.addl_lib_search_paths);
766 targ_cfg: target_cfg,
771 // For a library crate, this is always none
773 entry_type: @mut None,
774 span_diagnostic: span_diagnostic_handler,
775 filesearch: filesearch,
776 building_library: @mut false,
777 working_dir: os::getcwd(),
778 lints: @mut HashMap::new(),
782 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
784 &"normal" => ppm_normal,
785 &"expanded" => ppm_expanded,
786 &"typed" => ppm_typed,
787 &"expanded,identified" => ppm_expanded_identified,
788 &"identified" => ppm_identified,
790 sess.fatal("argument to `pretty` must be one of `normal`, \
791 `expanded`, `typed`, `identified`, \
792 or `expanded,identified`");
797 // rustc command line options
798 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
800 optflag("", "bin", "Compile an executable crate (default)"),
801 optflag("c", "", "Compile and assemble, but do not link"),
802 optmulti("", "cfg", "Configure the compilation
803 environment", "SPEC"),
804 optflag("", "emit-llvm",
805 "Produce an LLVM bitcode file"),
806 optflag("h", "help","Display this message"),
807 optmulti("L", "", "Add a directory to the library search path",
809 optflag("", "lib", "Compile a library crate"),
810 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
811 optmulti("", "link-args", "FLAGS is a space-separated list of flags
812 passed to the linker", "FLAGS"),
813 optflag("", "ls", "List the symbols defined by a library crate"),
814 optflag("", "no-trans",
815 "Run all passes except translation; no output"),
816 optflag("O", "", "Equivalent to --opt-level=2"),
817 optopt("o", "", "Write output to <filename>", "FILENAME"),
818 optopt("", "opt-level",
819 "Optimize with possible levels 0-3", "LEVEL"),
820 optopt("", "passes", "Comma or space separated list of pass names to use. \
821 Overrides the default passes for optimization levels,\n\
822 a value of \"list\" will list the available passes.", "NAMES"),
823 optopt( "", "out-dir",
824 "Write output to compiler-chosen filename
826 optflag("", "parse-only",
827 "Parse only; do not compile, assemble, or link"),
828 optflagopt("", "pretty",
829 "Pretty-print the input instead of compiling;
830 valid types are: normal (un-annotated source),
831 expanded (crates expanded),
832 typed (crates expanded, with type annotations),
833 or identified (fully parenthesized,
834 AST nodes and blocks with IDs)", "TYPE"),
835 optflag("S", "", "Compile only; do not assemble or link"),
836 optflag("", "save-temps",
837 "Write intermediate files (.bc, .opt.bc, .o)
838 in addition to normal output"),
839 optopt("", "sysroot",
840 "Override the system root", "PATH"),
841 optflag("", "test", "Build a test harness"),
843 "Target triple cpu-manufacturer-kernel[-os]
844 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
845 for detail)", "TRIPLE"),
846 optopt("", "target-feature",
847 "Target specific attributes (llc -mattr=help
848 for detail)", "FEATURE"),
849 optopt("", "android-cross-path",
850 "The path to the Android NDK", "PATH"),
851 optflagopt("W", "warn",
852 "Set lint warnings", "OPT"),
853 optmulti("A", "allow",
854 "Set lint allowed", "OPT"),
855 optmulti("D", "deny",
856 "Set lint denied", "OPT"),
857 optmulti("F", "forbid",
858 "Set lint forbidden", "OPT"),
859 optmulti("Z", "", "Set internal debugging options", "FLAG"),
860 optflag( "v", "version",
861 "Print version info and exit"),
865 pub struct OutputFilenames {
870 pub fn build_output_filenames(input: &input,
872 ofile: &Option<Path>,
873 attrs: &[ast::attribute],
875 -> @OutputFilenames {
878 let sopts = sess.opts;
879 let stop_after_codegen =
880 sopts.output_type != link::output_type_exe ||
881 sopts.is_static && *sess.building_library;
884 match sopts.output_type {
885 link::output_type_none => ~"none",
886 link::output_type_bitcode => ~"bc",
887 link::output_type_assembly => ~"s",
888 link::output_type_llvm_assembly => ~"ll",
889 // Object and exe output both use the '.o' extension here
890 link::output_type_object | link::output_type_exe => ~"o"
895 // "-" as input file will cause the parser to read from stdin so we
896 // have to make up a name
897 // We want to toss everything after the final '.'
898 let dirpath = match *odir {
899 Some(ref d) => (*d).clone(),
900 None => match *input {
901 str_input(_) => os::getcwd(),
902 file_input(ref ifile) => (*ifile).dir_path()
906 let mut stem = match *input {
907 file_input(ref ifile) => (*ifile).filestem().get().to_managed(),
908 str_input(_) => @"rust_out"
911 // If a linkage name meta is present, we use it as the link name
912 let linkage_metas = attr::find_linkage_metas(attrs);
913 if !linkage_metas.is_empty() {
914 // But if a linkage meta is present, that overrides
915 let maybe_matches = attr::find_meta_items_by_name(linkage_metas, "name");
916 if !maybe_matches.is_empty() {
917 match attr::get_meta_item_value_str(maybe_matches[0]) {
922 // If the name is missing, we just default to the filename
926 if *sess.building_library {
927 out_path = dirpath.push(os::dll_filename(stem));
928 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
930 out_path = dirpath.push(stem);
931 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
935 Some(ref out_file) => {
936 out_path = (*out_file).clone();
937 obj_path = if stop_after_codegen {
940 (*out_file).with_filetype(obj_suffix)
943 if *sess.building_library {
944 // FIXME (#2401): We might want to warn here; we're actually not
945 // going to respect the user's choice of library name when it
946 // comes time to link, we'll be linking to
947 // lib<basename>-<hash>-<version>.so no matter what.
951 sess.warn("ignoring --out-dir flag due to -o flag.");
957 out_filename: out_path,
958 obj_filename: obj_path
962 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
963 emitter(None, msg, diagnostic::fatal);
967 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
968 metadata::loader::list_file_metadata(
969 token::get_ident_interner(),
970 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
976 use driver::driver::{build_configuration, build_session};
977 use driver::driver::{build_session_options, optgroups, str_input};
979 use extra::getopts::groups::getopts;
982 use syntax::diagnostic;
984 // When the user supplies --test we should implicitly supply --cfg test
986 fn test_switch_implies_cfg_test() {
988 &match getopts([~"--test"], optgroups()) {
990 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
992 let sessopts = build_session_options(
993 @"rustc", matches, diagnostic::emit);
994 let sess = build_session(sessopts, diagnostic::emit);
995 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
996 assert!((attr::contains_name(cfg, "test")));
999 // When the user supplies --test and --cfg test, don't implicitly add
1000 // another --cfg test
1002 fn test_switch_implies_cfg_test_unless_cfg_test() {
1004 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1007 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1010 let sessopts = build_session_options(
1011 @"rustc", matches, diagnostic::emit);
1012 let sess = build_session(sessopts, diagnostic::emit);
1013 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1014 let test_items = attr::find_meta_items_by_name(cfg, "test");
1015 assert_eq!(test_items.len(), 1u);