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::node_id>
207 /// Run the resolution, typechecking, region checking and other
208 /// miscellaneous analysis passes on the crate. Return various
209 /// structures carrying the results of the analysis.
210 pub fn phase_3_run_analysis_passes(sess: Session,
211 crate: @ast::Crate) -> CrateAnalysis {
213 let time_passes = sess.time_passes();
214 let ast_map = time(time_passes, ~"ast indexing", ||
215 syntax::ast_map::map_crate(sess.diagnostic(), crate));
217 time(time_passes, ~"external crate/lib resolution", ||
218 creader::read_crates(sess.diagnostic(), crate, sess.cstore,
220 session::sess_os_to_meta_os(sess.targ_cfg.os),
222 token::get_ident_interner()));
224 let lang_items = time(time_passes, ~"language item collection", ||
225 middle::lang_items::collect_language_items(crate, sess));
227 let middle::resolve::CrateMap {
232 time(time_passes, ~"resolution", ||
233 middle::resolve::resolve_crate(sess, lang_items, crate));
235 time(time_passes, ~"looking for entry point",
236 || middle::entry::find_entry_point(sess, crate, ast_map));
238 let freevars = time(time_passes, ~"freevar finding", ||
239 freevars::annotate_freevars(def_map, crate));
241 let region_map = time(time_passes, ~"region resolution", ||
242 middle::region::resolve_crate(sess, def_map, crate));
244 let rp_set = time(time_passes, ~"region parameterization inference", ||
245 middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
247 let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
248 region_map, rp_set, lang_items);
250 // passes are timed inside typeck
251 let (method_map, vtable_map) = typeck::check_crate(
252 ty_cx, trait_map, crate);
254 // These next two const passes can probably be merged
255 time(time_passes, ~"const marking", ||
256 middle::const_eval::process_crate(crate, ty_cx));
258 time(time_passes, ~"const checking", ||
259 middle::check_const::check_crate(sess, crate, ast_map, def_map,
262 time(time_passes, ~"privacy checking", ||
263 middle::privacy::check_crate(ty_cx, &method_map, crate));
265 time(time_passes, ~"effect checking", ||
266 middle::effect::check_crate(ty_cx, method_map, crate));
268 time(time_passes, ~"loop checking", ||
269 middle::check_loop::check_crate(ty_cx, crate));
271 let middle::moves::MoveMaps {moves_map, moved_variables_set,
273 time(time_passes, ~"compute moves", ||
274 middle::moves::compute_moves(ty_cx, method_map, crate));
276 time(time_passes, ~"match checking", ||
277 middle::check_match::check_crate(ty_cx, method_map,
280 time(time_passes, ~"liveness checking", ||
281 middle::liveness::check_crate(ty_cx, method_map,
282 capture_map, crate));
284 let (root_map, write_guard_map) =
285 time(time_passes, ~"borrow checking", ||
286 middle::borrowck::check_crate(ty_cx, method_map,
287 moves_map, moved_variables_set,
288 capture_map, crate));
290 time(time_passes, ~"kind checking", ||
291 kind::check_crate(ty_cx, method_map, crate));
294 time(time_passes, ~"reachability checking", ||
295 reachable::find_reachable(ty_cx, method_map, crate));
297 time(time_passes, ~"lint checking", ||
298 lint::check_crate(ty_cx, crate));
303 maps: astencode::Maps {
305 method_map: method_map,
306 vtable_map: vtable_map,
307 write_guard_map: write_guard_map,
308 capture_map: capture_map
310 reachable: reachable_map
314 pub struct CrateTranslation {
320 /// Run the translation phase to LLVM, after which the AST and analysis can
322 pub fn phase_4_translate_to_llvm(sess: Session,
324 analysis: &CrateAnalysis,
325 outputs: &OutputFilenames) -> CrateTranslation {
326 time(sess.time_passes(), ~"translation", ||
327 trans::base::trans_crate(sess, crate, analysis,
328 &outputs.obj_filename))
331 /// Run LLVM itself, producing a bitcode file, assembly file or object file
332 /// as a side effect.
333 pub fn phase_5_run_llvm_passes(sess: Session,
334 trans: &CrateTranslation,
335 outputs: &OutputFilenames) {
338 if sess.targ_cfg.arch == abi::Arm &&
339 (sess.opts.output_type == link::output_type_object ||
340 sess.opts.output_type == link::output_type_exe) {
341 let output_type = link::output_type_assembly;
342 let obj_filename = outputs.obj_filename.with_filetype("s");
344 time(sess.time_passes(), ~"LLVM passes", ||
345 link::write::run_passes(sess,
351 link::write::run_ndk(sess, &obj_filename, &outputs.obj_filename);
353 time(sess.time_passes(), ~"LLVM passes", ||
354 link::write::run_passes(sess,
357 sess.opts.output_type,
358 &outputs.obj_filename));
362 /// Run the linker on any artifacts that resulted from the LLVM run.
363 /// This should produce either a finished executable or library.
364 pub fn phase_6_link_output(sess: Session,
365 trans: &CrateTranslation,
366 outputs: &OutputFilenames) {
367 time(sess.time_passes(), ~"linking", ||
368 link::link_binary(sess,
369 &outputs.obj_filename,
370 &outputs.out_filename,
374 pub fn stop_after_phase_3(sess: Session) -> bool {
375 if sess.opts.no_trans {
376 debug!("invoked with --no-trans, returning early from compile_input");
382 pub fn stop_after_phase_1(sess: Session) -> bool {
383 if sess.opts.parse_only {
384 debug!("invoked with --parse-only, returning early from compile_input");
390 pub fn stop_after_phase_5(sess: Session) -> bool {
391 if sess.opts.output_type != link::output_type_exe {
392 debug!("not building executable, returning early from compile_input");
396 if sess.opts.is_static && *sess.building_library {
397 debug!("building static library, returning early from compile_input");
402 debug!("running JIT, returning early from compile_input");
408 #[fixed_stack_segment]
409 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
410 outdir: &Option<Path>, output: &Option<Path>) {
411 let outputs = build_output_filenames(input, outdir, output, [], sess);
412 let crate = phase_1_parse_input(sess, cfg.clone(), input);
413 if stop_after_phase_1(sess) { return; }
414 let expanded_crate = phase_2_configure_and_expand(sess, cfg, crate);
415 let analysis = phase_3_run_analysis_passes(sess, expanded_crate);
416 if stop_after_phase_3(sess) { return; }
417 let trans = phase_4_translate_to_llvm(sess, expanded_crate, &analysis, outputs);
418 phase_5_run_llvm_passes(sess, &trans, outputs);
419 if stop_after_phase_5(sess) { return; }
420 phase_6_link_output(sess, &trans, outputs);
423 pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &input,
426 fn ann_paren_for_expr(node: pprust::ann_node) {
428 pprust::node_expr(s, _) => pprust::popen(s),
432 fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
434 pprust::node_expr(s, expr) => {
438 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
444 fn ann_identified_post(node: pprust::ann_node) {
446 pprust::node_item(s, item) => {
448 pprust::synth_comment(s, int::to_str(item.id));
450 pprust::node_block(s, ref blk) => {
452 pprust::synth_comment(
453 s, ~"block " + int::to_str(blk.id));
455 pprust::node_expr(s, expr) => {
457 pprust::synth_comment(s, int::to_str(expr.id));
460 pprust::node_pat(s, pat) => {
462 pprust::synth_comment(s, ~"pat " + int::to_str(pat.id));
467 let crate = phase_1_parse_input(sess, cfg.clone(), input);
469 let (crate, is_expanded) = match ppm {
470 ppm_expanded | ppm_expanded_identified | ppm_typed => {
471 (phase_2_configure_and_expand(sess, cfg, crate), true)
476 let annotation = match ppm {
477 ppm_identified | ppm_expanded_identified => {
479 pre: ann_paren_for_expr,
480 post: ann_identified_post
484 let analysis = phase_3_run_analysis_passes(sess, crate);
486 pre: ann_paren_for_expr,
487 post: |a| ann_typed_post(analysis.ty_cx, a)
490 _ => pprust::no_ann()
493 let src = sess.codemap.get_filemap(source_name(input)).src;
494 do io::with_str_reader(src) |rdr| {
495 pprust::print_crate(sess.codemap, token::get_ident_interner(),
496 sess.span_diagnostic, crate,
499 annotation, is_expanded);
503 pub fn get_os(triple: &str) -> Option<session::os> {
504 for os_names.iter().advance |&(name, os)| {
505 if triple.contains(name) { return Some(os) }
509 static os_names : &'static [(&'static str, session::os)] = &'static [
510 ("mingw32", session::os_win32),
511 ("win32", session::os_win32),
512 ("darwin", session::os_macos),
513 ("android", session::os_android),
514 ("linux", session::os_linux),
515 ("freebsd", session::os_freebsd)];
517 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
518 for architecture_abis.iter().advance |&(arch, abi)| {
519 if triple.contains(arch) { return Some(abi) }
523 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
530 ("x86_64", abi::X86_64),
533 ("xscale", abi::Arm),
535 ("mips", abi::Mips)];
537 pub fn build_target_config(sopts: @session::options,
538 demitter: diagnostic::Emitter)
539 -> @session::config {
540 let os = match get_os(sopts.target_triple) {
542 None => early_error(demitter, ~"unknown operating system")
544 let arch = match get_arch(sopts.target_triple) {
546 None => early_error(demitter,
547 ~"unknown architecture: " + sopts.target_triple)
549 let (int_type, uint_type, float_type) = match arch {
550 abi::X86 => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
551 abi::X86_64 => (ast::ty_i64, ast::ty_u64, ast::ty_f64),
552 abi::Arm => (ast::ty_i32, ast::ty_u32, ast::ty_f64),
553 abi::Mips => (ast::ty_i32, ast::ty_u32, ast::ty_f64)
555 let target_strs = match arch {
556 abi::X86 => x86::get_target_strs(os),
557 abi::X86_64 => x86_64::get_target_strs(os),
558 abi::Arm => arm::get_target_strs(os),
559 abi::Mips => mips::get_target_strs(os)
561 let target_cfg = @session::config {
564 target_strs: target_strs,
566 uint_type: uint_type,
567 float_type: float_type
572 pub fn host_triple() -> ~str {
573 // Get the host triple out of the build environment. This ensures that our
574 // idea of the host triple is the same as for the set of libraries we've
575 // actually built. We can't just take LLVM's host triple because they
576 // normalize all ix86 architectures to i386.
578 // Instead of grabbing the host triple (for the current host), we grab (at
579 // compile time) the target triple that this rustc is built with and
580 // calling that (at runtime) the host triple.
581 let ht = env!("CFG_COMPILER_TRIPLE");
585 fail!("rustc built without CFG_COMPILER_TRIPLE")
589 pub fn build_session_options(binary: @str,
590 matches: &getopts::Matches,
591 demitter: diagnostic::Emitter)
592 -> @session::options {
593 let crate_type = if opt_present(matches, "lib") {
595 } else if opt_present(matches, "bin") {
598 session::unknown_crate
600 let parse_only = opt_present(matches, "parse-only");
601 let no_trans = opt_present(matches, "no-trans");
603 let lint_levels = [lint::allow, lint::warn,
604 lint::deny, lint::forbid];
605 let mut lint_opts = ~[];
606 let lint_dict = lint::get_lint_dict();
607 for lint_levels.iter().advance |level| {
608 let level_name = lint::level_to_str(*level);
610 // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
611 // to_ascii_consume and to_str_consume to not do a unnecessary copy.
612 let level_short = level_name.slice_chars(0, 1);
613 let level_short = level_short.to_ascii().to_upper().to_str_ascii();
614 let flags = vec::append(getopts::opt_strs(matches, level_short),
615 getopts::opt_strs(matches, level_name));
616 for flags.iter().advance |lint_name| {
617 let lint_name = lint_name.replace("-", "_");
618 match lint_dict.find_equiv(&lint_name) {
620 early_error(demitter, fmt!("unknown %s flag: %s",
621 level_name, lint_name));
624 lint_opts.push((lint.lint, *level));
630 let mut debugging_opts = 0u;
631 let debug_flags = getopts::opt_strs(matches, "Z");
632 let debug_map = session::debugging_opts_map();
633 for debug_flags.iter().advance |debug_flag| {
634 let mut this_bit = 0u;
635 for debug_map.iter().advance |tuple| {
636 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
637 if name == debug_flag { this_bit = bit; break; }
640 early_error(demitter, fmt!("unknown debug flag: %s", *debug_flag))
642 debugging_opts |= this_bit;
644 if debugging_opts & session::debug_llvm != 0 {
646 llvm::LLVMSetDebug(1);
651 if parse_only || no_trans {
652 link::output_type_none
653 } else if opt_present(matches, "S") &&
654 opt_present(matches, "emit-llvm") {
655 link::output_type_llvm_assembly
656 } else if opt_present(matches, "S") {
657 link::output_type_assembly
658 } else if opt_present(matches, "c") {
659 link::output_type_object
660 } else if opt_present(matches, "emit-llvm") {
661 link::output_type_bitcode
662 } else { link::output_type_exe };
663 let sysroot_opt = getopts::opt_maybe_str(matches, "sysroot");
664 let sysroot_opt = sysroot_opt.map(|m| @Path(*m));
665 let target_opt = getopts::opt_maybe_str(matches, "target");
666 let target_feature_opt = getopts::opt_maybe_str(matches, "target-feature");
667 let save_temps = getopts::opt_present(matches, "save-temps");
669 if (debugging_opts & session::no_opt) != 0 {
671 } else if opt_present(matches, "O") {
672 if opt_present(matches, "opt-level") {
673 early_error(demitter, ~"-O and --opt-level both provided");
676 } else if opt_present(matches, "opt-level") {
677 match getopts::opt_str(matches, "opt-level") {
683 early_error(demitter, ~"optimization level needs to be between 0-3")
688 let gc = debugging_opts & session::gc != 0;
689 let jit = debugging_opts & session::jit != 0;
690 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
691 let debuginfo = debugging_opts & session::debug_info != 0 ||
693 let statik = debugging_opts & session::statik != 0;
696 None => host_triple(),
699 let target_feature = match target_feature_opt {
704 let addl_lib_search_paths = getopts::opt_strs(matches, "L").map(|s| Path(*s));
705 let linker = getopts::opt_maybe_str(matches, "linker");
706 let linker_args = getopts::opt_strs(matches, "link-args").flat_map( |a| {
707 a.split_iter(' ').transform(|arg| arg.to_owned()).collect()
710 let cfg = parse_cfgspecs(getopts::opt_strs(matches, "cfg"), demitter);
711 let test = opt_present(matches, "test");
712 let android_cross_path = getopts::opt_maybe_str(
713 matches, "android-cross-path");
715 let custom_passes = match getopts::opt_maybe_str(matches, "passes") {
718 s.split_iter(|c: char| c == ' ' || c == ',').transform(|s| {
724 let sopts = @session::options {
725 crate_type: crate_type,
729 custom_passes: custom_passes,
730 debuginfo: debuginfo,
731 extra_debuginfo: extra_debuginfo,
732 lint_opts: lint_opts,
733 save_temps: save_temps,
735 output_type: output_type,
736 addl_lib_search_paths: @mut addl_lib_search_paths,
738 linker_args: linker_args,
739 maybe_sysroot: sysroot_opt,
740 target_triple: target,
741 target_feature: target_feature,
745 parse_only: parse_only,
747 debugging_opts: debugging_opts,
748 android_cross_path: android_cross_path
753 pub fn build_session(sopts: @session::options,
754 demitter: diagnostic::Emitter) -> Session {
755 let codemap = @codemap::CodeMap::new();
756 let diagnostic_handler =
757 diagnostic::mk_handler(Some(demitter));
758 let span_diagnostic_handler =
759 diagnostic::mk_span_handler(diagnostic_handler, codemap);
760 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
763 pub fn build_session_(sopts: @session::options,
764 cm: @codemap::CodeMap,
765 demitter: diagnostic::Emitter,
766 span_diagnostic_handler: @diagnostic::span_handler)
768 let target_cfg = build_target_config(sopts, demitter);
769 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
771 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
772 let filesearch = filesearch::mk_filesearch(
773 &sopts.maybe_sysroot,
775 sopts.addl_lib_search_paths);
777 targ_cfg: target_cfg,
782 // For a library crate, this is always none
784 entry_type: @mut None,
785 span_diagnostic: span_diagnostic_handler,
786 filesearch: filesearch,
787 building_library: @mut false,
788 working_dir: os::getcwd(),
789 lints: @mut HashMap::new(),
793 pub fn parse_pretty(sess: Session, name: &str) -> pp_mode {
795 &"normal" => ppm_normal,
796 &"expanded" => ppm_expanded,
797 &"typed" => ppm_typed,
798 &"expanded,identified" => ppm_expanded_identified,
799 &"identified" => ppm_identified,
801 sess.fatal("argument to `pretty` must be one of `normal`, \
802 `expanded`, `typed`, `identified`, \
803 or `expanded,identified`");
808 // rustc command line options
809 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
811 optflag("", "bin", "Compile an executable crate (default)"),
812 optflag("c", "", "Compile and assemble, but do not link"),
813 optmulti("", "cfg", "Configure the compilation
814 environment", "SPEC"),
815 optflag("", "emit-llvm",
816 "Produce an LLVM bitcode file"),
817 optflag("h", "help","Display this message"),
818 optmulti("L", "", "Add a directory to the library search path",
820 optflag("", "lib", "Compile a library crate"),
821 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
822 optmulti("", "link-args", "FLAGS is a space-separated list of flags
823 passed to the linker", "FLAGS"),
824 optflag("", "ls", "List the symbols defined by a library crate"),
825 optflag("", "no-trans",
826 "Run all passes except translation; no output"),
827 optflag("O", "", "Equivalent to --opt-level=2"),
828 optopt("o", "", "Write output to <filename>", "FILENAME"),
829 optopt("", "opt-level",
830 "Optimize with possible levels 0-3", "LEVEL"),
831 optopt("", "passes", "Comma or space separated list of pass names to use. \
832 Overrides the default passes for optimization levels,\n\
833 a value of \"list\" will list the available passes.", "NAMES"),
834 optopt( "", "out-dir",
835 "Write output to compiler-chosen filename
837 optflag("", "parse-only",
838 "Parse only; do not compile, assemble, or link"),
839 optflagopt("", "pretty",
840 "Pretty-print the input instead of compiling;
841 valid types are: normal (un-annotated source),
842 expanded (crates expanded),
843 typed (crates expanded, with type annotations),
844 or identified (fully parenthesized,
845 AST nodes and blocks with IDs)", "TYPE"),
846 optflag("S", "", "Compile only; do not assemble or link"),
847 optflag("", "save-temps",
848 "Write intermediate files (.bc, .opt.bc, .o)
849 in addition to normal output"),
850 optopt("", "sysroot",
851 "Override the system root", "PATH"),
852 optflag("", "test", "Build a test harness"),
854 "Target triple cpu-manufacturer-kernel[-os]
855 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
856 for detail)", "TRIPLE"),
857 optopt("", "target-feature",
858 "Target specific attributes (llc -mattr=help
859 for detail)", "FEATURE"),
860 optopt("", "android-cross-path",
861 "The path to the Android NDK", "PATH"),
862 optflagopt("W", "warn",
863 "Set lint warnings", "OPT"),
864 optmulti("A", "allow",
865 "Set lint allowed", "OPT"),
866 optmulti("D", "deny",
867 "Set lint denied", "OPT"),
868 optmulti("F", "forbid",
869 "Set lint forbidden", "OPT"),
870 optmulti("Z", "", "Set internal debugging options", "FLAG"),
871 optflag( "v", "version",
872 "Print version info and exit"),
876 pub struct OutputFilenames {
881 pub fn build_output_filenames(input: &input,
883 ofile: &Option<Path>,
884 attrs: &[ast::Attribute],
886 -> ~OutputFilenames {
889 let sopts = sess.opts;
890 let stop_after_codegen =
891 sopts.output_type != link::output_type_exe ||
892 sopts.is_static && *sess.building_library;
895 match sopts.output_type {
896 link::output_type_none => ~"none",
897 link::output_type_bitcode => ~"bc",
898 link::output_type_assembly => ~"s",
899 link::output_type_llvm_assembly => ~"ll",
900 // Object and exe output both use the '.o' extension here
901 link::output_type_object | link::output_type_exe => ~"o"
906 // "-" as input file will cause the parser to read from stdin so we
907 // have to make up a name
908 // We want to toss everything after the final '.'
909 let dirpath = match *odir {
910 Some(ref d) => (*d).clone(),
911 None => match *input {
912 str_input(_) => os::getcwd(),
913 file_input(ref ifile) => (*ifile).dir_path()
917 let mut stem = match *input {
918 file_input(ref ifile) => (*ifile).filestem().get().to_managed(),
919 str_input(_) => @"rust_out"
922 // If a linkage name meta is present, we use it as the link name
923 let linkage_metas = attr::find_linkage_metas(attrs);
924 if !linkage_metas.is_empty() {
925 // But if a linkage meta is present, that overrides
926 let maybe_name = linkage_metas.iter().find_(|m| "name" == m.name());
927 match maybe_name.chain(|m| m.value_str()) {
931 // If the name is missing, we just default to the filename
935 if *sess.building_library {
936 out_path = dirpath.push(os::dll_filename(stem));
937 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
939 out_path = dirpath.push(stem);
940 obj_path = dirpath.push(stem).with_filetype(obj_suffix);
944 Some(ref out_file) => {
945 out_path = (*out_file).clone();
946 obj_path = if stop_after_codegen {
949 (*out_file).with_filetype(obj_suffix)
952 if *sess.building_library {
953 // FIXME (#2401): We might want to warn here; we're actually not
954 // going to respect the user's choice of library name when it
955 // comes time to link, we'll be linking to
956 // lib<basename>-<hash>-<version>.so no matter what.
960 sess.warn("ignoring --out-dir flag due to -o flag.");
966 out_filename: out_path,
967 obj_filename: obj_path
971 pub fn early_error(emitter: diagnostic::Emitter, msg: ~str) -> ! {
972 emitter(None, msg, diagnostic::fatal);
976 pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) {
977 metadata::loader::list_file_metadata(
978 token::get_ident_interner(),
979 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
985 use driver::driver::{build_configuration, build_session};
986 use driver::driver::{build_session_options, optgroups, str_input};
988 use extra::getopts::groups::getopts;
991 use syntax::diagnostic;
993 // When the user supplies --test we should implicitly supply --cfg test
995 fn test_switch_implies_cfg_test() {
997 &match getopts([~"--test"], optgroups()) {
999 Err(f) => fail!("test_switch_implies_cfg_test: %s", getopts::fail_str(f))
1001 let sessopts = build_session_options(
1002 @"rustc", matches, diagnostic::emit);
1003 let sess = build_session(sessopts, diagnostic::emit);
1004 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1005 assert!((attr::contains_name(cfg, "test")));
1008 // When the user supplies --test and --cfg test, don't implicitly add
1009 // another --cfg test
1011 fn test_switch_implies_cfg_test_unless_cfg_test() {
1013 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1016 fail!("test_switch_implies_cfg_test_unless_cfg_test: %s", getopts::fail_str(f));
1019 let sessopts = build_session_options(
1020 @"rustc", matches, diagnostic::emit);
1021 let sess = build_session(sessopts, diagnostic::emit);
1022 let cfg = build_configuration(sess, @"whatever", &str_input(@""));
1023 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1024 assert!(test_items.next().is_some());
1025 assert!(test_items.next().is_none());