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.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 let ht = env!("CFG_COMPILER_TRIPLE");
594 fail!("rustc built without CFG_COMPILER_TRIPLE")
598 pub fn build_session_options(binary: @str,
599 matches: &getopts::Matches,
600 demitter: diagnostic::Emitter)
601 -> @session::options {
602 let crate_type = if opt_present(matches, "lib") {
604 } else if opt_present(matches, "bin") {
607 session::unknown_crate
609 let parse_only = opt_present(matches, "parse-only");
610 let no_trans = opt_present(matches, "no-trans");
612 let lint_levels = [lint::allow, lint::warn,
613 lint::deny, lint::forbid];
614 let mut lint_opts = ~[];
615 let lint_dict = lint::get_lint_dict();
616 for level in lint_levels.iter() {
617 let level_name = lint::level_to_str(*level);
619 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
620 // to_ascii_consume and to_str_consume to not do a unnecessary copy.
621 let level_short = level_name.slice_chars(0, 1);
622 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
623 let flags = vec::append(getopts::opt_strs(matches, level_short),
624 getopts::opt_strs(matches, level_name));
625 for lint_name in flags.iter() {
626 let lint_name = lint_name.replace("-", "_");
627 match lint_dict.find_equiv(&lint_name) {
629 early_error(demitter, fmt!("unknown %s flag: %s",
630 level_name, lint_name));
633 lint_opts.push((lint.lint, *level));
639 let mut debugging_opts = 0u;
640 let debug_flags = getopts::opt_strs(matches, "Z");
641 let debug_map = session::debugging_opts_map();
642 for debug_flag in debug_flags.iter() {
643 let mut this_bit = 0u;
644 for tuple in debug_map.iter() {
645 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
646 if name == debug_flag { this_bit = bit; break; }
649 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
651 debugging_opts |= this_bit;
653 if debugging_opts & session::debug_llvm != 0 {
655 llvm::LLVMSetDebug(1);
660 if parse_only || no_trans {
661 link::output_type_none
662 } else if opt_present(matches, "S") &&
663 opt_present(matches, "emit-llvm") {
664 link::output_type_llvm_assembly
665 } else if opt_present(matches, "S") {
666 link::output_type_assembly
667 } else if opt_present(matches, "c") {
668 link::output_type_object
669 } else if opt_present(matches, "emit-llvm") {
670 link::output_type_bitcode
671 } else { link::output_type_exe };
672 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot");
673 let sysroot_opt = sysroot_opt.map(|m| @Path(*m));
674 let target_opt = getopts::opt_maybe_str(matches, "target");
675 let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
676 let save_temps = getopts::opt_present(matches, "save-temps");
678 if (debugging_opts & session::no_opt) != 0 {
680 } else if opt_present(matches, "O") {
681 if opt_present(matches, "opt-level") {
682 early_error(demitter, ~"-O and --opt-level both provided");
685 } else if opt_present(matches, "opt-level") {
686 match getopts::opt_str(matches, "opt-level") {
692 early_error(demitter, ~"optimization level needs to be between 0-3")
697 let gc = debugging_opts & session::gc != 0;
698 let jit = debugging_opts & session::jit != 0;
699 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
700 let debuginfo = debugging_opts & session::debug_info != 0 ||
702 let statik = debugging_opts & session::statik != 0;
705 None => host_triple(),
708 let target_feature = match target_feature_opt {
713 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
714 let linker = getopts::opt_maybe_str(matches, "linker");
715 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
716 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
719 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
720 let test = opt_present(matches, "test");
721 let android_cross_path = getopts::opt_maybe_str(
722 matches, "android-cross-path");
724 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
727 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
733 let sopts = @session::options {
734 crate_type: crate_type,
738 custom_passes: custom_passes,
739 debuginfo: debuginfo,
740 extra_debuginfo: extra_debuginfo,
741 lint_opts: lint_opts,
742 save_temps: save_temps,
744 output_type: output_type,
745 addl_lib_search_paths: @mut addl_lib_search_paths,
747 linker_args: linker_args,
748 maybe_sysroot: sysroot_opt,
749 target_triple: target,
750 target_feature: target_feature,
754 parse_only: parse_only,
756 debugging_opts: debugging_opts,
757 android_cross_path: android_cross_path
762 pub fn build_session(sopts: @session::options,
763 demitter: diagnostic::Emitter) -> Session {
764 let codemap = @codemap::CodeMap::new();
765 let diagnostic_handler =
766 diagnostic::mk_handler(Some(demitter));
767 let span_diagnostic_handler =
768 diagnostic::mk_span_handler(diagnostic_handler, codemap);
769 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
772 pub fn build_session_(sopts: @session::options,
773 cm: @codemap::CodeMap,
774 demitter: diagnostic::Emitter,
775 span_diagnostic_handler: @diagnostic::span_handler)
777 let target_cfg = build_target_config(sopts, demitter);
778 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
780 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
781 let filesearch = filesearch::mk_filesearch(
782 &sopts.maybe_sysroot,
784 sopts.addl_lib_search_paths);
786 targ_cfg: target_cfg,
791 // For a library crate, this is always none
793 entry_type: @mut None,
794 span_diagnostic: span_diagnostic_handler,
795 filesearch: filesearch,
796 building_library: @mut false,
797 working_dir: os::getcwd(),
798 lints: @mut HashMap::new(),
802 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
804 &"normal" => ppm_normal,
805 &"expanded" => ppm_expanded,
806 &"typed" => ppm_typed,
807 &"expanded,identified" => ppm_expanded_identified,
808 &"identified" => ppm_identified,
810 sess.fatal("argument to `pretty` must be one of `normal`, \
811 `expanded`, `typed`, `identified`, \
812 or `expanded,identified`");
817 // rustc command line options
818 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
820 optflag("", "bin", "Compile an executable crate (default)"),
821 optflag("c", "", "Compile and assemble, but do not link"),
822 optmulti("", "cfg", "Configure the compilation
823 environment", "SPEC"),
824 optflag("", "emit-llvm",
825 "Produce an LLVM assembly file if used with -S option;
826 produce an LLVM bitcode file otherwise"),
827 optflag("h", "help","Display this message"),
828 optmulti("L", "", "Add a directory to the library search path",
830 optflag("", "lib", "Compile a library crate"),
831 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
832 optmulti("", "link-args", "FLAGS is a space-separated list of flags
833 passed to the linker", "FLAGS"),
834 optflag("", "ls", "List the symbols defined by a library crate"),
835 optflag("", "no-trans",
836 "Run all passes except translation; no output"),
837 optflag("O", "", "Equivalent to --opt-level=2"),
838 optopt("o", "", "Write output to <filename>", "FILENAME"),
839 optopt("", "opt-level",
840 "Optimize with possible levels 0-3", "LEVEL"),
841 optopt("", "passes", "Comma or space separated list of pass names to use. \
842 Overrides the default passes for optimization levels,\n\
843 a value of \"list\" will list the available passes.", "NAMES"),
844 optopt( "", "out-dir",
845 "Write output to compiler-chosen filename
847 optflag("", "parse-only",
848 "Parse only; do not compile, assemble, or link"),
849 optflagopt("", "pretty",
850 "Pretty-print the input instead of compiling;
851 valid types are: normal (un-annotated source),
852 expanded (crates expanded),
853 typed (crates expanded, with type annotations),
854 or identified (fully parenthesized,
855 AST nodes and blocks with IDs)", "TYPE"),
856 optflag("S", "", "Compile only; do not assemble or link"),
857 optflag("", "save-temps",
858 "Write intermediate files (.bc, .opt.bc, .o)
859 in addition to normal output"),
860 optopt("", "sysroot",
861 "Override the system root", "PATH"),
862 optflag("", "test", "Build a test harness"),
864 "Target triple cpu-manufacturer-kernel[-os]
865 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
866 for detail)", "TRIPLE"),
867 optopt("", "target-feature",
868 "Target specific attributes (llc -mattr=help
869 for detail)", "FEATURE"),
870 optopt("", "android-cross-path",
871 "The path to the Android NDK", "PATH"),
872 optflagopt("W", "warn",
873 "Set lint warnings", "OPT"),
874 optmulti("A", "allow",
875 "Set lint allowed", "OPT"),
876 optmulti("D", "deny",
877 "Set lint denied", "OPT"),
878 optmulti("F", "forbid",
879 "Set lint forbidden", "OPT"),
880 optmulti("Z", "", "Set internal debugging options", "FLAG"),
881 optflag( "v", "version",
882 "Print version info and exit"),
886 pub struct OutputFilenames {
891 pub fn build_output_filenames(input: &input,
893 ofile: &Option<Path>,
894 attrs: &[ast::Attribute],
896 -> ~OutputFilenames {
899 let sopts = sess.opts;
900 let stop_after_codegen =
901 sopts.output_type != link::output_type_exe ||
902 sopts.is_static && *sess.building_library;
905 match sopts.output_type {
906 link::output_type_none => ~"none",
907 link::output_type_bitcode => ~"bc",
908 link::output_type_assembly => ~"s",
909 link::output_type_llvm_assembly => ~"ll",
910 // Object and exe output both use the '.o' extension here
911 link::output_type_object | link::output_type_exe => ~"o"
916 // "-" as input file will cause the parser to read from stdin so we
917 // have to make up a name
918 // We want to toss everything after the final '.'
919 let dirpath = match *odir {
920 Some(ref d) => (*d).clone(),
921 None => match *input {
922 str_input(_) => os::getcwd(),
923 file_input(ref ifile) => (*ifile).dir_path()
927 let mut stem = match *input {
928 file_input(ref ifile) => (*ifile).filestem().unwrap().to_managed(),
929 str_input(_) => @"rust_out"
932 // If a linkage name meta is present, we use it as the link name
933 let linkage_metas = attr::find_linkage_metas(attrs);
934 if !linkage_metas.is_empty() {
935 // But if a linkage meta is present, that overrides
936 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
937 match maybe_name.chain(|m| m.value_str()) {
941 // If the name is missing, we just default to the filename
945 if *sess.building_library {
946 out_path = dirpath.push(os::dll_filename(stem));
947 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
949 out_path = dirpath.push(stem);
950 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
954 Some(ref out_file) => {
955 out_path = (*out_file).clone();
956 obj_path = if stop_after_codegen {
959 (*out_file).with_filetype(obj_suffix)
962 if *sess.building_library {
963 sess.warn("ignoring specified output filename for library.");
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());