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 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.arch == abi::Arm &&
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 let outputs = build_output_filenames(input, outdir, output, [], sess);
412 // We need nested scopes here, because the intermediate results can keep
413 // large chunks of memory alive and we want to free them as soon as
414 // possible to keep the peak memory usage low
416 let expanded_crate = {
417 let crate = phase_1_parse_input(sess, cfg.clone(), input);
418 if stop_after_phase_1(sess) { return; }
419 phase_2_configure_and_expand(sess, cfg, crate)
421 let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
422 if stop_after_phase_3(sess) { return; }
423 phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs)
425 phase_5_run_llvm_passes(sess, &trans, outputs);
426 if stop_after_phase_5(sess) { return; }
427 phase_6_link_output(sess, &trans, outputs);
430 pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
433 fn ann_paren_for_expr(node: pprust::ann_node) {
435 pprust::node_expr(s, _) => pprust::popen(s),
439 fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
441 pprust::node_expr(s, expr) => {
445 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
451 fn ann_identified_post(node: pprust::ann_node) {
453 pprust::node_item(s, item) => {
455 pprust::synth_comment(s, int::to_str(item.id));
457 pprust::node_block(s, ref blk) => {
459 pprust::synth_comment(
460 s, ~"block " + int::to_str(blk.id));
462 pprust::node_expr(s, expr) => {
464 pprust::synth_comment(s, int::to_str(expr.id));
467 pprust::node_pat(s, pat) => {
469 pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
474 let crate = phase_1_parse_input(sess, cfg.clone(), input);
476 let (crate, is_expanded) = match ppm {
477 ppm_expanded | ppm_expanded_identified | ppm_typed => {
478 (phase_2_configure_and_expand(sess, cfg, crate), true)
483 let annotation = match ppm {
484 ppm_identified | ppm_expanded_identified => {
486 pre: ann_paren_for_expr,
487 post: ann_identified_post
491 let analysis = phase_3_run_analysis_passes(sess, crate);
493 pre: ann_paren_for_expr,
494 post: |a| ann_typed_post(analysis.ty_cx, a)
497 _ => pprust::no_ann()
500 let src = sess.codemap.get_filemap(source_name(input)).src;
501 do io::with_str_reader(src) |rdr| {
502 pprust::print_crate(sess.codemap, token::get_ident_interner(),
503 sess.span_diagnostic, crate,
506 annotation, is_expanded);
510 pub fn get_os(triple: &str) -> Option<session::os> {
511 for os_names.iter().advance |&(name, os)| {
512 if triple.contains(name) { return Some(os) }
516 static os_names : &'static [(&'static str, session::os)] = &'static [
517 ("mingw32", session::os_win32),
518 ("win32", session::os_win32),
519 ("darwin", session::os_macos),
520 ("android", session::os_android),
521 ("linux", session::os_linux),
522 ("freebsd", session::os_freebsd)];
524 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
525 for architecture_abis.iter().advance |&(arch, abi)| {
526 if triple.contains(arch) { return Some(abi) }
530 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
537 ("x86_64", abi::X86_64),
540 ("xscale", abi::Arm),
542 ("mips", abi::Mips)];
544 pub fn build_target_config(sopts: @session::options,
545 demitter: diagnostic::Emitter)
546 -> @session::config {
547 let os = match get_os(sopts.target_triple) {
549 None => early_error(demitter, ~"unknown operating system")
551 let arch = match get_arch(sopts.target_triple) {
553 None => early_error(demitter,
554 ~"unknown architecture: " + sopts.target_triple)
556 let (int_type, uint_type, float_type) = match arch {
557 abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
558 abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
559 abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
560 abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
562 let target_strs = match arch {
563 abi::X86 => x86::get_target_strs(os),
564 abi::X86_64 => x86_64::get_target_strs(os),
565 abi::Arm => arm::get_target_strs(os),
566 abi::Mips => mips::get_target_strs(os)
568 let target_cfg = @session::config {
571 target_strs: target_strs,
573 uint_type: uint_type,
574 float_type: float_type
579 pub fn host_triple() -> ~str {
580 // Get the host triple out of the build environment. This ensures that our
581 // idea of the host triple is the same as for the set of libraries we've
582 // actually built. We can't just take LLVM's host triple because they
583 // normalize all ix86 architectures to i386.
585 // Instead of grabbing the host triple (for the current host), we grab (at
586 // compile time) the target triple that this rustc is built with and
587 // calling that (at runtime) the host triple.
588 let ht = env!("CFG_COMPILER_TRIPLE");
592 fail!("rustc built without CFG_COMPILER_TRIPLE")
596 pub fn build_session_options(binary: @str,
597 matches: &getopts::Matches,
598 demitter: diagnostic::Emitter)
599 -> @session::options {
600 let crate_type = if opt_present(matches, "lib") {
602 } else if opt_present(matches, "bin") {
605 session::unknown_crate
607 let parse_only = opt_present(matches, "parse-only");
608 let no_trans = opt_present(matches, "no-trans");
610 let lint_levels = [lint::allow, lint::warn,
611 lint::deny, lint::forbid];
612 let mut lint_opts = ~[];
613 let lint_dict = lint::get_lint_dict();
614 for lint_levels.iter().advance |level| {
615 let level_name = lint::level_to_str(*level);
617 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
618 // to_ascii_consume and to_str_consume to not do a unnecessary copy.
619 let level_short = level_name.slice_chars(0, 1);
620 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
621 let flags = vec::append(getopts::opt_strs(matches, level_short),
622 getopts::opt_strs(matches, level_name));
623 for flags.iter().advance |lint_name| {
624 let lint_name = lint_name.replace("-", "_");
625 match lint_dict.find_equiv(&lint_name) {
627 early_error(demitter, fmt!("unknown %s flag: %s",
628 level_name, lint_name));
631 lint_opts.push((lint.lint, *level));
637 let mut debugging_opts = 0u;
638 let debug_flags = getopts::opt_strs(matches, "Z");
639 let debug_map = session::debugging_opts_map();
640 for debug_flags.iter().advance |debug_flag| {
641 let mut this_bit = 0u;
642 for debug_map.iter().advance |tuple| {
643 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
644 if name == debug_flag { this_bit = bit; break; }
647 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
649 debugging_opts |= this_bit;
651 if debugging_opts & session::debug_llvm != 0 {
653 llvm::LLVMSetDebug(1);
658 if parse_only || no_trans {
659 link::output_type_none
660 } else if opt_present(matches, "S") &&
661 opt_present(matches, "emit-llvm") {
662 link::output_type_llvm_assembly
663 } else if opt_present(matches, "S") {
664 link::output_type_assembly
665 } else if opt_present(matches, "c") {
666 link::output_type_object
667 } else if opt_present(matches, "emit-llvm") {
668 link::output_type_bitcode
669 } else { link::output_type_exe };
670 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot");
671 let sysroot_opt = sysroot_opt.map(|m| @Path(*m));
672 let target_opt = getopts::opt_maybe_str(matches, "target");
673 let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
674 let save_temps = getopts::opt_present(matches, "save-temps");
676 if (debugging_opts & session::no_opt) != 0 {
678 } else if opt_present(matches, "O") {
679 if opt_present(matches, "opt-level") {
680 early_error(demitter, ~"-O and --opt-level both provided");
683 } else if opt_present(matches, "opt-level") {
684 match getopts::opt_str(matches, "opt-level") {
690 early_error(demitter, ~"optimization level needs to be between 0-3")
695 let gc = debugging_opts & session::gc != 0;
696 let jit = debugging_opts & session::jit != 0;
697 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
698 let debuginfo = debugging_opts & session::debug_info != 0 ||
700 let statik = debugging_opts & session::statik != 0;
703 None => host_triple(),
706 let target_feature = match target_feature_opt {
711 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
712 let linker = getopts::opt_maybe_str(matches, "linker");
713 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
714 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
717 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
718 let test = opt_present(matches, "test");
719 let android_cross_path = getopts::opt_maybe_str(
720 matches, "android-cross-path");
722 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
725 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
731 let sopts = @session::options {
732 crate_type: crate_type,
736 custom_passes: custom_passes,
737 debuginfo: debuginfo,
738 extra_debuginfo: extra_debuginfo,
739 lint_opts: lint_opts,
740 save_temps: save_temps,
742 output_type: output_type,
743 addl_lib_search_paths: @mut addl_lib_search_paths,
745 linker_args: linker_args,
746 maybe_sysroot: sysroot_opt,
747 target_triple: target,
748 target_feature: target_feature,
752 parse_only: parse_only,
754 debugging_opts: debugging_opts,
755 android_cross_path: android_cross_path
760 pub fn build_session(sopts: @session::options,
761 demitter: diagnostic::Emitter) -> Session {
762 let codemap = @codemap::CodeMap::new();
763 let diagnostic_handler =
764 diagnostic::mk_handler(Some(demitter));
765 let span_diagnostic_handler =
766 diagnostic::mk_span_handler(diagnostic_handler, codemap);
767 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
770 pub fn build_session_(sopts: @session::options,
771 cm: @codemap::CodeMap,
772 demitter: diagnostic::Emitter,
773 span_diagnostic_handler: @diagnostic::span_handler)
775 let target_cfg = build_target_config(sopts, demitter);
776 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
778 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
779 let filesearch = filesearch::mk_filesearch(
780 &sopts.maybe_sysroot,
782 sopts.addl_lib_search_paths);
784 targ_cfg: target_cfg,
789 // For a library crate, this is always none
791 entry_type: @mut None,
792 span_diagnostic: span_diagnostic_handler,
793 filesearch: filesearch,
794 building_library: @mut false,
795 working_dir: os::getcwd(),
796 lints: @mut HashMap::new(),
800 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
802 &"normal" => ppm_normal,
803 &"expanded" => ppm_expanded,
804 &"typed" => ppm_typed,
805 &"expanded,identified" => ppm_expanded_identified,
806 &"identified" => ppm_identified,
808 sess.fatal("argument to `pretty` must be one of `normal`, \
809 `expanded`, `typed`, `identified`, \
810 or `expanded,identified`");
815 // rustc command line options
816 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
818 optflag("", "bin", "Compile an executable crate (default)"),
819 optflag("c", "", "Compile and assemble, but do not link"),
820 optmulti("", "cfg", "Configure the compilation
821 environment", "SPEC"),
822 optflag("", "emit-llvm",
823 "Produce an LLVM bitcode file"),
824 optflag("h", "help","Display this message"),
825 optmulti("L", "", "Add a directory to the library search path",
827 optflag("", "lib", "Compile a library crate"),
828 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
829 optmulti("", "link-args", "FLAGS is a space-separated list of flags
830 passed to the linker", "FLAGS"),
831 optflag("", "ls", "List the symbols defined by a library crate"),
832 optflag("", "no-trans",
833 "Run all passes except translation; no output"),
834 optflag("O", "", "Equivalent to --opt-level=2"),
835 optopt("o", "", "Write output to <filename>", "FILENAME"),
836 optopt("", "opt-level",
837 "Optimize with possible levels 0-3", "LEVEL"),
838 optopt("", "passes", "Comma or space separated list of pass names to use. \
839 Overrides the default passes for optimization levels,\n\
840 a value of \"list\" will list the available passes.", "NAMES"),
841 optopt( "", "out-dir",
842 "Write output to compiler-chosen filename
844 optflag("", "parse-only",
845 "Parse only; do not compile, assemble, or link"),
846 optflagopt("", "pretty",
847 "Pretty-print the input instead of compiling;
848 valid types are: normal (un-annotated source),
849 expanded (crates expanded),
850 typed (crates expanded, with type annotations),
851 or identified (fully parenthesized,
852 AST nodes and blocks with IDs)", "TYPE"),
853 optflag("S", "", "Compile only; do not assemble or link"),
854 optflag("", "save-temps",
855 "Write intermediate files (.bc, .opt.bc, .o)
856 in addition to normal output"),
857 optopt("", "sysroot",
858 "Override the system root", "PATH"),
859 optflag("", "test", "Build a test harness"),
861 "Target triple cpu-manufacturer-kernel[-os]
862 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
863 for detail)", "TRIPLE"),
864 optopt("", "target-feature",
865 "Target specific attributes (llc -mattr=help
866 for detail)", "FEATURE"),
867 optopt("", "android-cross-path",
868 "The path to the Android NDK", "PATH"),
869 optflagopt("W", "warn",
870 "Set lint warnings", "OPT"),
871 optmulti("A", "allow",
872 "Set lint allowed", "OPT"),
873 optmulti("D", "deny",
874 "Set lint denied", "OPT"),
875 optmulti("F", "forbid",
876 "Set lint forbidden", "OPT"),
877 optmulti("Z", "", "Set internal debugging options", "FLAG"),
878 optflag( "v", "version",
879 "Print version info and exit"),
883 pub struct OutputFilenames {
888 pub fn build_output_filenames(input: &input,
890 ofile: &Option<Path>,
891 attrs: &[ast::Attribute],
893 -> ~OutputFilenames {
896 let sopts = sess.opts;
897 let stop_after_codegen =
898 sopts.output_type != link::output_type_exe ||
899 sopts.is_static && *sess.building_library;
902 match sopts.output_type {
903 link::output_type_none => ~"none",
904 link::output_type_bitcode => ~"bc",
905 link::output_type_assembly => ~"s",
906 link::output_type_llvm_assembly => ~"ll",
907 // Object and exe output both use the '.o' extension here
908 link::output_type_object | link::output_type_exe => ~"o"
913 // "-" as input file will cause the parser to read from stdin so we
914 // have to make up a name
915 // We want to toss everything after the final '.'
916 let dirpath = match *odir {
917 Some(ref d) => (*d).clone(),
918 None => match *input {
919 str_input(_) => os::getcwd(),
920 file_input(ref ifile) => (*ifile).dir_path()
924 let mut stem = match *input {
925 file_input(ref ifile) => (*ifile).filestem().get().to_managed(),
926 str_input(_) => @"rust_out"
929 // If a linkage name meta is present, we use it as the link name
930 let linkage_metas = attr::find_linkage_metas(attrs);
931 if !linkage_metas.is_empty() {
932 // But if a linkage meta is present, that overrides
933 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
934 match maybe_name.chain(|m| m.value_str()) {
938 // If the name is missing, we just default to the filename
942 if *sess.building_library {
943 out_path = dirpath.push(os::dll_filename(stem));
944 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
946 out_path = dirpath.push(stem);
947 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
951 Some(ref out_file) => {
952 out_path = (*out_file).clone();
953 obj_path = if stop_after_codegen {
956 (*out_file).with_filetype(obj_suffix)
959 if *sess.building_library {
960 // FIXME (#2401): We might want to warn here; we're actually not
961 // going to respect the user's choice of library name when it
962 // comes time to link, we'll be linking to
963 // lib<basename>-<hash>-<version>.so no matter what.
967 sess.warn("ignoring --out-dir flag due to -o flag.");
973 out_filename: out_path,
974 obj_filename: obj_path
978 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
979 emitter(None, msg, diagnostic::fatal);
983 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
984 metadata::loader::list_file_metadata(
985 token::get_ident_interner(),
986 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
992 use driver::driver::{build_configuration, build_session};
993 use driver::driver::{build_session_options, optgroups, str_input};
995 use extra::getopts::groups::getopts;
998 use syntax::diagnostic;
1000 // When the user supplies --test we should implicitly supply --cfg test
1002 fn test_switch_implies_cfg_test() {
1004 &match getopts([~"--test"], optgroups()) {
1006 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
1008 let sessopts = build_session_options(
1009 @"rustc", matches, diagnostic::emit);
1010 let sess = build_session(sessopts, diagnostic::emit);
1011 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1012 assert!((attr::contains_name(cfg, "test")));
1015 // When the user supplies --test and --cfg test, don't implicitly add
1016 // another --cfg test
1018 fn test_switch_implies_cfg_test_unless_cfg_test() {
1020 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1023 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1026 let sessopts = build_session_options(
1027 @"rustc", matches, diagnostic::emit);
1028 let sess = build_session(sessopts, diagnostic::emit);
1029 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1030 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1031 assert!(test_items.next().is_some());
1032 assert!(test_items.next().is_none());