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").map_move(|m| @Path(m));
673 let target_opt = getopts::opt_maybe_str(matches, "target");
674 let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
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 ||
701 let statik = debugging_opts & session::statik != 0;
704 None => host_triple(),
707 let target_feature = match target_feature_opt {
712 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
713 let linker = getopts::opt_maybe_str(matches, "linker");
714 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
715 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
718 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
719 let test = opt_present(matches, "test");
720 let android_cross_path = getopts::opt_maybe_str(
721 matches, "android-cross-path");
723 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
726 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
732 let sopts = @session::options {
733 crate_type: crate_type,
737 custom_passes: custom_passes,
738 debuginfo: debuginfo,
739 extra_debuginfo: extra_debuginfo,
740 lint_opts: lint_opts,
741 save_temps: save_temps,
743 output_type: output_type,
744 addl_lib_search_paths: @mut addl_lib_search_paths,
746 linker_args: linker_args,
747 maybe_sysroot: sysroot_opt,
748 target_triple: target,
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: @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 detail)", "TRIPLE"),
866 optopt("", "target-feature",
867 "Target specific attributes (llc -mattr=help
868 for detail)", "FEATURE"),
869 optopt("", "android-cross-path",
870 "The path to the Android NDK", "PATH"),
871 optflagopt("W", "warn",
872 "Set lint warnings", "OPT"),
873 optmulti("A", "allow",
874 "Set lint allowed", "OPT"),
875 optmulti("D", "deny",
876 "Set lint denied", "OPT"),
877 optmulti("F", "forbid",
878 "Set lint forbidden", "OPT"),
879 optmulti("Z", "", "Set internal debugging options", "FLAG"),
880 optflag( "v", "version",
881 "Print version info and exit"),
885 pub struct OutputFilenames {
890 pub fn build_output_filenames(input: &input,
892 ofile: &Option<Path>,
893 attrs: &[ast::Attribute],
895 -> ~OutputFilenames {
898 let sopts = sess.opts;
899 let stop_after_codegen =
900 sopts.output_type != link::output_type_exe ||
901 sopts.is_static && *sess.building_library;
904 match sopts.output_type {
905 link::output_type_none => ~"none",
906 link::output_type_bitcode => ~"bc",
907 link::output_type_assembly => ~"s",
908 link::output_type_llvm_assembly => ~"ll",
909 // Object and exe output both use the '.o' extension here
910 link::output_type_object | link::output_type_exe => ~"o"
915 // "-" as input file will cause the parser to read from stdin so we
916 // have to make up a name
917 // We want to toss everything after the final '.'
918 let dirpath = match *odir {
919 Some(ref d) => (*d).clone(),
920 None => match *input {
921 str_input(_) => os::getcwd(),
922 file_input(ref ifile) => (*ifile).dir_path()
926 let mut stem = match *input {
927 file_input(ref ifile) => (*ifile).filestem().unwrap().to_managed(),
928 str_input(_) => @"rust_out"
931 // If a linkage name meta is present, we use it as the link name
932 let linkage_metas = attr::find_linkage_metas(attrs);
933 if !linkage_metas.is_empty() {
934 // But if a linkage meta is present, that overrides
935 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
936 match maybe_name.chain(|m| m.value_str()) {
940 // If the name is missing, we just default to the filename
944 if *sess.building_library {
945 out_path = dirpath.push(os::dll_filename(stem));
946 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
948 out_path = dirpath.push(stem);
949 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
953 Some(ref out_file) => {
954 out_path = (*out_file).clone();
955 obj_path = if stop_after_codegen {
958 (*out_file).with_filetype(obj_suffix)
961 if *sess.building_library {
962 sess.warn("ignoring specified output filename for library.");
966 sess.warn("ignoring --out-dir flag due to -o flag.");
972 out_filename: out_path,
973 obj_filename: obj_path
977 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
978 emitter(None, msg, diagnostic::fatal);
982 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
983 metadata::loader::list_file_metadata(
984 token::get_ident_interner(),
985 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
991 use driver::driver::{build_configuration, build_session};
992 use driver::driver::{build_session_options, optgroups, str_input};
994 use extra::getopts::groups::getopts;
997 use syntax::diagnostic;
999 // When the user supplies --test we should implicitly supply --cfg test
1001 fn test_switch_implies_cfg_test() {
1003 &match getopts([~"--test"], optgroups()) {
1005 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
1007 let sessopts = build_session_options(
1008 @"rustc", matches, diagnostic::emit);
1009 let sess = build_session(sessopts, diagnostic::emit);
1010 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1011 assert!((attr::contains_name(cfg, "test")));
1014 // When the user supplies --test and --cfg test, don't implicitly add
1015 // another --cfg test
1017 fn test_switch_implies_cfg_test_unless_cfg_test() {
1019 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1022 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1025 let sessopts = build_session_options(
1026 @"rustc", matches, diagnostic::emit);
1027 let sess = build_session(sessopts, diagnostic::emit);
1028 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1029 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1030 assert!(test_items.next().is_some());
1031 assert!(test_items.next().is_none());