1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use back::{arm, x86, x86_64, mips};
14 use driver::session::{Aggressive, OutputExecutable};
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};
31 use std::io::mem::MemReader;
34 use extra::getopts::groups::{optopt, optmulti, optflag, optflagopt};
39 use syntax::attr::{AttrMetaMethods};
41 use syntax::diagnostic;
43 use syntax::parse::token;
44 use syntax::print::{pp, pprust};
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 // FIXME (#9639): This needs to handle non-utf8 paths
64 file_input(ref ifile) => ifile.as_str().unwrap().to_managed(),
65 str_input(_) => anon_src()
69 pub fn default_configuration(sess: Session) ->
71 let tos = match sess.targ_cfg.os {
72 abi::OsWin32 => @"win32",
73 abi::OsMacos => @"macos",
74 abi::OsLinux => @"linux",
75 abi::OsAndroid => @"android",
76 abi::OsFreebsd => @"freebsd"
79 // ARM is bi-endian, however using NDK seems to default
80 // to little-endian unless a flag is provided.
81 let (end,arch,wordsz) = match sess.targ_cfg.arch {
82 abi::X86 => (@"little", @"x86", @"32"),
83 abi::X86_64 => (@"little", @"x86_64", @"64"),
84 abi::Arm => (@"little", @"arm", @"32"),
85 abi::Mips => (@"big", @"mips", @"32")
88 let fam = match sess.targ_cfg.os {
89 abi::OsWin32 => @"windows",
93 let mk = attr::mk_name_value_item_str;
94 return ~[ // Target bindings.
95 attr::mk_word_item(fam),
96 mk(@"target_os", tos),
97 mk(@"target_family", fam),
98 mk(@"target_arch", arch),
99 mk(@"target_endian", end),
100 mk(@"target_word_size", wordsz),
104 pub fn append_configuration(cfg: &mut ast::CrateConfig, name: @str) {
105 if !cfg.iter().any(|mi| mi.name() == name) {
106 cfg.push(attr::mk_word_item(name))
110 pub fn build_configuration(sess: Session) ->
112 // Combine the configuration requested by the session (command line) with
113 // some default and generated configuration items
114 let default_cfg = default_configuration(sess);
115 let mut user_cfg = sess.opts.cfg.clone();
116 // If the user wants a test runner, then add the test cfg
117 if sess.opts.test { append_configuration(&mut user_cfg, @"test") }
118 // If the user requested GC, then add the GC cfg
119 append_configuration(&mut user_cfg, if sess.opts.gc { @"gc" } else { @"nogc" });
120 return vec::append(user_cfg, default_cfg);
123 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
124 fn parse_cfgspecs(cfgspecs: ~[~str], demitter: @diagnostic::Emitter)
125 -> ast::CrateConfig {
126 cfgspecs.move_iter().map(|s| {
127 let sess = parse::new_parse_sess(Some(demitter));
128 parse::parse_meta_from_source_str(@"cfgspec", s.to_managed(), ~[], sess)
129 }).collect::<ast::CrateConfig>()
133 /// Load source from file
135 /// The string is the source
136 // FIXME (#2319): Don't really want to box the source string
140 pub fn phase_1_parse_input(sess: Session, cfg: ast::CrateConfig, input: &input)
142 time(sess.time_passes(), "parsing", (), |_| {
144 file_input(ref file) => {
145 parse::parse_crate_from_file(&(*file), cfg.clone(), sess.parse_sess)
148 parse::parse_crate_from_source_str(
149 anon_src(), src, cfg.clone(), sess.parse_sess)
155 // For continuing compilation after a parsed crate has been
158 /// Run the "early phases" of the compiler: initial `cfg` processing,
159 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
160 /// harness if one is to be provided and injection of a dependency on the
161 /// standard library and prelude.
162 pub fn phase_2_configure_and_expand(sess: Session,
163 cfg: ast::CrateConfig,
164 mut crate: ast::Crate) -> ast::Crate {
165 let time_passes = sess.time_passes();
167 *sess.building_library = session::building_library(sess.opts, &crate);
168 let want_exe = sess.opts.outputs.iter().any(|&o| o == OutputExecutable);
169 if *sess.building_library && want_exe {
170 sess.err("cannot build both a library and an executable");
173 time(time_passes, "gated feature checking", (), |_|
174 front::feature_gate::check_crate(sess, &crate));
176 // strip before expansion to allow macros to depend on
177 // configuration variables e.g/ in
179 // #[macro_escape] #[cfg(foo)]
180 // mod bar { macro_rules! baz!(() => {{}}) }
182 // baz! should not use this definition unless foo is enabled.
183 crate = time(time_passes, "std macros injection", crate, |crate|
184 syntax::ext::expand::inject_std_macros(sess.parse_sess,
188 crate = time(time_passes, "configuration 1", crate, |crate|
189 front::config::strip_unconfigured_items(crate));
191 crate = time(time_passes, "expansion", crate, |crate|
192 syntax::ext::expand::expand_crate(sess.parse_sess, cfg.clone(),
195 // strip again, in case expansion added anything with a #[cfg].
196 crate = time(time_passes, "configuration 2", crate, |crate|
197 front::config::strip_unconfigured_items(crate));
199 crate = time(time_passes, "maybe building test harness", crate, |crate|
200 front::test::modify_for_testing(sess, crate));
202 crate = time(time_passes, "std injection", crate, |crate|
203 front::std_inject::maybe_inject_libstd_ref(sess, crate));
205 crate = time(time_passes, "assigning node ids", crate, |crate|
206 front::assign_node_ids::assign_node_ids(sess, crate));
211 pub struct CrateAnalysis {
212 exp_map2: middle::resolve::ExportMap2,
213 exported_items: middle::privacy::ExportedItems,
215 maps: astencode::Maps,
216 reachable: @mut HashSet<ast::NodeId>
219 /// Run the resolution, typechecking, region checking and other
220 /// miscellaneous analysis passes on the crate. Return various
221 /// structures carrying the results of the analysis.
222 pub fn phase_3_run_analysis_passes(sess: Session,
223 crate: &ast::Crate) -> CrateAnalysis {
225 let time_passes = sess.time_passes();
227 let ast_map = time(time_passes, "ast indexing", (), |_|
228 syntax::ast_map::map_crate(sess.diagnostic(), crate));
230 time(time_passes, "external crate/lib resolution", (), |_|
231 creader::read_crates(sess, crate,
232 session::sess_os_to_meta_os(sess.targ_cfg.os),
233 token::get_ident_interner()));
235 let lang_items = time(time_passes, "language item collection", (), |_|
236 middle::lang_items::collect_language_items(crate, sess));
238 let middle::resolve::CrateMap {
241 trait_map: trait_map,
242 external_exports: external_exports,
243 last_private_map: last_private_map
245 time(time_passes, "resolution", (), |_|
246 middle::resolve::resolve_crate(sess, lang_items, crate));
248 let named_region_map = time(time_passes, "lifetime resolution", (),
249 |_| middle::resolve_lifetime::crate(sess, crate));
251 time(time_passes, "looking for entry point", (),
252 |_| middle::entry::find_entry_point(sess, crate, ast_map));
254 let freevars = time(time_passes, "freevar finding", (), |_|
255 freevars::annotate_freevars(def_map, crate));
257 let region_map = time(time_passes, "region resolution", (), |_|
258 middle::region::resolve_crate(sess, crate));
260 let ty_cx = ty::mk_ctxt(sess, def_map, named_region_map, ast_map, freevars,
261 region_map, lang_items);
263 // passes are timed inside typeck
264 let (method_map, vtable_map) = typeck::check_crate(
265 ty_cx, trait_map, crate);
267 // These next two const passes can probably be merged
268 time(time_passes, "const marking", (), |_|
269 middle::const_eval::process_crate(crate, ty_cx));
271 time(time_passes, "const checking", (), |_|
272 middle::check_const::check_crate(sess, crate, ast_map, def_map,
275 let maps = (external_exports, last_private_map);
277 time(time_passes, "privacy checking", maps, |(a, b)|
278 middle::privacy::check_crate(ty_cx, &method_map, &exp_map2,
281 time(time_passes, "effect checking", (), |_|
282 middle::effect::check_crate(ty_cx, method_map, crate));
284 time(time_passes, "loop checking", (), |_|
285 middle::check_loop::check_crate(ty_cx, crate));
287 let middle::moves::MoveMaps {moves_map, moved_variables_set,
289 time(time_passes, "compute moves", (), |_|
290 middle::moves::compute_moves(ty_cx, method_map, crate));
292 time(time_passes, "match checking", (), |_|
293 middle::check_match::check_crate(ty_cx, method_map,
296 time(time_passes, "liveness checking", (), |_|
297 middle::liveness::check_crate(ty_cx, method_map,
298 capture_map, crate));
300 let (root_map, write_guard_map) =
301 time(time_passes, "borrow checking", (), |_|
302 middle::borrowck::check_crate(ty_cx, method_map,
303 moves_map, moved_variables_set,
304 capture_map, crate));
306 time(time_passes, "kind checking", (), |_|
307 kind::check_crate(ty_cx, method_map, crate));
310 time(time_passes, "reachability checking", (), |_|
311 reachable::find_reachable(ty_cx, method_map, &exported_items));
313 time(time_passes, "lint checking", (), |_|
314 lint::check_crate(ty_cx, &exported_items, crate));
319 exported_items: exported_items,
320 maps: astencode::Maps {
322 method_map: method_map,
323 vtable_map: vtable_map,
324 write_guard_map: write_guard_map,
325 capture_map: capture_map
327 reachable: reachable_map
331 pub struct CrateTranslation {
335 crate_types: ~[~str],
338 /// Run the translation phase to LLVM, after which the AST and analysis can
340 pub fn phase_4_translate_to_llvm(sess: Session,
342 analysis: &CrateAnalysis,
343 outputs: &OutputFilenames) -> CrateTranslation {
344 time(sess.time_passes(), "translation", crate, |crate|
345 trans::base::trans_crate(sess, crate, analysis,
346 &outputs.obj_filename))
349 /// Run LLVM itself, producing a bitcode file, assembly file or object file
350 /// as a side effect.
351 pub fn phase_5_run_llvm_passes(sess: Session,
352 trans: &CrateTranslation,
353 outputs: &OutputFilenames) {
355 // On Windows, LLVM integrated assembler emits bad stack unwind tables when
356 // segmented stacks are enabled. However, unwind info directives in assembly
357 // output are OK, so we generate assembly first and then run it through
358 // an external assembler.
359 if sess.targ_cfg.os == abi::OsWin32 &&
360 (sess.opts.output_type == link::output_type_object ||
361 sess.opts.output_type == link::output_type_exe) {
362 let output_type = link::output_type_assembly;
363 let asm_filename = outputs.obj_filename.with_extension("s");
365 time(sess.time_passes(), "LLVM passes", (), |_|
366 link::write::run_passes(sess,
372 link::write::run_assembler(sess, &asm_filename, &outputs.obj_filename);
374 // Remove assembly source unless --save-temps was specified
375 if !sess.opts.save_temps {
376 fs::unlink(&asm_filename);
379 time(sess.time_passes(), "LLVM passes", (), |_|
380 link::write::run_passes(sess,
383 sess.opts.output_type,
384 &outputs.obj_filename));
388 /// Run the linker on any artifacts that resulted from the LLVM run.
389 /// This should produce either a finished executable or library.
390 pub fn phase_6_link_output(sess: Session,
391 trans: &CrateTranslation,
392 outputs: &OutputFilenames) {
393 time(sess.time_passes(), "linking", (), |_|
394 link::link_binary(sess,
396 &outputs.obj_filename,
397 &outputs.out_filename,
401 pub fn stop_after_phase_3(sess: Session) -> bool {
402 if sess.opts.no_trans {
403 debug!("invoked with --no-trans, returning early from compile_input");
409 pub fn stop_after_phase_1(sess: Session) -> bool {
410 if sess.opts.parse_only {
411 debug!("invoked with --parse-only, returning early from compile_input");
417 pub fn stop_after_phase_5(sess: Session) -> bool {
418 if sess.opts.output_type != link::output_type_exe {
419 debug!("not building executable, returning early from compile_input");
424 debug!("running JIT, returning early from compile_input");
430 pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
431 outdir: &Option<Path>, output: &Option<Path>) {
432 // We need nested scopes here, because the intermediate results can keep
433 // large chunks of memory alive and we want to free them as soon as
434 // possible to keep the peak memory usage low
435 let (outputs, trans) = {
436 let expanded_crate = {
437 let crate = phase_1_parse_input(sess, cfg.clone(), input);
438 if stop_after_phase_1(sess) { return; }
439 phase_2_configure_and_expand(sess, cfg, crate)
441 let analysis = phase_3_run_analysis_passes(sess, &expanded_crate);
442 if stop_after_phase_3(sess) { return; }
443 let outputs = build_output_filenames(input, outdir, output,
444 expanded_crate.attrs, sess);
445 let trans = phase_4_translate_to_llvm(sess, expanded_crate,
449 phase_5_run_llvm_passes(sess, &trans, outputs);
450 if stop_after_phase_5(sess) { return; }
451 phase_6_link_output(sess, &trans, outputs);
454 struct IdentifiedAnnotation {
458 impl pprust::pp_ann for IdentifiedAnnotation {
459 fn pre(&self, node: pprust::ann_node) {
461 pprust::node_expr(s, _) => pprust::popen(s),
465 fn post(&self, node: pprust::ann_node) {
467 pprust::node_item(s, item) => {
469 pprust::synth_comment(s, item.id.to_str());
471 pprust::node_block(s, ref blk) => {
473 pprust::synth_comment(s, ~"block " + blk.id.to_str());
475 pprust::node_expr(s, expr) => {
477 pprust::synth_comment(s, expr.id.to_str());
480 pprust::node_pat(s, pat) => {
482 pprust::synth_comment(s, ~"pat " + pat.id.to_str());
488 struct TypedAnnotation {
489 analysis: CrateAnalysis,
492 impl pprust::pp_ann for TypedAnnotation {
493 fn pre(&self, node: pprust::ann_node) {
495 pprust::node_expr(s, _) => pprust::popen(s),
499 fn post(&self, node: pprust::ann_node) {
500 let tcx = self.analysis.ty_cx;
502 pprust::node_expr(s, expr) => {
506 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
514 pub fn pretty_print_input(sess: Session,
515 cfg: ast::CrateConfig,
518 fn ann_typed_post(tcx: ty::ctxt, node: pprust::ann_node) {
520 pprust::node_expr(s, expr) => {
524 pp::word(s.s, ppaux::ty_to_str(tcx, ty::expr_ty(tcx, expr)));
531 let crate = phase_1_parse_input(sess, cfg.clone(), input);
533 let (crate, is_expanded) = match ppm {
534 PpmExpanded | PpmExpandedIdentified | PpmTyped => {
535 (phase_2_configure_and_expand(sess, cfg, crate), true)
540 let annotation = match ppm {
541 PpmIdentified | PpmExpandedIdentified => {
542 @IdentifiedAnnotation {
547 let analysis = phase_3_run_analysis_passes(sess, &crate);
552 _ => @pprust::no_ann::new() as @pprust::pp_ann,
555 let src = sess.codemap.get_filemap(source_name(input)).src;
556 let rdr = @mut MemReader::new(src.as_bytes().to_owned());
557 pprust::print_crate(sess.codemap,
558 token::get_ident_interner(),
559 sess.span_diagnostic,
562 rdr as @mut io::Reader,
563 @mut io::stdout() as @mut io::Writer,
568 pub fn get_os(triple: &str) -> Option<abi::Os> {
569 for &(name, os) in os_names.iter() {
570 if triple.contains(name) { return Some(os) }
574 static os_names : &'static [(&'static str, abi::Os)] = &'static [
575 ("mingw32", abi::OsWin32),
576 ("win32", abi::OsWin32),
577 ("darwin", abi::OsMacos),
578 ("android", abi::OsAndroid),
579 ("linux", abi::OsLinux),
580 ("freebsd", abi::OsFreebsd)];
582 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
583 for &(arch, abi) in architecture_abis.iter() {
584 if triple.contains(arch) { return Some(abi) }
588 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
595 ("x86_64", abi::X86_64),
598 ("xscale", abi::Arm),
600 ("mips", abi::Mips)];
602 pub fn build_target_config(sopts: @session::options,
603 demitter: @diagnostic::Emitter)
604 -> @session::config {
605 let os = match get_os(sopts.target_triple) {
607 None => early_error(demitter, "unknown operating system")
609 let arch = match get_arch(sopts.target_triple) {
611 None => early_error(demitter,
612 "unknown architecture: " + sopts.target_triple)
614 let (int_type, uint_type) = match arch {
615 abi::X86 => (ast::ty_i32, ast::ty_u32),
616 abi::X86_64 => (ast::ty_i64, ast::ty_u64),
617 abi::Arm => (ast::ty_i32, ast::ty_u32),
618 abi::Mips => (ast::ty_i32, ast::ty_u32)
620 let target_triple = sopts.target_triple.clone();
621 let target_strs = match arch {
622 abi::X86 => x86::get_target_strs(target_triple, os),
623 abi::X86_64 => x86_64::get_target_strs(target_triple, os),
624 abi::Arm => arm::get_target_strs(target_triple, os),
625 abi::Mips => mips::get_target_strs(target_triple, os)
627 let target_cfg = @session::config {
630 target_strs: target_strs,
632 uint_type: uint_type,
637 pub fn host_triple() -> ~str {
638 // Get the host triple out of the build environment. This ensures that our
639 // idea of the host triple is the same as for the set of libraries we've
640 // actually built. We can't just take LLVM's host triple because they
641 // normalize all ix86 architectures to i386.
643 // Instead of grabbing the host triple (for the current host), we grab (at
644 // compile time) the target triple that this rustc is built with and
645 // calling that (at runtime) the host triple.
646 (env!("CFG_COMPILER")).to_owned()
649 pub fn build_session_options(binary: @str,
650 matches: &getopts::Matches,
651 demitter: @diagnostic::Emitter)
652 -> @session::options {
653 let mut outputs = ~[];
654 if matches.opt_present("rlib") {
655 outputs.push(session::OutputRlib)
657 if matches.opt_present("staticlib") {
658 outputs.push(session::OutputStaticlib)
660 // dynamic libraries are the "compiler blesssed" default library
661 if matches.opt_present("dylib") || matches.opt_present("lib") {
662 outputs.push(session::OutputDylib)
664 if matches.opt_present("bin") {
665 outputs.push(session::OutputExecutable)
668 let parse_only = matches.opt_present("parse-only");
669 let no_trans = matches.opt_present("no-trans");
671 let lint_levels = [lint::allow, lint::warn,
672 lint::deny, lint::forbid];
673 let mut lint_opts = ~[];
674 let lint_dict = lint::get_lint_dict();
675 for level in lint_levels.iter() {
676 let level_name = lint::level_to_str(*level);
678 let level_short = level_name.slice_chars(0, 1);
679 let level_short = level_short.to_ascii().to_upper().into_str();
680 let flags = vec::append(matches.opt_strs(level_short),
681 matches.opt_strs(level_name));
682 for lint_name in flags.iter() {
683 let lint_name = lint_name.replace("-", "_");
684 match lint_dict.find_equiv(&lint_name) {
686 early_error(demitter, format!("unknown {} flag: {}",
687 level_name, lint_name));
690 lint_opts.push((lint.lint, *level));
696 let mut debugging_opts = 0u;
697 let debug_flags = matches.opt_strs("Z");
698 let debug_map = session::debugging_opts_map();
699 for debug_flag in debug_flags.iter() {
700 let mut this_bit = 0u;
701 for tuple in debug_map.iter() {
702 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
703 if *name == *debug_flag { this_bit = bit; break; }
706 early_error(demitter, format!("unknown debug flag: {}", *debug_flag))
708 debugging_opts |= this_bit;
711 if debugging_opts & session::debug_llvm != 0 {
712 unsafe { llvm::LLVMSetDebug(1); }
716 if parse_only || no_trans {
717 link::output_type_none
718 } else if matches.opt_present("S") &&
719 matches.opt_present("emit-llvm") {
720 link::output_type_llvm_assembly
721 } else if matches.opt_present("S") {
722 link::output_type_assembly
723 } else if matches.opt_present("c") {
724 link::output_type_object
725 } else if matches.opt_present("emit-llvm") {
726 link::output_type_bitcode
727 } else { link::output_type_exe };
728 let sysroot_opt = matches.opt_str("sysroot").map(|m| @Path::init(m));
729 let target = matches.opt_str("target").unwrap_or(host_triple());
730 let target_cpu = matches.opt_str("target-cpu").unwrap_or(~"generic");
731 let target_feature = matches.opt_str("target-feature").unwrap_or(~"");
732 let save_temps = matches.opt_present("save-temps");
734 if (debugging_opts & session::no_opt) != 0 {
736 } else if matches.opt_present("O") {
737 if matches.opt_present("opt-level") {
738 early_error(demitter, "-O and --opt-level both provided");
741 } else if matches.opt_present("opt-level") {
742 match matches.opt_str("opt-level").unwrap() {
748 early_error(demitter, "optimization level needs to be between 0-3")
753 let gc = debugging_opts & session::gc != 0;
754 let jit = debugging_opts & session::jit != 0;
755 let extra_debuginfo = debugging_opts & session::extra_debug_info != 0;
756 let debuginfo = debugging_opts & session::debug_info != 0 ||
759 let addl_lib_search_paths = matches.opt_strs("L").map(|s| {
760 Path::init(s.as_slice())
761 }).move_iter().collect();
762 let ar = matches.opt_str("ar");
763 let linker = matches.opt_str("linker");
764 let linker_args = matches.opt_strs("link-args").flat_map( |a| {
765 a.split(' ').map(|arg| arg.to_owned()).collect()
768 let cfg = parse_cfgspecs(matches.opt_strs("cfg"), demitter);
769 let test = matches.opt_present("test");
770 let android_cross_path = matches.opt_str("android-cross-path");
772 let custom_passes = match matches.opt_str("passes") {
775 s.split(|c: char| c == ' ' || c == ',').map(|s| {
780 let llvm_args = match matches.opt_str("llvm-args") {
783 s.split(|c: char| c == ' ' || c == ',').map(|s| {
789 let sopts = @session::options {
793 custom_passes: custom_passes,
794 llvm_args: llvm_args,
795 debuginfo: debuginfo,
796 extra_debuginfo: extra_debuginfo,
797 lint_opts: lint_opts,
798 save_temps: save_temps,
800 output_type: output_type,
801 addl_lib_search_paths: @mut addl_lib_search_paths,
804 linker_args: linker_args,
805 maybe_sysroot: sysroot_opt,
806 target_triple: target,
807 target_cpu: target_cpu,
808 target_feature: target_feature,
812 parse_only: parse_only,
814 debugging_opts: debugging_opts,
815 android_cross_path: android_cross_path
820 pub fn build_session(sopts: @session::options, demitter: @diagnostic::Emitter)
822 let codemap = @codemap::CodeMap::new();
823 let diagnostic_handler =
824 diagnostic::mk_handler(Some(demitter));
825 let span_diagnostic_handler =
826 diagnostic::mk_span_handler(diagnostic_handler, codemap);
827 build_session_(sopts, codemap, demitter, span_diagnostic_handler)
830 pub fn build_session_(sopts: @session::options,
831 cm: @codemap::CodeMap,
832 demitter: @diagnostic::Emitter,
833 span_diagnostic_handler: @mut diagnostic::span_handler)
835 let target_cfg = build_target_config(sopts, demitter);
836 let p_s = parse::new_parse_sess_special_handler(span_diagnostic_handler,
838 let cstore = @mut cstore::mk_cstore(token::get_ident_interner());
839 let filesearch = filesearch::mk_filesearch(
840 &sopts.maybe_sysroot,
842 sopts.addl_lib_search_paths);
844 targ_cfg: target_cfg,
849 // For a library crate, this is always none
851 entry_type: @mut None,
852 span_diagnostic: span_diagnostic_handler,
853 filesearch: filesearch,
854 building_library: @mut false,
855 working_dir: os::getcwd(),
856 lints: @mut HashMap::new(),
861 pub fn parse_pretty(sess: Session, name: &str) -> PpMode {
863 &"normal" => PpmNormal,
864 &"expanded" => PpmExpanded,
865 &"typed" => PpmTyped,
866 &"expanded,identified" => PpmExpandedIdentified,
867 &"identified" => PpmIdentified,
869 sess.fatal("argument to `pretty` must be one of `normal`, \
870 `expanded`, `typed`, `identified`, \
871 or `expanded,identified`");
876 // rustc command line options
877 pub fn optgroups() -> ~[getopts::groups::OptGroup] {
879 optflag("c", "", "Compile and assemble, but do not link"),
880 optmulti("", "cfg", "Configure the compilation
881 environment", "SPEC"),
882 optflag("", "emit-llvm",
883 "Produce an LLVM assembly file if used with -S option;
884 produce an LLVM bitcode file otherwise"),
885 optflag("h", "help","Display this message"),
886 optmulti("L", "", "Add a directory to the library search path",
888 optflag("", "bin", "Compile an executable crate (default)"),
889 optflag("", "lib", "Compile a rust library crate using the compiler's default"),
890 optflag("", "rlib", "Compile a rust library crate as an rlib file"),
891 optflag("", "staticlib", "Compile a static library crate"),
892 optflag("", "dylib", "Compile a dynamic library crate"),
893 optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"),
894 optopt("", "ar", "Program to use for managing archives instead of the default.", "AR"),
895 optmulti("", "link-args", "FLAGS is a space-separated list of flags
896 passed to the linker", "FLAGS"),
897 optflag("", "ls", "List the symbols defined by a library crate"),
898 optflag("", "no-trans",
899 "Run all passes except translation; no output"),
900 optflag("O", "", "Equivalent to --opt-level=2"),
901 optopt("o", "", "Write output to <filename>", "FILENAME"),
902 optopt("", "opt-level",
903 "Optimize with possible levels 0-3", "LEVEL"),
904 optopt("", "passes", "Comma or space separated list of pass names to use. \
905 Appends to the default list of passes to run for the \
906 specified current optimization level. A value of \
907 \"list\" will list all of the available passes", "NAMES"),
908 optopt("", "llvm-args", "A list of arguments to pass to llvm, comma \
910 optopt( "", "out-dir",
911 "Write output to compiler-chosen filename
913 optflag("", "parse-only",
914 "Parse only; do not compile, assemble, or link"),
915 optflagopt("", "pretty",
916 "Pretty-print the input instead of compiling;
917 valid types are: normal (un-annotated source),
918 expanded (crates expanded),
919 typed (crates expanded, with type annotations),
920 or identified (fully parenthesized,
921 AST nodes and blocks with IDs)", "TYPE"),
922 optflag("S", "", "Compile only; do not assemble or link"),
923 optflag("", "save-temps",
924 "Write intermediate files (.bc, .opt.bc, .o)
925 in addition to normal output"),
926 optopt("", "sysroot",
927 "Override the system root", "PATH"),
928 optflag("", "test", "Build a test harness"),
930 "Target triple cpu-manufacturer-kernel[-os]
931 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
932 for details)", "TRIPLE"),
933 optopt("", "target-cpu",
934 "Select target processor (llc -mcpu=help
935 for details)", "CPU"),
936 optopt("", "target-feature",
937 "Target specific attributes (llc -mattr=help
938 for details)", "FEATURE"),
939 optopt("", "android-cross-path",
940 "The path to the Android NDK", "PATH"),
941 optflagopt("W", "warn",
942 "Set lint warnings", "OPT"),
943 optmulti("A", "allow",
944 "Set lint allowed", "OPT"),
945 optmulti("D", "deny",
946 "Set lint denied", "OPT"),
947 optmulti("F", "forbid",
948 "Set lint forbidden", "OPT"),
949 optmulti("Z", "", "Set internal debugging options", "FLAG"),
950 optflag( "v", "version",
951 "Print version info and exit"),
955 pub struct OutputFilenames {
960 pub fn build_output_filenames(input: &input,
962 ofile: &Option<Path>,
963 attrs: &[ast::Attribute],
965 -> ~OutputFilenames {
968 let sopts = sess.opts;
969 let stop_after_codegen = sopts.output_type != link::output_type_exe;
971 let obj_suffix = match sopts.output_type {
972 link::output_type_none => ~"none",
973 link::output_type_bitcode => ~"bc",
974 link::output_type_assembly => ~"s",
975 link::output_type_llvm_assembly => ~"ll",
976 // Object and exe output both use the '.o' extension here
977 link::output_type_object | link::output_type_exe => ~"o"
982 // "-" as input file will cause the parser to read from stdin so we
983 // have to make up a name
984 // We want to toss everything after the final '.'
985 let dirpath = match *odir {
986 Some(ref d) => (*d).clone(),
987 None => match *input {
988 str_input(_) => os::getcwd(),
989 file_input(ref ifile) => (*ifile).dir_path()
993 let mut stem = match *input {
994 // FIXME (#9639): This needs to handle non-utf8 paths
995 file_input(ref ifile) => (*ifile).filestem_str().unwrap().to_managed(),
996 str_input(_) => @"rust_out"
999 // If a linkage name meta is present, we use it as the link name
1000 let linkage_metas = attr::find_linkage_metas(attrs);
1001 if !linkage_metas.is_empty() {
1002 // But if a linkage meta is present, that overrides
1003 let maybe_name = linkage_metas.iter().find(|m| "name" == m.name());
1004 match maybe_name.and_then(|m| m.value_str()) {
1005 Some(s) => stem = s,
1008 // If the name is missing, we just default to the filename
1012 if *sess.building_library {
1013 out_path = dirpath.join(os::dll_filename(stem));
1015 let mut p = dirpath.join(stem);
1016 p.set_extension(obj_suffix);
1020 out_path = dirpath.join(stem);
1021 obj_path = out_path.with_extension(obj_suffix);
1025 Some(ref out_file) => {
1026 out_path = out_file.clone();
1027 obj_path = if stop_after_codegen {
1030 out_file.with_extension(obj_suffix)
1033 if *sess.building_library {
1034 sess.warn("ignoring specified output filename for library.");
1038 sess.warn("ignoring --out-dir flag due to -o flag.");
1044 out_filename: out_path,
1045 obj_filename: obj_path
1049 pub fn early_error(emitter: @diagnostic::Emitter, msg: &str) -> ! {
1050 emitter.emit(None, msg, diagnostic::fatal);
1054 pub fn list_metadata(sess: Session, path: &Path, out: @mut io::Writer) {
1055 metadata::loader::list_file_metadata(
1057 token::get_ident_interner(),
1058 session::sess_os_to_meta_os(sess.targ_cfg.os), path, out);
1064 use driver::driver::{build_configuration, build_session};
1065 use driver::driver::{build_session_options, optgroups};
1067 use extra::getopts::groups::getopts;
1069 use syntax::diagnostic;
1071 // When the user supplies --test we should implicitly supply --cfg test
1073 fn test_switch_implies_cfg_test() {
1075 &match getopts([~"--test"], optgroups()) {
1077 Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
1079 let sessopts = build_session_options(
1082 @diagnostic::DefaultEmitter as @diagnostic::Emitter);
1083 let sess = build_session(sessopts,
1084 @diagnostic::DefaultEmitter as
1085 @diagnostic::Emitter);
1086 let cfg = build_configuration(sess);
1087 assert!((attr::contains_name(cfg, "test")));
1090 // When the user supplies --test and --cfg test, don't implicitly add
1091 // another --cfg test
1093 fn test_switch_implies_cfg_test_unless_cfg_test() {
1095 &match getopts([~"--test", ~"--cfg=test"], optgroups()) {
1098 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
1102 let sessopts = build_session_options(
1105 @diagnostic::DefaultEmitter as @diagnostic::Emitter);
1106 let sess = build_session(sessopts,
1107 @diagnostic::DefaultEmitter as
1108 @diagnostic::Emitter);
1109 let cfg = build_configuration(sess);
1110 let mut test_items = cfg.iter().filter(|m| "test" == m.name());
1111 assert!(test_items.next().is_some());
1112 assert!(test_items.next().is_none());