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) ->
70 let tos = match sess.targ_cfg.os {
71 session::os_win32 => @"win32",
72 session::os_macos => @"macos",
73 session::os_linux => @"linux",
74 session::os_android => @"android",
75 session::os_freebsd => @"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),
98 pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
99 if !cfg.iter().any(|mi| mi.name() == name) {
100 cfg.push(attr::mk_word_item(name))
104 pub fn build_configuration(sess: Session) ->
106 // Combine the configuration requested by the session (command line) with
107 // some default and generated configuration items
108 let default_cfg = default_configuration(sess);
109 let mut user_cfg = sess.opts.cfg.clone();
110 // If the user wants a test runner, then add the test cfg
111 if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
112 // If the user requested GC, then add the GC cfg
113 append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
114 return vec::append(user_cfg, default_cfg);
117 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
118 fn parse_cfgspecs(cfgspecs: ~[~str],
119 demitter: diagnostic::Emitter) -> ast::CrateConfig {
120 do cfgspecs.move_iter().map |s| {
121 let sess = parse::new_parse_sess(Some(demitter));
122 parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
123 }.collect::<ast::CrateConfig>()
127 /// Load source from file
129 /// The string is the source
130 // FIXME (#2319): Don't really want to box the source string
134 pub fn phase_1_parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
136 time(sess.time_passes(), ~"parsing", || {
138 file_input(ref file) => {
139 parse::parse_crate_from_file(&(*file), cfg.clone(), sess.parse_sess)
142 parse::parse_crate_from_source_str(
143 anon_src(), src, cfg.clone(), sess.parse_sess)
149 // For continuing compilation after a parsed crate has been
152 /// Run the "early phases" of the compiler: initial `cfg` processing,
153 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
154 /// harness if one is to be provided and injection of a dependency on the
155 /// standard library and prelude.
156 pub fn phase_2_configure_and_expand(sess: Session,
157 cfg: ast::CrateConfig,
158 mut crate: @ast::Crate) -> @ast::Crate {
159 let time_passes = sess.time_passes();
161 *sess.building_library = session::building_library(sess.opts.crate_type,
162 crate, sess.opts.test);
165 // strip before expansion to allow macros to depend on
166 // configuration variables e.g/ in
168 // #[macro_escape] #[cfg(foo)]
169 // mod bar { macro_rules! baz!(() => {{}}) }
171 // baz! should not use this definition unless foo is enabled.
172 crate = time(time_passes, ~"std macros injection", ||
173 syntax::ext::expand::inject_std_macros(sess.parse_sess,
177 crate = time(time_passes, ~"configuration 1", ||
178 front::config::strip_unconfigured_items(crate));
180 crate = time(time_passes, ~"expansion", ||
181 syntax::ext::expand::expand_crate(sess.parse_sess, cfg.clone(),
184 // strip again, in case expansion added anything with a #[cfg].
185 crate = time(time_passes, ~"configuration 2", ||
186 front::config::strip_unconfigured_items(crate));
188 crate = time(time_passes, ~"maybe building test harness", ||
189 front::test::modify_for_testing(sess, crate));
191 crate = time(time_passes, ~"std injection", ||
192 front::std_inject::maybe_inject_libstd_ref(sess, crate));
197 pub struct CrateAnalysis {
198 exp_map2: middle::resolve::ExportMap2,
200 maps: astencode::Maps,
201 reachable: @mut HashSet<ast::NodeId>
204 /// Run the resolution, typechecking, region checking and other
205 /// miscellaneous analysis passes on the crate. Return various
206 /// structures carrying the results of the analysis.
207 pub fn phase_3_run_analysis_passes(sess: Session,
208 crate: @ast::Crate) -> CrateAnalysis {
210 let time_passes = sess.time_passes();
211 let ast_map = time(time_passes, ~"ast indexing", ||
212 syntax::ast_map::map_crate(sess.diagnostic(), crate));
214 time(time_passes, ~"external crate/lib resolution", ||
215 creader::read_crates(sess.diagnostic(), crate, sess.cstore,
217 session::sess_os_to_meta_os(sess.targ_cfg.os),
219 token::get_ident_interner()));
221 let lang_items = time(time_passes, ~"language item collection", ||
222 middle::lang_items::collect_language_items(crate, sess));
224 let middle::resolve::CrateMap {
229 time(time_passes, ~"resolution", ||
230 middle::resolve::resolve_crate(sess, lang_items, crate));
232 time(time_passes, ~"looking for entry point",
233 || middle::entry::find_entry_point(sess, crate, ast_map));
235 let freevars = time(time_passes, ~"freevar finding", ||
236 freevars::annotate_freevars(def_map, crate));
238 let region_map = time(time_passes, ~"region resolution", ||
239 middle::region::resolve_crate(sess, def_map, crate));
241 let rp_set = time(time_passes, ~"region parameterization inference", ||
242 middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
244 let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
245 region_map, rp_set, lang_items);
247 // passes are timed inside typeck
248 let (method_map, vtable_map) = typeck::check_crate(
249 ty_cx, trait_map, crate);
251 // These next two const passes can probably be merged
252 time(time_passes, ~"const marking", ||
253 middle::const_eval::process_crate(crate, ty_cx));
255 time(time_passes, ~"const checking", ||
256 middle::check_const::check_crate(sess, crate, ast_map, def_map,
259 time(time_passes, ~"privacy checking", ||
260 middle::privacy::check_crate(ty_cx, &method_map, crate));
262 time(time_passes, ~"effect checking", ||
263 middle::effect::check_crate(ty_cx, method_map, crate));
265 time(time_passes, ~"loop checking", ||
266 middle::check_loop::check_crate(ty_cx, crate));
268 time(time_passes, ~"stack checking", ||
269 middle::stack_check::stack_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
581 pub fn host_triple() -> ~str {
582 // Get the host triple out of the build environment. This ensures that our
583 // idea of the host triple is the same as for the set of libraries we've
584 // actually built. We can't just take LLVM's host triple because they
585 // normalize all ix86 architectures to i386.
587 // Instead of grabbing the host triple (for the current host), we grab (at
588 // compile time) the target triple that this rustc is built with and
589 // calling that (at runtime) the host triple.
590 (env!("CFG_COMPILER_TRIPLE")).to_owned()
593 pub fn build_session_options(binary: @str,
594 matches: &getopts::Matches,
595 demitter: diagnostic::Emitter)
596 -> @session::options {
597 let crate_type = if opt_present(matches, "lib") {
599 } else if opt_present(matches, "bin") {
602 session::unknown_crate
604 let parse_only = opt_present(matches, "parse-only");
605 let no_trans = opt_present(matches, "no-trans");
607 let lint_levels = [lint::allow, lint::warn,
608 lint::deny, lint::forbid];
609 let mut lint_opts = ~[];
610 let lint_dict = lint::get_lint_dict();
611 for level in lint_levels.iter() {
612 let level_name = lint::level_to_str(*level);
614 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
615 // to_ascii_move and to_str_move to not do a unnecessary copy.
616 let level_short = level_name.slice_chars(0, 1);
617 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
618 let flags = vec::append(getopts::opt_strs(matches, level_short),
619 getopts::opt_strs(matches, level_name));
620 for lint_name in flags.iter() {
621 let lint_name = lint_name.replace("-", "_");
622 match lint_dict.find_equiv(&lint_name) {
624 early_error(demitter, fmt!("unknown %s flag: %s",
625 level_name, lint_name));
628 lint_opts.push((lint.lint, *level));
634 let mut debugging_opts = 0u;
635 let debug_flags = getopts::opt_strs(matches, "Z");
636 let debug_map = session::debugging_opts_map();
637 for debug_flag in debug_flags.iter() {
638 let mut this_bit = 0u;
639 for tuple in debug_map.iter() {
640 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
641 if name == debug_flag { this_bit = bit; break; }
644 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
646 debugging_opts |= this_bit;
649 if debugging_opts & session::debug_llvm != 0 {
652 fn set_llvm_debug() {
653 #[fixed_stack_segment]; #[inline(never)];
654 unsafe { llvm::LLVMSetDebug(1); }
659 if parse_only || no_trans {
660 link::output_type_none
661 } else if opt_present(matches, "S") &&
662 opt_present(matches, "emit-llvm") {
663 link::output_type_llvm_assembly
664 } else if opt_present(matches, "S") {
665 link::output_type_assembly
666 } else if opt_present(matches, "c") {
667 link::output_type_object
668 } else if opt_present(matches, "emit-llvm") {
669 link::output_type_bitcode
670 } else { link::output_type_exe };
671 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot").map_move(|m| @Path(m));
672 let target = getopts::opt_maybe_str(matches, "target").unwrap_or_default(host_triple());
673 let target_cpu = getopts::opt_maybe_str(matches, "target-cpu").unwrap_or_default(~"generic");
674 let target_feature = getopts::opt_maybe_str(matches, "target-feature").unwrap_or_default(~"");
675 let save_temps = getopts::opt_present(matches, "save-temps");
677 if (debugging_opts & session::no_opt) != 0 {
679 } else if opt_present(matches, "O") {
680 if opt_present(matches, "opt-level") {
681 early_error(demitter, ~"-O and --opt-level both provided");
684 } else if opt_present(matches, "opt-level") {
685 match getopts::opt_str(matches, "opt-level") {
691 early_error(demitter, ~"optimization level needs to be between 0-3")
696 let gc = debugging_opts & session::gc != 0;
697 let jit = debugging_opts & session::jit != 0;
698 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
699 let debuginfo = debugging_opts & session::debug_info != 0 ||
702 // If debugging info is generated, do not collapse monomorphized function instances.
703 // Functions with equivalent llvm code still need separate debugging descriptions because names
706 debugging_opts |= session::no_monomorphic_collapse;
709 let statik = debugging_opts & session::statik != 0;
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(' ').map(|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 == ',').map(|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_cpu: target_cpu,
749 target_feature: target_feature,
753 parse_only: parse_only,
755 debugging_opts: debugging_opts,
756 android_cross_path: android_cross_path
761 pub fn build_session(sopts: @session::options,
762 demitter: diagnostic::Emitter) -> Session {
763 let codemap = @codemap::CodeMap::new();
764 let diagnostic_handler =
765 diagnostic::mk_handler(Some(demitter));
766 let span_diagnostic_handler =
767 diagnostic::mk_span_handler(diagnostic_handler, codemap);
768 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
771 pub fn build_session_(sopts: @session::options,
772 cm: @codemap::CodeMap,
773 demitter: diagnostic::Emitter,
774 span_diagnostic_handler: @mut diagnostic::span_handler)
776 let target_cfg = build_target_config(sopts, demitter);
777 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
779 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
780 let filesearch = filesearch::mk_filesearch(
781 &sopts.maybe_sysroot,
783 sopts.addl_lib_search_paths);
785 targ_cfg: target_cfg,
790 // For a library crate, this is always none
792 entry_type: @mut None,
793 span_diagnostic: span_diagnostic_handler,
794 filesearch: filesearch,
795 building_library: @mut false,
796 working_dir: os::getcwd(),
797 lints: @mut HashMap::new(),
801 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
803 &"normal" => ppm_normal,
804 &"expanded" => ppm_expanded,
805 &"typed" => ppm_typed,
806 &"expanded,identified" => ppm_expanded_identified,
807 &"identified" => ppm_identified,
809 sess.fatal("argument to `pretty` must be one of `normal`, \
810 `expanded`, `typed`, `identified`, \
811 or `expanded,identified`");
816 // rustc command line options
817 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
819 optflag("", "bin", "Compile an executable crate (default)"),
820 optflag("c", "", "Compile and assemble, but do not link"),
821 optmulti("", "cfg", "Configure the compilation
822 environment", "SPEC"),
823 optflag("", "emit-llvm",
824 "Produce an LLVM assembly file if used with -S option;
825 produce an LLVM bitcode file otherwise"),
826 optflag("h", "help","Display this message"),
827 optmulti("L", "", "Add a directory to the library search path",
829 optflag("", "lib", "Compile a library crate"),
830 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
831 optmulti("", "link-args", "FLAGS is a space-separated list of flags
832 passed to the linker", "FLAGS"),
833 optflag("", "ls", "List the symbols defined by a library crate"),
834 optflag("", "no-trans",
835 "Run all passes except translation; no output"),
836 optflag("O", "", "Equivalent to --opt-level=2"),
837 optopt("o", "", "Write output to <filename>", "FILENAME"),
838 optopt("", "opt-level",
839 "Optimize with possible levels 0-3", "LEVEL"),
840 optopt("", "passes", "Comma or space separated list of pass names to use. \
841 Overrides the default passes for optimization levels,\n\
842 a value of \"list\" will list the available passes.", "NAMES"),
843 optopt( "", "out-dir",
844 "Write output to compiler-chosen filename
846 optflag("", "parse-only",
847 "Parse only; do not compile, assemble, or link"),
848 optflagopt("", "pretty",
849 "Pretty-print the input instead of compiling;
850 valid types are: normal (un-annotated source),
851 expanded (crates expanded),
852 typed (crates expanded, with type annotations),
853 or identified (fully parenthesized,
854 AST nodes and blocks with IDs)", "TYPE"),
855 optflag("S", "", "Compile only; do not assemble or link"),
856 optflag("", "save-temps",
857 "Write intermediate files (.bc, .opt.bc, .o)
858 in addition to normal output"),
859 optopt("", "sysroot",
860 "Override the system root", "PATH"),
861 optflag("", "test", "Build a test harness"),
863 "Target triple cpu-manufacturer-kernel[-os]
864 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
865 for details)", "TRIPLE"),
866 optopt("", "target-cpu",
867 "Select target processor (llc -mcpu=help
868 for details)", "CPU"),
869 optopt("", "target-feature",
870 "Target specific attributes (llc -mattr=help
871 for details)", "FEATURE"),
872 optopt("", "android-cross-path",
873 "The path to the Android NDK", "PATH"),
874 optflagopt("W", "warn",
875 "Set lint warnings", "OPT"),
876 optmulti("A", "allow",
877 "Set lint allowed", "OPT"),
878 optmulti("D", "deny",
879 "Set lint denied", "OPT"),
880 optmulti("F", "forbid",
881 "Set lint forbidden", "OPT"),
882 optmulti("Z", "", "Set internal debugging options", "FLAG"),
883 optflag( "v", "version",
884 "Print version info and exit"),
888 pub struct OutputFilenames {
893 pub fn build_output_filenames(input: &input,
895 ofile: &Option<Path>,
896 attrs: &[ast::Attribute],
898 -> ~OutputFilenames {
901 let sopts = sess.opts;
902 let stop_after_codegen =
903 sopts.output_type != link::output_type_exe ||
904 sopts.is_static && *sess.building_library;
907 match sopts.output_type {
908 link::output_type_none => ~"none",
909 link::output_type_bitcode => ~"bc",
910 link::output_type_assembly => ~"s",
911 link::output_type_llvm_assembly => ~"ll",
912 // Object and exe output both use the '.o' extension here
913 link::output_type_object | link::output_type_exe => ~"o"
918 // "-" as input file will cause the parser to read from stdin so we
919 // have to make up a name
920 // We want to toss everything after the final '.'
921 let dirpath = match *odir {
922 Some(ref d) => (*d).clone(),
923 None => match *input {
924 str_input(_) => os::getcwd(),
925 file_input(ref ifile) => (*ifile).dir_path()
929 let mut stem = match *input {
930 file_input(ref ifile) => (*ifile).filestem().unwrap().to_managed(),
931 str_input(_) => @"rust_out"
934 // If a linkage name meta is present, we use it as the link name
935 let linkage_metas = attr::find_linkage_metas(attrs);
936 if !linkage_metas.is_empty() {
937 // But if a linkage meta is present, that overrides
938 let maybe_name = linkage_metas.iter().find(|m| "name" == m.name());
939 match maybe_name.chain(|m| m.value_str()) {
943 // If the name is missing, we just default to the filename
947 if *sess.building_library {
948 out_path = dirpath.push(os::dll_filename(stem));
949 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
951 out_path = dirpath.push(stem);
952 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
956 Some(ref out_file) => {
957 out_path = (*out_file).clone();
958 obj_path = if stop_after_codegen {
961 (*out_file).with_filetype(obj_suffix)
964 if *sess.building_library {
965 sess.warn("ignoring specified output filename for library.");
969 sess.warn("ignoring --out-dir flag due to -o flag.");
975 out_filename: out_path,
976 obj_filename: obj_path
980 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
981 emitter(None, msg, diagnostic::fatal);
985 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
986 metadata::loader::list_file_metadata(
987 token::get_ident_interner(),
988 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
994 use driver::driver::{build_configuration, build_session};
995 use driver::driver::{build_session_options, optgroups};
997 use extra::getopts::groups::getopts;
1000 use syntax::diagnostic;
1002 // When the user supplies --test we should implicitly supply --cfg test
1004 fn test_switch_implies_cfg_test() {
1006 &match getopts([~"--test"], optgroups()) {
1008 Err(f) => fail!("test_switch_implies_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);
1014 assert!((attr::contains_name(cfg, "test")));
1017 // When the user supplies --test and --cfg test, don't implicitly add
1018 // another --cfg test
1020 fn test_switch_implies_cfg_test_unless_cfg_test() {
1022 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1025 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1028 let sessopts = build_session_options(
1029 @"rustc", matches, diagnostic::emit);
1030 let sess = build_session(sessopts, diagnostic::emit);
1031 let cfg = build_configuration(sess);
1032 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1033 assert!(test_items.next().is_some());
1034 assert!(test_items.next().is_none());