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 bitcode file"),
825 optflag("h", "help","Display this message"),
826 optmulti("L", "", "Add a directory to the library search path",
828 optflag("", "lib", "Compile a library crate"),
829 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
830 optmulti("", "link-args", "FLAGS is a space-separated list of flags
831 passed to the linker", "FLAGS"),
832 optflag("", "ls", "List the symbols defined by a library crate"),
833 optflag("", "no-trans",
834 "Run all passes except translation; no output"),
835 optflag("O", "", "Equivalent to --opt-level=2"),
836 optopt("o", "", "Write output to <filename>", "FILENAME"),
837 optopt("", "opt-level",
838 "Optimize with possible levels 0-3", "LEVEL"),
839 optopt("", "passes", "Comma or space separated list of pass names to use. \
840 Overrides the default passes for optimization levels,\n\
841 a value of \"list\" will list the available passes.", "NAMES"),
842 optopt( "", "out-dir",
843 "Write output to compiler-chosen filename
845 optflag("", "parse-only",
846 "Parse only; do not compile, assemble, or link"),
847 optflagopt("", "pretty",
848 "Pretty-print the input instead of compiling;
849 valid types are: normal (un-annotated source),
850 expanded (crates expanded),
851 typed (crates expanded, with type annotations),
852 or identified (fully parenthesized,
853 AST nodes and blocks with IDs)", "TYPE"),
854 optflag("S", "", "Compile only; do not assemble or link"),
855 optflag("", "save-temps",
856 "Write intermediate files (.bc, .opt.bc, .o)
857 in addition to normal output"),
858 optopt("", "sysroot",
859 "Override the system root", "PATH"),
860 optflag("", "test", "Build a test harness"),
862 "Target triple cpu-manufacturer-kernel[-os]
863 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
864 for detail)", "TRIPLE"),
865 optopt("", "target-feature",
866 "Target specific attributes (llc -mattr=help
867 for detail)", "FEATURE"),
868 optopt("", "android-cross-path",
869 "The path to the Android NDK", "PATH"),
870 optflagopt("W", "warn",
871 "Set lint warnings", "OPT"),
872 optmulti("A", "allow",
873 "Set lint allowed", "OPT"),
874 optmulti("D", "deny",
875 "Set lint denied", "OPT"),
876 optmulti("F", "forbid",
877 "Set lint forbidden", "OPT"),
878 optmulti("Z", "", "Set internal debugging options", "FLAG"),
879 optflag( "v", "version",
880 "Print version info and exit"),
884 pub struct OutputFilenames {
889 pub fn build_output_filenames(input: &input,
891 ofile: &Option<Path>,
892 attrs: &[ast::Attribute],
894 -> ~OutputFilenames {
897 let sopts = sess.opts;
898 let stop_after_codegen =
899 sopts.output_type != link::output_type_exe ||
900 sopts.is_static && *sess.building_library;
903 match sopts.output_type {
904 link::output_type_none => ~"none",
905 link::output_type_bitcode => ~"bc",
906 link::output_type_assembly => ~"s",
907 link::output_type_llvm_assembly => ~"ll",
908 // Object and exe output both use the '.o' extension here
909 link::output_type_object | link::output_type_exe => ~"o"
914 // "-" as input file will cause the parser to read from stdin so we
915 // have to make up a name
916 // We want to toss everything after the final '.'
917 let dirpath = match *odir {
918 Some(ref d) => (*d).clone(),
919 None => match *input {
920 str_input(_) => os::getcwd(),
921 file_input(ref ifile) => (*ifile).dir_path()
925 let mut stem = match *input {
926 file_input(ref ifile) => (*ifile).filestem().unwrap().to_managed(),
927 str_input(_) => @"rust_out"
930 // If a linkage name meta is present, we use it as the link name
931 let linkage_metas = attr::find_linkage_metas(attrs);
932 if !linkage_metas.is_empty() {
933 // But if a linkage meta is present, that overrides
934 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
935 match maybe_name.chain(|m| m.value_str()) {
939 // If the name is missing, we just default to the filename
943 if *sess.building_library {
944 out_path = dirpath.push(os::dll_filename(stem));
945 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
947 out_path = dirpath.push(stem);
948 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
952 Some(ref out_file) => {
953 out_path = (*out_file).clone();
954 obj_path = if stop_after_codegen {
957 (*out_file).with_filetype(obj_suffix)
960 if *sess.building_library {
961 sess.warn("ignoring specified output filename for library.");
965 sess.warn("ignoring --out-dir flag due to -o flag.");
971 out_filename: out_path,
972 obj_filename: obj_path
976 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
977 emitter(None, msg, diagnostic::fatal);
981 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
982 metadata::loader::list_file_metadata(
983 token::get_ident_interner(),
984 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
990 use driver::driver::{build_configuration, build_session};
991 use driver::driver::{build_session_options, optgroups, str_input};
993 use extra::getopts::groups::getopts;
996 use syntax::diagnostic;
998 // When the user supplies --test we should implicitly supply --cfg test
1000 fn test_switch_implies_cfg_test() {
1002 &match getopts([~"--test"], optgroups()) {
1004 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
1006 let sessopts = build_session_options(
1007 @"rustc", matches, diagnostic::emit);
1008 let sess = build_session(sessopts, diagnostic::emit);
1009 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1010 assert!((attr::contains_name(cfg, "test")));
1013 // When the user supplies --test and --cfg test, don't implicitly add
1014 // another --cfg test
1016 fn test_switch_implies_cfg_test_unless_cfg_test() {
1018 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1021 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1024 let sessopts = build_session_options(
1025 @"rustc", matches, diagnostic::emit);
1026 let sess = build_session(sessopts, diagnostic::emit);
1027 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1028 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1029 assert!(test_items.next().is_some());
1030 assert!(test_items.next().is_none());