auto merge of : nick29581/rust/driver, r=brson

The goal of this refactoring is to make the rustc driver code easier to understand and use. Since this is as close to an API as we have, I think it is important that it is nice. On getting stuck in, I found that there wasn't as much to change as I'd hoped to make the stage... functions easier to use by tools (which is a good thing :-) ).

This patch only moves code around - mostly just moving code to different files, but a few extracted method refactorings too. To summarise the changes: I added driver::config which handles everything about configuring the compiler. driver::session now just defines and builds session objects. I moved driver code from librustc/lib.rs to librustc/driver/mod.rs so all the code is one place. I extracted methods to make emulating the compiler without being the compiler a little easier. Within the driver directory, I moved code around to more logically fit in the modules.
This commit is contained in:
bors 2014-05-11 21:31:48 -07:00
commit e031ba1028
27 changed files with 1447 additions and 1377 deletions

@ -9,7 +9,7 @@
// except according to those terms.
use back::target_strs;
use driver::session::sess_os_to_meta_os;
use driver::config::cfg_os_to_meta_os;
use metadata::loader::meta_section_name;
use syntax::abi;
@ -22,7 +22,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
return target_strs::t {
module_asm: "".to_owned(),
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
meta_sect_name: meta_section_name(cfg_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os {
abi::OsMacos => {

@ -12,8 +12,9 @@ use back::archive::{Archive, METADATA_FILENAME};
use back::rpath;
use back::svh::Svh;
use driver::driver::{CrateTranslation, OutputFilenames};
use driver::session::{NoDebugInfo, Session};
use driver::session;
use driver::config::NoDebugInfo;
use driver::session::Session;
use driver::config;
use lib::llvm::llvm;
use lib::llvm::ModuleRef;
use lib;
@ -92,8 +93,9 @@ pub mod write {
use back::link::{OutputTypeExe, OutputTypeLlvmAssembly};
use back::link::{OutputTypeObject};
use driver::driver::{CrateTranslation, OutputFilenames};
use driver::session::{NoDebugInfo, Session};
use driver::session;
use driver::config::NoDebugInfo;
use driver::session::Session;
use driver::config;
use lib::llvm::llvm;
use lib::llvm::{ModuleRef, TargetMachineRef, PassManagerRef};
use lib;
@ -139,10 +141,10 @@ pub mod write {
}
let opt_level = match sess.opts.optimize {
session::No => lib::llvm::CodeGenLevelNone,
session::Less => lib::llvm::CodeGenLevelLess,
session::Default => lib::llvm::CodeGenLevelDefault,
session::Aggressive => lib::llvm::CodeGenLevelAggressive,
config::No => lib::llvm::CodeGenLevelNone,
config::Less => lib::llvm::CodeGenLevelLess,
config::Default => lib::llvm::CodeGenLevelDefault,
config::Aggressive => lib::llvm::CodeGenLevelAggressive,
};
let use_softfp = sess.opts.cg.soft_float;
@ -231,7 +233,7 @@ pub mod write {
// emitting an rlib. Whenever an rlib is created, the bytecode is
// inserted into the archive in order to allow LTO against it.
if sess.opts.cg.save_temps ||
(sess.crate_types.borrow().contains(&session::CrateTypeRlib) &&
(sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
sess.opts.output_types.contains(&OutputTypeExe)) {
output.temp_path(OutputTypeBitcode).with_c_str(|buf| {
llvm::LLVMWriteBitcodeToFile(llmod, buf);
@ -378,10 +380,10 @@ pub mod write {
// Copy what clang does by turning on loop vectorization at O2 and
// slp vectorization at O3
let vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
(sess.opts.optimize == session::Default ||
sess.opts.optimize == session::Aggressive);
(sess.opts.optimize == config::Default ||
sess.opts.optimize == config::Aggressive);
let vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
sess.opts.optimize == session::Aggressive;
sess.opts.optimize == config::Aggressive;
let mut llvm_c_strs = Vec::new();
let mut llvm_args = Vec::new();
@ -823,14 +825,14 @@ fn is_writeable(p: &Path) -> bool {
}
}
pub fn filename_for_input(sess: &Session, crate_type: session::CrateType,
pub fn filename_for_input(sess: &Session, crate_type: config::CrateType,
id: &CrateId, out_filename: &Path) -> Path {
let libname = output_lib_filename(id);
match crate_type {
session::CrateTypeRlib => {
config::CrateTypeRlib => {
out_filename.with_filename(format!("lib{}.rlib", libname))
}
session::CrateTypeDylib => {
config::CrateTypeDylib => {
let (prefix, suffix) = match sess.targ_cfg.os {
abi::OsWin32 => (loader::WIN32_DLL_PREFIX, loader::WIN32_DLL_SUFFIX),
abi::OsMacos => (loader::MACOS_DLL_PREFIX, loader::MACOS_DLL_SUFFIX),
@ -840,16 +842,16 @@ pub fn filename_for_input(sess: &Session, crate_type: session::CrateType,
};
out_filename.with_filename(format!("{}{}{}", prefix, libname, suffix))
}
session::CrateTypeStaticlib => {
config::CrateTypeStaticlib => {
out_filename.with_filename(format!("lib{}.a", libname))
}
session::CrateTypeExecutable => out_filename.clone(),
config::CrateTypeExecutable => out_filename.clone(),
}
}
fn link_binary_output(sess: &Session,
trans: &CrateTranslation,
crate_type: session::CrateType,
crate_type: config::CrateType,
outputs: &OutputFilenames,
id: &CrateId) -> Path {
let obj_filename = outputs.temp_path(OutputTypeObject);
@ -877,16 +879,16 @@ fn link_binary_output(sess: &Session,
}
match crate_type {
session::CrateTypeRlib => {
config::CrateTypeRlib => {
link_rlib(sess, Some(trans), &obj_filename, &out_filename);
}
session::CrateTypeStaticlib => {
config::CrateTypeStaticlib => {
link_staticlib(sess, &obj_filename, &out_filename);
}
session::CrateTypeExecutable => {
config::CrateTypeExecutable => {
link_natively(sess, trans, false, &obj_filename, &out_filename);
}
session::CrateTypeDylib => {
config::CrateTypeDylib => {
link_natively(sess, trans, true, &obj_filename, &out_filename);
}
}
@ -1045,7 +1047,7 @@ fn link_natively(sess: &Session, trans: &CrateTranslation, dylib: bool,
let mut cc_args = sess.targ_cfg.target_strs.cc_args.clone();
cc_args.push_all_move(link_args(sess, dylib, tmpdir.path(), trans,
obj_filename, out_filename));
if (sess.opts.debugging_opts & session::PRINT_LINK_ARGS) != 0 {
if (sess.opts.debugging_opts & config::PRINT_LINK_ARGS) != 0 {
println!("{} link args: '{}'", cc_prog, cc_args.connect("' '"));
}
@ -1161,8 +1163,8 @@ fn link_args(sess: &Session,
// GNU-style linkers support optimization with -O. GNU ld doesn't need a
// numeric argument, but other linkers do.
if sess.opts.optimize == session::Default ||
sess.opts.optimize == session::Aggressive {
if sess.opts.optimize == config::Default ||
sess.opts.optimize == config::Aggressive {
args.push("-Wl,-O1".to_owned());
}
} else if sess.targ_cfg.os == abi::OsMacos {
@ -1373,9 +1375,9 @@ fn add_upstream_rust_crates(args: &mut Vec<~str>, sess: &Session,
// involves just passing the right -l flag.
let data = if dylib {
trans.crate_formats.get(&session::CrateTypeDylib)
trans.crate_formats.get(&config::CrateTypeDylib)
} else {
trans.crate_formats.get(&session::CrateTypeExecutable)
trans.crate_formats.get(&config::CrateTypeExecutable)
};
// Invoke get_used_crates to ensure that we get a topological sorting of
@ -1403,7 +1405,7 @@ fn add_upstream_rust_crates(args: &mut Vec<~str>, sess: &Session,
}
// Converts a library file-stem into a cc -l argument
fn unlib(config: &session::Config, stem: &str) -> ~str {
fn unlib(config: &config::Config, stem: &str) -> ~str {
if stem.starts_with("lib") && config.os != abi::OsWin32 {
stem.slice(3, stem.len()).to_owned()
} else {

@ -11,6 +11,7 @@
use back::archive::ArchiveRO;
use back::link;
use driver::session;
use driver::config;
use lib::llvm::{ModuleRef, TargetMachineRef, llvm, True, False};
use metadata::cstore;
use util::common::time;
@ -29,7 +30,7 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
// Make sure we actually can run LTO
for crate_type in sess.crate_types.borrow().iter() {
match *crate_type {
session::CrateTypeExecutable | session::CrateTypeStaticlib => {}
config::CrateTypeExecutable | config::CrateTypeStaticlib => {}
_ => {
sess.fatal("lto can only be run for executables and \
static library outputs");

@ -9,7 +9,7 @@
// except according to those terms.
use back::target_strs;
use driver::session::sess_os_to_meta_os;
use driver::config::cfg_os_to_meta_os;
use metadata::loader::meta_section_name;
use syntax::abi;
@ -17,7 +17,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
return target_strs::t {
module_asm: "".to_owned(),
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
meta_sect_name: meta_section_name(cfg_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os {
abi::OsMacos => {

@ -10,7 +10,7 @@
use back::target_strs;
use driver::session::sess_os_to_meta_os;
use driver::config::cfg_os_to_meta_os;
use metadata::loader::meta_section_name;
use syntax::abi;
@ -18,7 +18,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
return target_strs::t {
module_asm: "".to_owned(),
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
meta_sect_name: meta_section_name(cfg_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os {
abi::OsMacos => {

@ -10,7 +10,7 @@
use back::target_strs;
use driver::session::sess_os_to_meta_os;
use driver::config::cfg_os_to_meta_os;
use metadata::loader::meta_section_name;
use syntax::abi;
@ -18,7 +18,7 @@ pub fn get_target_strs(target_triple: ~str, target_os: abi::Os) -> target_strs::
return target_strs::t {
module_asm: "".to_owned(),
meta_sect_name: meta_section_name(sess_os_to_meta_os(target_os)).to_owned(),
meta_sect_name: meta_section_name(cfg_os_to_meta_os(target_os)).to_owned(),
data_layout: match target_os {
abi::OsMacos => {

@ -0,0 +1,769 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Contains infrastructure for configuring the compiler, including parsing
//! command line options.
use driver::early_error;
use driver::driver;
use driver::session::Session;
use back;
use back::link;
use back::target_strs;
use back::{arm, x86, x86_64, mips};
use metadata;
use middle::lint;
use syntax::abi;
use syntax::ast;
use syntax::ast::{IntTy, UintTy};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::parse;
use syntax::parse::token::InternedString;
use collections::HashSet;
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
use lib::llvm::llvm;
use std::cell::{RefCell};
pub struct Config {
pub os: abi::Os,
pub arch: abi::Architecture,
pub target_strs: target_strs::t,
pub int_type: IntTy,
pub uint_type: UintTy,
}
#[deriving(Clone, Eq)]
pub enum OptLevel {
No, // -O0
Less, // -O1
Default, // -O2
Aggressive // -O3
}
#[deriving(Clone, Eq)]
pub enum DebugInfoLevel {
NoDebugInfo,
LimitedDebugInfo,
FullDebugInfo,
}
#[deriving(Clone)]
pub struct Options {
// The crate config requested for the session, which may be combined
// with additional crate configurations during the compile process
pub crate_types: Vec<CrateType>,
pub gc: bool,
pub optimize: OptLevel,
pub debuginfo: DebugInfoLevel,
pub lint_opts: Vec<(lint::Lint, lint::level)> ,
pub output_types: Vec<back::link::OutputType> ,
// This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use
// this.
pub addl_lib_search_paths: RefCell<HashSet<Path>>,
pub maybe_sysroot: Option<Path>,
pub target_triple: ~str,
// User-specified cfg meta items. The compiler itself will add additional
// items to the crate config, and during parsing the entire crate config
// will be added to the crate AST node. This should not be used for
// anything except building the full crate config prior to parsing.
pub cfg: ast::CrateConfig,
pub test: bool,
pub parse_only: bool,
pub no_trans: bool,
pub no_analysis: bool,
pub debugging_opts: u64,
/// Whether to write dependency files. It's (enabled, optional filename).
pub write_dependency_info: (bool, Option<Path>),
/// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
pub print_metas: (bool, bool, bool),
pub cg: CodegenOptions,
}
/// Some reasonable defaults
pub fn basic_options() -> Options {
Options {
crate_types: Vec::new(),
gc: false,
optimize: No,
debuginfo: NoDebugInfo,
lint_opts: Vec::new(),
output_types: Vec::new(),
addl_lib_search_paths: RefCell::new(HashSet::new()),
maybe_sysroot: None,
target_triple: driver::host_triple().to_owned(),
cfg: Vec::new(),
test: false,
parse_only: false,
no_trans: false,
no_analysis: false,
debugging_opts: 0,
write_dependency_info: (false, None),
print_metas: (false, false, false),
cg: basic_codegen_options(),
}
}
// The type of entry function, so
// users can have their own entry
// functions that don't start a
// scheduler
#[deriving(Eq)]
pub enum EntryFnType {
EntryMain,
EntryStart,
EntryNone,
}
#[deriving(Eq, Ord, Clone, TotalOrd, TotalEq, Hash)]
pub enum CrateType {
CrateTypeExecutable,
CrateTypeDylib,
CrateTypeRlib,
CrateTypeStaticlib,
}
macro_rules! debugging_opts(
([ $opt:ident ] $cnt:expr ) => (
pub static $opt: u64 = 1 << $cnt;
);
([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
pub static $opt: u64 = 1 << $cnt;
debugging_opts!([ $($rest),* ] $cnt + 1)
)
)
debugging_opts!(
[
VERBOSE,
TIME_PASSES,
COUNT_LLVM_INSNS,
TIME_LLVM_PASSES,
TRANS_STATS,
ASM_COMMENTS,
NO_VERIFY,
BORROWCK_STATS,
NO_LANDING_PADS,
DEBUG_LLVM,
SHOW_SPAN,
COUNT_TYPE_SIZES,
META_STATS,
NO_OPT,
GC,
PRINT_LINK_ARGS,
PRINT_LLVM_PASSES,
LTO,
AST_JSON,
AST_JSON_NOEXPAND,
LS
]
0
)
pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
vec!(("verbose", "in general, enable more debug printouts", VERBOSE),
("time-passes", "measure time of each rustc pass", TIME_PASSES),
("count-llvm-insns", "count where LLVM \
instrs originate", COUNT_LLVM_INSNS),
("time-llvm-passes", "measure time of each LLVM pass",
TIME_LLVM_PASSES),
("trans-stats", "gather trans statistics", TRANS_STATS),
("asm-comments", "generate comments into the assembly (may change behavior)",
ASM_COMMENTS),
("no-verify", "skip LLVM verification", NO_VERIFY),
("borrowck-stats", "gather borrowck statistics", BORROWCK_STATS),
("no-landing-pads", "omit landing pads for unwinding",
NO_LANDING_PADS),
("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
("show-span", "show spans for compiler debugging", SHOW_SPAN),
("count-type-sizes", "count the sizes of aggregate types",
COUNT_TYPE_SIZES),
("meta-stats", "gather metadata statistics", META_STATS),
("no-opt", "do not optimize, even if -O is passed", NO_OPT),
("print-link-args", "Print the arguments passed to the linker",
PRINT_LINK_ARGS),
("gc", "Garbage collect shared data (experimental)", GC),
("print-llvm-passes",
"Prints the llvm optimization passes being run",
PRINT_LLVM_PASSES),
("lto", "Perform LLVM link-time optimizations", LTO),
("ast-json", "Print the AST as JSON and halt", AST_JSON),
("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
("ls", "List the symbols defined by a library crate", LS))
}
/// Declare a macro that will define all CodegenOptions fields and parsers all
/// at once. The goal of this macro is to define an interface that can be
/// programmatically used by the option parser in order to initialize the struct
/// without hardcoding field names all over the place.
///
/// The goal is to invoke this macro once with the correct fields, and then this
/// macro generates all necessary code. The main gotcha of this macro is the
/// cgsetters module which is a bunch of generated code to parse an option into
/// its respective field in the struct. There are a few hand-written parsers for
/// parsing specific types of values in this module.
macro_rules! cgoptions(
($($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
(
#[deriving(Clone)]
pub struct CodegenOptions { $(pub $opt: $t),* }
pub fn basic_codegen_options() -> CodegenOptions {
CodegenOptions { $($opt: $init),* }
}
pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool;
pub static CG_OPTIONS: &'static [(&'static str, CodegenSetter,
&'static str)] =
&[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];
mod cgsetters {
use super::CodegenOptions;
$(
pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
$parse(&mut cg.$opt, v)
}
)*
fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
match v {
Some(..) => false,
None => { *slot = true; true }
}
}
fn parse_opt_string(slot: &mut Option<~str>, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = Some(s.to_owned()); true },
None => false,
}
}
fn parse_string(slot: &mut ~str, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = s.to_owned(); true },
None => false,
}
}
fn parse_list(slot: &mut Vec<~str>, v: Option<&str>)
-> bool {
match v {
Some(s) => {
for s in s.words() {
slot.push(s.to_owned());
}
true
},
None => false,
}
}
}
) )
cgoptions!(
ar: Option<~str> = (None, parse_opt_string,
"tool to assemble archives with"),
linker: Option<~str> = (None, parse_opt_string,
"system linker to link outputs with"),
link_args: Vec<~str> = (Vec::new(), parse_list,
"extra arguments to pass to the linker (space separated)"),
target_cpu: ~str = ("generic".to_owned(), parse_string,
"select target processor (llc -mcpu=help for details)"),
target_feature: ~str = ("".to_owned(), parse_string,
"target specific attributes (llc -mattr=help for details)"),
passes: Vec<~str> = (Vec::new(), parse_list,
"a list of extra LLVM passes to run (space separated)"),
llvm_args: Vec<~str> = (Vec::new(), parse_list,
"a list of arguments to pass to llvm (space separated)"),
save_temps: bool = (false, parse_bool,
"save all temporary output files during compilation"),
android_cross_path: Option<~str> = (None, parse_opt_string,
"the path to the Android NDK"),
no_rpath: bool = (false, parse_bool,
"disables setting the rpath in libs/exes"),
no_prepopulate_passes: bool = (false, parse_bool,
"don't pre-populate the pass manager with a list of passes"),
no_vectorize_loops: bool = (false, parse_bool,
"don't run the loop vectorization optimization passes"),
no_vectorize_slp: bool = (false, parse_bool,
"don't run LLVM's SLP vectorization pass"),
soft_float: bool = (false, parse_bool,
"generate software floating point library calls"),
prefer_dynamic: bool = (false, parse_bool,
"prefer dynamic linking to static linking"),
no_integrated_as: bool = (false, parse_bool,
"use an external assembler rather than LLVM's integrated one"),
relocation_model: ~str = ("pic".to_owned(), parse_string,
"choose the relocation model to use (llc -relocation-model for details)"),
)
pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
{
let mut cg = basic_codegen_options();
for option in matches.opt_strs("C").move_iter() {
let mut iter = option.splitn('=', 1);
let key = iter.next().unwrap();
let value = iter.next();
let option_to_lookup = key.replace("-", "_");
let mut found = false;
for &(candidate, setter, _) in CG_OPTIONS.iter() {
if option_to_lookup.as_slice() != candidate { continue }
if !setter(&mut cg, value) {
match value {
Some(..) => early_error(format!("codegen option `{}` takes \
no value", key)),
None => early_error(format!("codegen option `{0}` requires \
a value (-C {0}=<value>)",
key))
}
}
found = true;
break;
}
if !found {
early_error(format!("unknown codegen option: `{}`", key));
}
}
return cg;
}
pub fn default_lib_output() -> CrateType {
CrateTypeRlib
}
pub fn cfg_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
use metadata::loader;
match os {
abi::OsWin32 => loader::OsWin32,
abi::OsLinux => loader::OsLinux,
abi::OsAndroid => loader::OsAndroid,
abi::OsMacos => loader::OsMacos,
abi::OsFreebsd => loader::OsFreebsd
}
}
pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
let tos = match sess.targ_cfg.os {
abi::OsWin32 => InternedString::new("win32"),
abi::OsMacos => InternedString::new("macos"),
abi::OsLinux => InternedString::new("linux"),
abi::OsAndroid => InternedString::new("android"),
abi::OsFreebsd => InternedString::new("freebsd"),
};
// ARM is bi-endian, however using NDK seems to default
// to little-endian unless a flag is provided.
let (end,arch,wordsz) = match sess.targ_cfg.arch {
abi::X86 => ("little", "x86", "32"),
abi::X86_64 => ("little", "x86_64", "64"),
abi::Arm => ("little", "arm", "32"),
abi::Mips => ("big", "mips", "32")
};
let fam = match sess.targ_cfg.os {
abi::OsWin32 => InternedString::new("windows"),
_ => InternedString::new("unix")
};
let mk = attr::mk_name_value_item_str;
return vec!(// Target bindings.
attr::mk_word_item(fam.clone()),
mk(InternedString::new("target_os"), tos),
mk(InternedString::new("target_family"), fam),
mk(InternedString::new("target_arch"), InternedString::new(arch)),
mk(InternedString::new("target_endian"), InternedString::new(end)),
mk(InternedString::new("target_word_size"),
InternedString::new(wordsz))
);
}
pub fn append_configuration(cfg: &mut ast::CrateConfig,
name: InternedString) {
if !cfg.iter().any(|mi| mi.name() == name) {
cfg.push(attr::mk_word_item(name))
}
}
pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
let default_cfg = default_configuration(sess);
let mut user_cfg = sess.opts.cfg.clone();
// If the user wants a test runner, then add the test cfg
if sess.opts.test {
append_configuration(&mut user_cfg, InternedString::new("test"))
}
// If the user requested GC, then add the GC cfg
append_configuration(&mut user_cfg, if sess.opts.gc {
InternedString::new("gc")
} else {
InternedString::new("nogc")
});
user_cfg.move_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
}
pub fn get_os(triple: &str) -> Option<abi::Os> {
for &(name, os) in os_names.iter() {
if triple.contains(name) { return Some(os) }
}
None
}
static os_names : &'static [(&'static str, abi::Os)] = &'static [
("mingw32", abi::OsWin32),
("win32", abi::OsWin32),
("darwin", abi::OsMacos),
("android", abi::OsAndroid),
("linux", abi::OsLinux),
("freebsd", abi::OsFreebsd)];
pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
for &(arch, abi) in architecture_abis.iter() {
if triple.contains(arch) { return Some(abi) }
}
None
}
static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
("i386", abi::X86),
("i486", abi::X86),
("i586", abi::X86),
("i686", abi::X86),
("i786", abi::X86),
("x86_64", abi::X86_64),
("arm", abi::Arm),
("xscale", abi::Arm),
("thumb", abi::Arm),
("mips", abi::Mips)];
pub fn build_target_config(sopts: &Options) -> Config {
let os = match get_os(sopts.target_triple) {
Some(os) => os,
None => early_error("unknown operating system")
};
let arch = match get_arch(sopts.target_triple) {
Some(arch) => arch,
None => early_error("unknown architecture: " + sopts.target_triple)
};
let (int_type, uint_type) = match arch {
abi::X86 => (ast::TyI32, ast::TyU32),
abi::X86_64 => (ast::TyI64, ast::TyU64),
abi::Arm => (ast::TyI32, ast::TyU32),
abi::Mips => (ast::TyI32, ast::TyU32)
};
let target_triple = sopts.target_triple.clone();
let target_strs = match arch {
abi::X86 => x86::get_target_strs(target_triple, os),
abi::X86_64 => x86_64::get_target_strs(target_triple, os),
abi::Arm => arm::get_target_strs(target_triple, os),
abi::Mips => mips::get_target_strs(target_triple, os)
};
Config {
os: os,
arch: arch,
target_strs: target_strs,
int_type: int_type,
uint_type: uint_type,
}
}
// rustc command line options
pub fn optgroups() -> Vec<getopts::OptGroup> {
vec!(
optflag("h", "help", "Display this message"),
optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
optmulti("L", "", "Add a directory to the library search path", "PATH"),
optmulti("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
"[bin|lib|rlib|dylib|staticlib]"),
optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
"[asm|bc|ir|obj|link]"),
optflag("", "crate-id", "Output the crate id and exit"),
optflag("", "crate-name", "Output the crate name and exit"),
optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
continued and exit"),
optflag("g", "", "Equivalent to --debuginfo=2"),
optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
0 = no debug info,
1 = line-tables only (for stacktraces and breakpoints),
2 = full debug info with variable and type information (same as -g)", "LEVEL"),
optflag("", "no-trans", "Run all passes except translation; no output"),
optflag("", "no-analysis",
"Parse and expand the source, but run no analysis and produce no output"),
optflag("O", "", "Equivalent to --opt-level=2"),
optopt("o", "", "Write output to <filename>", "FILENAME"),
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
optflagopt("", "pretty",
"Pretty-print the input instead of compiling;
valid types are: normal (un-annotated source),
expanded (crates expanded),
typed (crates expanded, with type annotations),
or identified (fully parenthesized,
AST nodes and blocks with IDs)", "TYPE"),
optflagopt("", "dep-info",
"Output dependency info to <filename> after compiling, \
in a format suitable for use by Makefiles", "FILENAME"),
optopt("", "sysroot", "Override the system root", "PATH"),
optflag("", "test", "Build a test harness"),
optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
for details)", "TRIPLE"),
optmulti("W", "warn", "Set lint warnings", "OPT"),
optmulti("A", "allow", "Set lint allowed", "OPT"),
optmulti("D", "deny", "Set lint denied", "OPT"),
optmulti("F", "forbid", "Set lint forbidden", "OPT"),
optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
optmulti("Z", "", "Set internal debugging options", "FLAG"),
optflag( "v", "version", "Print version info and exit")
)
}
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
fn parse_cfgspecs(cfgspecs: Vec<~str> ) -> ast::CrateConfig {
cfgspecs.move_iter().map(|s| {
parse::parse_meta_from_source_str("cfgspec".to_strbuf(),
s.to_strbuf(),
Vec::new(),
&parse::new_parse_sess())
}).collect::<ast::CrateConfig>()
}
pub fn build_session_options(matches: &getopts::Matches) -> Options {
let mut crate_types: Vec<CrateType> = Vec::new();
let unparsed_crate_types = matches.opt_strs("crate-type");
for unparsed_crate_type in unparsed_crate_types.iter() {
for part in unparsed_crate_type.split(',') {
let new_part = match part {
"lib" => default_lib_output(),
"rlib" => CrateTypeRlib,
"staticlib" => CrateTypeStaticlib,
"dylib" => CrateTypeDylib,
"bin" => CrateTypeExecutable,
_ => early_error(format!("unknown crate type: `{}`", part))
};
crate_types.push(new_part)
}
}
let parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans");
let no_analysis = matches.opt_present("no-analysis");
let lint_levels = [lint::allow, lint::warn,
lint::deny, lint::forbid];
let mut lint_opts = Vec::new();
let lint_dict = lint::get_lint_dict();
for level in lint_levels.iter() {
let level_name = lint::level_to_str(*level);
let level_short = level_name.slice_chars(0, 1);
let level_short = level_short.to_ascii().to_upper().into_str();
let flags = matches.opt_strs(level_short).move_iter().collect::<Vec<_>>().append(
matches.opt_strs(level_name).as_slice());
for lint_name in flags.iter() {
let lint_name = lint_name.replace("-", "_");
match lint_dict.find_equiv(&lint_name) {
None => {
early_error(format!("unknown {} flag: {}",
level_name, lint_name));
}
Some(lint) => {
lint_opts.push((lint.lint, *level));
}
}
}
}
let mut debugging_opts = 0;
let debug_flags = matches.opt_strs("Z");
let debug_map = debugging_opts_map();
for debug_flag in debug_flags.iter() {
let mut this_bit = 0;
for tuple in debug_map.iter() {
let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
if *name == *debug_flag { this_bit = bit; break; }
}
if this_bit == 0 {
early_error(format!("unknown debug flag: {}", *debug_flag))
}
debugging_opts |= this_bit;
}
if debugging_opts & DEBUG_LLVM != 0 {
unsafe { llvm::LLVMSetDebug(1); }
}
let mut output_types = Vec::new();
if !parse_only && !no_trans {
let unparsed_output_types = matches.opt_strs("emit");
for unparsed_output_type in unparsed_output_types.iter() {
for part in unparsed_output_type.split(',') {
let output_type = match part.as_slice() {
"asm" => link::OutputTypeAssembly,
"ir" => link::OutputTypeLlvmAssembly,
"bc" => link::OutputTypeBitcode,
"obj" => link::OutputTypeObject,
"link" => link::OutputTypeExe,
_ => early_error(format!("unknown emission type: `{}`", part))
};
output_types.push(output_type)
}
}
};
output_types.as_mut_slice().sort();
output_types.dedup();
if output_types.len() == 0 {
output_types.push(link::OutputTypeExe);
}
let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
let target = matches.opt_str("target").unwrap_or(driver::host_triple().to_owned());
let opt_level = {
if (debugging_opts & NO_OPT) != 0 {
No
} else if matches.opt_present("O") {
if matches.opt_present("opt-level") {
early_error("-O and --opt-level both provided");
}
Default
} else if matches.opt_present("opt-level") {
match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
None |
Some("0") => No,
Some("1") => Less,
Some("2") => Default,
Some("3") => Aggressive,
Some(arg) => {
early_error(format!("optimization level needs to be between 0-3 \
(instead was `{}`)", arg));
}
}
} else {
No
}
};
let gc = debugging_opts & GC != 0;
let debuginfo = if matches.opt_present("g") {
if matches.opt_present("debuginfo") {
early_error("-g and --debuginfo both provided");
}
FullDebugInfo
} else if matches.opt_present("debuginfo") {
match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
Some("0") => NoDebugInfo,
Some("1") => LimitedDebugInfo,
None |
Some("2") => FullDebugInfo,
Some(arg) => {
early_error(format!("optimization level needs to be between 0-3 \
(instead was `{}`)", arg));
}
}
} else {
NoDebugInfo
};
let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
Path::new(s.as_slice())
}).collect();
let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
let test = matches.opt_present("test");
let write_dependency_info = (matches.opt_present("dep-info"),
matches.opt_str("dep-info").map(|p| Path::new(p)));
let print_metas = (matches.opt_present("crate-id"),
matches.opt_present("crate-name"),
matches.opt_present("crate-file-name"));
let cg = build_codegen_options(matches);
Options {
crate_types: crate_types,
gc: gc,
optimize: opt_level,
debuginfo: debuginfo,
lint_opts: lint_opts,
output_types: output_types,
addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
maybe_sysroot: sysroot_opt,
target_triple: target,
cfg: cfg,
test: test,
parse_only: parse_only,
no_trans: no_trans,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
write_dependency_info: write_dependency_info,
print_metas: print_metas,
cg: cg,
}
}
#[cfg(test)]
mod test {
use driver::config::{build_configuration, optgroups, build_session_options};
use driver::session::build_session;
use getopts::getopts;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
let matches =
&match getopts(["--test".to_owned()], optgroups().as_slice()) {
Ok(m) => m,
Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
};
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, None);
let cfg = build_configuration(&sess);
assert!((attr::contains_name(cfg.as_slice(), "test")));
}
// When the user supplies --test and --cfg test, don't implicitly add
// another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
let matches =
&match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
optgroups().as_slice()) {
Ok(m) => m,
Err(f) => {
fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
f.to_err_msg());
}
};
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, None);
let cfg = build_configuration(&sess);
let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
}
}

@ -10,56 +10,89 @@
use back::link;
use back::{arm, x86, x86_64, mips};
use driver::session::{Aggressive, CrateTypeExecutable, CrateType,
FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use driver::session::{Session, No, Less, Default};
use driver::session;
use driver::session::Session;
use driver::config;
use front;
use lib::llvm::llvm;
use lib::llvm::{ContextRef, ModuleRef};
use metadata::common::LinkMeta;
use metadata::{creader, filesearch};
use metadata::cstore::CStore;
use metadata::creader;
use metadata::creader::Loader;
use metadata;
use middle::{trans, freevars, kind, ty, typeck, lint, reachable};
use middle::dependency_format;
use middle;
use util::common::time;
use util::ppaux;
use util::nodemap::{NodeMap, NodeSet};
use util::nodemap::{NodeSet};
use serialize::{json, Encodable};
use std::cell::{Cell, RefCell};
use std::io;
use std::io::fs;
use std::io::MemReader;
use std::os;
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
use syntax::ast;
use syntax::abi;
use syntax::attr;
use syntax::attr::{AttrMetaMethods};
use syntax::codemap;
use syntax::crateid::CrateId;
use syntax::diagnostic;
use syntax::diagnostic::Emitter;
use syntax::ext::base::CrateLoader;
use syntax::parse;
use syntax::parse::token::InternedString;
use syntax::parse::token;
use syntax::print::{pp, pprust};
use syntax;
pub enum PpMode {
PpmNormal,
PpmExpanded,
PpmTyped,
PpmIdentified,
PpmExpandedIdentified
pub fn host_triple() -> &'static str {
// Get the host triple out of the build environment. This ensures that our
// idea of the host triple is the same as for the set of libraries we've
// actually built. We can't just take LLVM's host triple because they
// normalize all ix86 architectures to i386.
//
// Instead of grabbing the host triple (for the current host), we grab (at
// compile time) the target triple that this rustc is built with and
// calling that (at runtime) the host triple.
(option_env!("CFG_COMPILER_HOST_TRIPLE")).
expect("CFG_COMPILER_HOST_TRIPLE")
}
pub fn compile_input(sess: Session,
cfg: ast::CrateConfig,
input: &Input,
outdir: &Option<Path>,
output: &Option<Path>) {
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
let (outputs, trans, sess) = {
let (outputs, expanded_crate, ast_map) = {
let krate = phase_1_parse_input(&sess, cfg, input);
if stop_after_phase_1(&sess) { return; }
let outputs = build_output_filenames(input,
outdir,
output,
krate.attrs.as_slice(),
&sess);
let loader = &mut Loader::new(&sess);
let id = link::find_crate_id(krate.attrs.as_slice(),
outputs.out_filestem);
let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
krate, &id);
(outputs, expanded_crate, ast_map)
};
write_out_deps(&sess, input, &outputs, &expanded_crate);
if stop_after_phase_2(&sess) { return; }
let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
analysis, &outputs);
// Discard interned strings as they are no longer required.
token::get_ident_interner().clear();
(outputs, trans, tcx.sess)
};
phase_5_run_llvm_passes(&sess, &trans, &outputs);
if stop_after_phase_5(&sess) { return; }
phase_6_link_output(&sess, &trans, &outputs);
}
/**
@ -78,78 +111,6 @@ pub fn source_name(input: &Input) -> ~str {
}
}
pub fn default_configuration(sess: &Session) ->
ast::CrateConfig {
let tos = match sess.targ_cfg.os {
abi::OsWin32 => InternedString::new("win32"),
abi::OsMacos => InternedString::new("macos"),
abi::OsLinux => InternedString::new("linux"),
abi::OsAndroid => InternedString::new("android"),
abi::OsFreebsd => InternedString::new("freebsd"),
};
// ARM is bi-endian, however using NDK seems to default
// to little-endian unless a flag is provided.
let (end,arch,wordsz) = match sess.targ_cfg.arch {
abi::X86 => ("little", "x86", "32"),
abi::X86_64 => ("little", "x86_64", "64"),
abi::Arm => ("little", "arm", "32"),
abi::Mips => ("big", "mips", "32")
};
let fam = match sess.targ_cfg.os {
abi::OsWin32 => InternedString::new("windows"),
_ => InternedString::new("unix")
};
let mk = attr::mk_name_value_item_str;
return vec!(// Target bindings.
attr::mk_word_item(fam.clone()),
mk(InternedString::new("target_os"), tos),
mk(InternedString::new("target_family"), fam),
mk(InternedString::new("target_arch"), InternedString::new(arch)),
mk(InternedString::new("target_endian"), InternedString::new(end)),
mk(InternedString::new("target_word_size"),
InternedString::new(wordsz))
);
}
pub fn append_configuration(cfg: &mut ast::CrateConfig,
name: InternedString) {
if !cfg.iter().any(|mi| mi.name() == name) {
cfg.push(attr::mk_word_item(name))
}
}
pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items
let default_cfg = default_configuration(sess);
let mut user_cfg = sess.opts.cfg.clone();
// If the user wants a test runner, then add the test cfg
if sess.opts.test {
append_configuration(&mut user_cfg, InternedString::new("test"))
}
// If the user requested GC, then add the GC cfg
append_configuration(&mut user_cfg, if sess.opts.gc {
InternedString::new("gc")
} else {
InternedString::new("nogc")
});
user_cfg.move_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
}
// Convert strings provided as --cfg [cfgspec] into a crate_cfg
fn parse_cfgspecs(cfgspecs: Vec<~str> )
-> ast::CrateConfig {
cfgspecs.move_iter().map(|s| {
parse::parse_meta_from_source_str("cfgspec".to_strbuf(),
s.to_strbuf(),
Vec::new(),
&parse::new_parse_sess())
}).collect::<ast::CrateConfig>()
}
pub enum Input {
/// Load source from file
FileInput(Path),
@ -183,7 +144,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input)
}
});
if sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0 {
if sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0 {
let mut stdout = io::BufferedWriter::new(io::stdout());
let mut json = json::PrettyEncoder::new(&mut stdout);
// unwrapping so IoError isn't ignored
@ -211,7 +172,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
-> (ast::Crate, syntax::ast_map::Map) {
let time_passes = sess.time_passes();
*sess.crate_types.borrow_mut() = session::collect_crate_types(sess, krate.attrs.as_slice());
*sess.crate_types.borrow_mut() = collect_crate_types(sess, krate.attrs.as_slice());
time(time_passes, "gated feature checking", (), |_|
front::feature_gate::check_crate(sess, &krate));
@ -262,7 +223,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
let (krate, map) = time(time_passes, "assinging node ids and indexing ast", krate, |krate|
front::assign_node_ids_and_map::assign_node_ids_and_map(sess, krate));
if sess.opts.debugging_opts & session::AST_JSON != 0 {
if sess.opts.debugging_opts & config::AST_JSON != 0 {
let mut stdout = io::BufferedWriter::new(io::stdout());
let mut json = json::PrettyEncoder::new(&mut stdout);
// unwrapping so IoError isn't ignored
@ -466,7 +427,7 @@ pub fn stop_after_phase_1(sess: &Session) -> bool {
if sess.show_span() {
return true;
}
return sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0;
return sess.opts.debugging_opts & config::AST_JSON_NOEXPAND != 0;
}
pub fn stop_after_phase_2(sess: &Session) -> bool {
@ -474,7 +435,7 @@ pub fn stop_after_phase_2(sess: &Session) -> bool {
debug!("invoked with --no-analysis, returning early from compile_input");
return true;
}
return sess.opts.debugging_opts & session::AST_JSON != 0;
return sess.opts.debugging_opts & config::AST_JSON != 0;
}
pub fn stop_after_phase_5(sess: &Session) -> bool {
@ -547,46 +508,6 @@ fn write_out_deps(sess: &Session,
}
}
pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &Input,
outdir: &Option<Path>, output: &Option<Path>) {
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
let (outputs, trans, sess) = {
let (outputs, expanded_crate, ast_map) = {
let krate = phase_1_parse_input(&sess, cfg, input);
if stop_after_phase_1(&sess) { return; }
let outputs = build_output_filenames(input,
outdir,
output,
krate.attrs.as_slice(),
&sess);
let loader = &mut Loader::new(&sess);
let id = link::find_crate_id(krate.attrs.as_slice(),
outputs.out_filestem);
let (expanded_crate, ast_map) = phase_2_configure_and_expand(&sess, loader,
krate, &id);
(outputs, expanded_crate, ast_map)
};
write_out_deps(&sess, input, &outputs, &expanded_crate);
if stop_after_phase_2(&sess) { return; }
let analysis = phase_3_run_analysis_passes(sess, &expanded_crate, ast_map);
if stop_after_phase_3(&analysis.ty_cx.sess) { return; }
let (tcx, trans) = phase_4_translate_to_llvm(expanded_crate,
analysis, &outputs);
// Discard interned strings as they are no longer required.
token::get_ident_interner().clear();
(outputs, trans, tcx.sess)
};
phase_5_run_llvm_passes(&sess, &trans, &outputs);
if stop_after_phase_5(&sess) { return; }
phase_6_link_output(&sess, &trans, &outputs);
}
struct IdentifiedAnnotation;
impl pprust::PpAnn for IdentifiedAnnotation {
@ -657,7 +578,7 @@ impl pprust::PpAnn for TypedAnnotation {
pub fn pretty_print_input(sess: Session,
cfg: ast::CrateConfig,
input: &Input,
ppm: PpMode,
ppm: ::driver::PpMode,
ofile: Option<Path>) {
let krate = phase_1_parse_input(&sess, cfg, input);
let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem());
@ -727,403 +648,58 @@ pub fn pretty_print_input(sess: Session,
}
pub fn get_os(triple: &str) -> Option<abi::Os> {
for &(name, os) in os_names.iter() {
if triple.contains(name) { return Some(os) }
}
None
}
static os_names : &'static [(&'static str, abi::Os)] = &'static [
("mingw32", abi::OsWin32),
("win32", abi::OsWin32),
("darwin", abi::OsMacos),
("android", abi::OsAndroid),
("linux", abi::OsLinux),
("freebsd", abi::OsFreebsd)];
pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
for &(arch, abi) in architecture_abis.iter() {
if triple.contains(arch) { return Some(abi) }
}
None
}
static architecture_abis : &'static [(&'static str, abi::Architecture)] = &'static [
("i386", abi::X86),
("i486", abi::X86),
("i586", abi::X86),
("i686", abi::X86),
("i786", abi::X86),
("x86_64", abi::X86_64),
("arm", abi::Arm),
("xscale", abi::Arm),
("thumb", abi::Arm),
("mips", abi::Mips)];
pub fn build_target_config(sopts: &session::Options) -> session::Config {
let os = match get_os(sopts.target_triple) {
Some(os) => os,
None => early_error("unknown operating system")
};
let arch = match get_arch(sopts.target_triple) {
Some(arch) => arch,
None => early_error("unknown architecture: " + sopts.target_triple)
};
let (int_type, uint_type) = match arch {
abi::X86 => (ast::TyI32, ast::TyU32),
abi::X86_64 => (ast::TyI64, ast::TyU64),
abi::Arm => (ast::TyI32, ast::TyU32),
abi::Mips => (ast::TyI32, ast::TyU32)
};
let target_triple = sopts.target_triple.clone();
let target_strs = match arch {
abi::X86 => x86::get_target_strs(target_triple, os),
abi::X86_64 => x86_64::get_target_strs(target_triple, os),
abi::Arm => arm::get_target_strs(target_triple, os),
abi::Mips => mips::get_target_strs(target_triple, os)
};
session::Config {
os: os,
arch: arch,
target_strs: target_strs,
int_type: int_type,
uint_type: uint_type,
}
}
pub fn host_triple() -> &'static str {
// Get the host triple out of the build environment. This ensures that our
// idea of the host triple is the same as for the set of libraries we've
// actually built. We can't just take LLVM's host triple because they
// normalize all ix86 architectures to i386.
//
// Instead of grabbing the host triple (for the current host), we grab (at
// compile time) the target triple that this rustc is built with and
// calling that (at runtime) the host triple.
(option_env!("CFG_COMPILER_HOST_TRIPLE")).
expect("CFG_COMPILER_HOST_TRIPLE")
}
pub fn build_session_options(matches: &getopts::Matches) -> session::Options {
let mut crate_types: Vec<CrateType> = Vec::new();
let unparsed_crate_types = matches.opt_strs("crate-type");
for unparsed_crate_type in unparsed_crate_types.iter() {
for part in unparsed_crate_type.split(',') {
let new_part = match part {
"lib" => session::default_lib_output(),
"rlib" => session::CrateTypeRlib,
"staticlib" => session::CrateTypeStaticlib,
"dylib" => session::CrateTypeDylib,
"bin" => session::CrateTypeExecutable,
_ => early_error(format!("unknown crate type: `{}`", part))
};
crate_types.push(new_part)
}
pub fn collect_crate_types(session: &Session,
attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
// If we're generating a test executable, then ignore all other output
// styles at all other locations
if session.opts.test {
return vec!(config::CrateTypeExecutable)
}
let parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans");
let no_analysis = matches.opt_present("no-analysis");
let lint_levels = [lint::allow, lint::warn,
lint::deny, lint::forbid];
let mut lint_opts = Vec::new();
let lint_dict = lint::get_lint_dict();
for level in lint_levels.iter() {
let level_name = lint::level_to_str(*level);
let level_short = level_name.slice_chars(0, 1);
let level_short = level_short.to_ascii().to_upper().into_str();
let flags = matches.opt_strs(level_short).move_iter().collect::<Vec<_>>().append(
matches.opt_strs(level_name).as_slice());
for lint_name in flags.iter() {
let lint_name = lint_name.replace("-", "_");
match lint_dict.find_equiv(&lint_name) {
None => {
early_error(format!("unknown {} flag: {}",
level_name, lint_name));
}
Some(lint) => {
lint_opts.push((lint.lint, *level));
}
}
}
}
let mut debugging_opts = 0;
let debug_flags = matches.opt_strs("Z");
let debug_map = session::debugging_opts_map();
for debug_flag in debug_flags.iter() {
let mut this_bit = 0;
for tuple in debug_map.iter() {
let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
if *name == *debug_flag { this_bit = bit; break; }
}
if this_bit == 0 {
early_error(format!("unknown debug flag: {}", *debug_flag))
}
debugging_opts |= this_bit;
}
if debugging_opts & session::DEBUG_LLVM != 0 {
unsafe { llvm::LLVMSetDebug(1); }
}
let mut output_types = Vec::new();
if !parse_only && !no_trans {
let unparsed_output_types = matches.opt_strs("emit");
for unparsed_output_type in unparsed_output_types.iter() {
for part in unparsed_output_type.split(',') {
let output_type = match part.as_slice() {
"asm" => link::OutputTypeAssembly,
"ir" => link::OutputTypeLlvmAssembly,
"bc" => link::OutputTypeBitcode,
"obj" => link::OutputTypeObject,
"link" => link::OutputTypeExe,
_ => early_error(format!("unknown emission type: `{}`", part))
};
output_types.push(output_type)
}
}
};
output_types.as_mut_slice().sort();
output_types.dedup();
if output_types.len() == 0 {
output_types.push(link::OutputTypeExe);
}
let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
let target = matches.opt_str("target").unwrap_or(host_triple().to_owned());
let opt_level = {
if (debugging_opts & session::NO_OPT) != 0 {
No
} else if matches.opt_present("O") {
if matches.opt_present("opt-level") {
early_error("-O and --opt-level both provided");
}
Default
} else if matches.opt_present("opt-level") {
match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
None |
Some("0") => No,
Some("1") => Less,
Some("2") => Default,
Some("3") => Aggressive,
Some(arg) => {
early_error(format!("optimization level needs to be between 0-3 \
(instead was `{}`)", arg));
}
}
} else {
No
}
};
let gc = debugging_opts & session::GC != 0;
let debuginfo = if matches.opt_present("g") {
if matches.opt_present("debuginfo") {
early_error("-g and --debuginfo both provided");
}
FullDebugInfo
} else if matches.opt_present("debuginfo") {
match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
Some("0") => NoDebugInfo,
Some("1") => LimitedDebugInfo,
None |
Some("2") => FullDebugInfo,
Some(arg) => {
early_error(format!("optimization level needs to be between 0-3 \
(instead was `{}`)", arg));
}
}
// Only check command line flags if present. If no types are specified by
// command line, then reuse the empty `base` Vec to hold the types that
// will be found in crate attributes.
let mut base = session.opts.crate_types.clone();
if base.len() > 0 {
return base
} else {
NoDebugInfo
};
let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
Path::new(s.as_slice())
}).collect();
let cfg = parse_cfgspecs(matches.opt_strs("cfg").move_iter().collect());
let test = matches.opt_present("test");
let write_dependency_info = (matches.opt_present("dep-info"),
matches.opt_str("dep-info").map(|p| Path::new(p)));
let print_metas = (matches.opt_present("crate-id"),
matches.opt_present("crate-name"),
matches.opt_present("crate-file-name"));
let cg = build_codegen_options(matches);
session::Options {
crate_types: crate_types,
gc: gc,
optimize: opt_level,
debuginfo: debuginfo,
lint_opts: lint_opts,
output_types: output_types,
addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
maybe_sysroot: sysroot_opt,
target_triple: target,
cfg: cfg,
test: test,
parse_only: parse_only,
no_trans: no_trans,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
write_dependency_info: write_dependency_info,
print_metas: print_metas,
cg: cg,
}
}
pub fn build_codegen_options(matches: &getopts::Matches)
-> session::CodegenOptions
{
let mut cg = session::basic_codegen_options();
for option in matches.opt_strs("C").move_iter() {
let mut iter = option.splitn('=', 1);
let key = iter.next().unwrap();
let value = iter.next();
let option_to_lookup = key.replace("-", "_");
let mut found = false;
for &(candidate, setter, _) in session::CG_OPTIONS.iter() {
if option_to_lookup.as_slice() != candidate { continue }
if !setter(&mut cg, value) {
match value {
Some(..) => early_error(format!("codegen option `{}` takes \
no value", key)),
None => early_error(format!("codegen option `{0}` requires \
a value (-C {0}=<value>)",
key))
let iter = attrs.iter().filter_map(|a| {
if a.name().equiv(&("crate_type")) {
match a.value_str() {
Some(ref n) if n.equiv(&("rlib")) => Some(config::CrateTypeRlib),
Some(ref n) if n.equiv(&("dylib")) => Some(config::CrateTypeDylib),
Some(ref n) if n.equiv(&("lib")) => {
Some(config::default_lib_output())
}
Some(ref n) if n.equiv(&("staticlib")) => {
Some(config::CrateTypeStaticlib)
}
Some(ref n) if n.equiv(&("bin")) => Some(config::CrateTypeExecutable),
Some(_) => {
session.add_lint(lint::UnknownCrateType,
ast::CRATE_NODE_ID,
a.span,
"invalid `crate_type` value".to_owned());
None
}
_ => {
session.add_lint(lint::UnknownCrateType, ast::CRATE_NODE_ID,
a.span, "`crate_type` requires a value".to_owned());
None
}
}
} else {
None
}
found = true;
break;
}
if !found {
early_error(format!("unknown codegen option: `{}`", key));
});
base.extend(iter);
if base.len() == 0 {
base.push(config::CrateTypeExecutable);
}
base.as_mut_slice().sort();
base.dedup();
return base;
}
return cg;
}
pub fn build_session(sopts: session::Options,
local_crate_source_file: Option<Path>)
-> Session {
let codemap = codemap::CodeMap::new();
let diagnostic_handler =
diagnostic::default_handler();
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
}
pub fn build_session_(sopts: session::Options,
local_crate_source_file: Option<Path>,
span_diagnostic: diagnostic::SpanHandler)
-> Session {
let target_cfg = build_target_config(&sopts);
let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
let default_sysroot = match sopts.maybe_sysroot {
Some(_) => None,
None => Some(filesearch::get_or_default_sysroot())
};
// Make the path absolute, if necessary
let local_crate_source_file = local_crate_source_file.map(|path|
if path.is_absolute() {
path.clone()
} else {
os::getcwd().join(path.clone())
}
);
Session {
targ_cfg: target_cfg,
opts: sopts,
cstore: CStore::new(token::get_ident_interner()),
parse_sess: p_s,
// For a library crate, this is always none
entry_fn: RefCell::new(None),
entry_type: Cell::new(None),
macro_registrar_fn: Cell::new(None),
default_sysroot: default_sysroot,
local_crate_source_file: local_crate_source_file,
working_dir: os::getcwd(),
lints: RefCell::new(NodeMap::new()),
node_id: Cell::new(1),
crate_types: RefCell::new(Vec::new()),
features: front::feature_gate::Features::new(),
recursion_limit: Cell::new(64),
}
}
pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
match name {
"normal" => PpmNormal,
"expanded" => PpmExpanded,
"typed" => PpmTyped,
"expanded,identified" => PpmExpandedIdentified,
"identified" => PpmIdentified,
_ => {
sess.fatal("argument to `pretty` must be one of `normal`, \
`expanded`, `typed`, `identified`, \
or `expanded,identified`");
}
}
}
// rustc command line options
pub fn optgroups() -> Vec<getopts::OptGroup> {
vec!(
optflag("h", "help", "Display this message"),
optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
optmulti("L", "", "Add a directory to the library search path", "PATH"),
optmulti("", "crate-type", "Comma separated list of types of crates for the compiler to emit",
"[bin|lib|rlib|dylib|staticlib]"),
optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
"[asm|bc|ir|obj|link]"),
optflag("", "crate-id", "Output the crate id and exit"),
optflag("", "crate-name", "Output the crate name and exit"),
optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
continued and exit"),
optflag("g", "", "Equivalent to --debuginfo=2"),
optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
0 = no debug info,
1 = line-tables only (for stacktraces and breakpoints),
2 = full debug info with variable and type information (same as -g)", "LEVEL"),
optflag("", "no-trans", "Run all passes except translation; no output"),
optflag("", "no-analysis",
"Parse and expand the source, but run no analysis and produce no output"),
optflag("O", "", "Equivalent to --opt-level=2"),
optopt("o", "", "Write output to <filename>", "FILENAME"),
optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
optflagopt("", "pretty",
"Pretty-print the input instead of compiling;
valid types are: normal (un-annotated source),
expanded (crates expanded),
typed (crates expanded, with type annotations),
or identified (fully parenthesized,
AST nodes and blocks with IDs)", "TYPE"),
optflagopt("", "dep-info",
"Output dependency info to <filename> after compiling, \
in a format suitable for use by Makefiles", "FILENAME"),
optopt("", "sysroot", "Override the system root", "PATH"),
optflag("", "test", "Build a test harness"),
optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
for details)", "TRIPLE"),
optmulti("W", "warn", "Set lint warnings", "OPT"),
optmulti("A", "allow", "Set lint allowed", "OPT"),
optmulti("D", "deny", "Set lint denied", "OPT"),
optmulti("F", "forbid", "Set lint forbidden", "OPT"),
optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
optmulti("Z", "", "Set internal debugging options", "FLAG"),
optflag( "v", "version", "Print version info and exit"))
}
pub struct OutputFilenames {
@ -1209,60 +785,3 @@ pub fn build_output_filenames(input: &Input,
}
}
pub fn early_error(msg: &str) -> ! {
let mut emitter = diagnostic::EmitterWriter::stderr();
emitter.emit(None, msg, diagnostic::Fatal);
fail!(diagnostic::FatalError);
}
pub fn list_metadata(sess: &Session, path: &Path,
out: &mut io::Writer) -> io::IoResult<()> {
metadata::loader::list_file_metadata(
session::sess_os_to_meta_os(sess.targ_cfg.os), path, out)
}
#[cfg(test)]
mod test {
use driver::driver::{build_configuration, build_session};
use driver::driver::{build_session_options, optgroups};
use getopts::getopts;
use syntax::attr;
use syntax::attr::AttrMetaMethods;
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
let matches =
&match getopts(["--test".to_owned()], optgroups().as_slice()) {
Ok(m) => m,
Err(f) => fail!("test_switch_implies_cfg_test: {}", f.to_err_msg())
};
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, None);
let cfg = build_configuration(&sess);
assert!((attr::contains_name(cfg.as_slice(), "test")));
}
// When the user supplies --test and --cfg test, don't implicitly add
// another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
let matches =
&match getopts(["--test".to_owned(), "--cfg=test".to_owned()],
optgroups().as_slice()) {
Ok(m) => m,
Err(f) => {
fail!("test_switch_implies_cfg_test_unless_cfg_test: {}",
f.to_err_msg());
}
};
let sessopts = build_session_options(matches);
let sess = build_session(sessopts, None);
let cfg = build_configuration(&sess);
let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
assert!(test_items.next().is_some());
assert!(test_items.next().is_none());
}
}

@ -10,5 +10,391 @@
pub use syntax::diagnostic;
use back::link;
use driver::driver::{Input, FileInput, StrInput};
use driver::session::{Session, build_session};
use middle::lint;
use metadata;
use std::any::AnyRefExt;
use std::cmp;
use std::io;
use std::os;
use std::str;
use std::task::TaskBuilder;
use syntax::ast;
use syntax::parse;
use syntax::diagnostic::Emitter;
use getopts;
pub mod driver;
pub mod session;
pub mod config;
pub fn main_args(args: &[~str]) -> int {
let owned_args = args.to_owned();
monitor(proc() run_compiler(owned_args));
0
}
static BUG_REPORT_URL: &'static str =
"http://static.rust-lang.org/doc/master/complement-bugreport.html";
fn run_compiler(args: &[~str]) {
let matches = match handle_options(Vec::from_slice(args)) {
Some(matches) => matches,
None => return
};
let (input, input_file_path) = match matches.free.len() {
0u => early_error("no input filename given"),
1u => {
let ifile = matches.free.get(0).as_slice();
if ifile == "-" {
let contents = io::stdin().read_to_end().unwrap();
let src = str::from_utf8(contents.as_slice()).unwrap().to_owned();
(StrInput(src), None)
} else {
(FileInput(Path::new(ifile)), Some(Path::new(ifile)))
}
}
_ => early_error("multiple input filenames provided")
};
let sopts = config::build_session_options(&matches);
let sess = build_session(sopts, input_file_path);
let cfg = config::build_configuration(&sess);
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
let ofile = matches.opt_str("o").map(|o| Path::new(o));
let pretty = matches.opt_default("pretty", "normal").map(|a| {
parse_pretty(&sess, a)
});
match pretty {
Some::<PpMode>(ppm) => {
driver::pretty_print_input(sess, cfg, &input, ppm, ofile);
return;
}
None::<PpMode> => {/* continue */ }
}
let r = matches.opt_strs("Z");
if r.contains(&("ls".to_owned())) {
match input {
FileInput(ref ifile) => {
let mut stdout = io::stdout();
list_metadata(&sess, &(*ifile), &mut stdout).unwrap();
}
StrInput(_) => {
early_error("can not list metadata for stdin");
}
}
return;
}
if print_crate_info(&sess, &input, &odir, &ofile) {
return;
}
driver::compile_input(sess, cfg, &input, &odir, &ofile);
}
pub fn version(argv0: &str) {
let vers = match option_env!("CFG_VERSION") {
Some(vers) => vers,
None => "unknown version"
};
println!("{} {}", argv0, vers);
println!("host: {}", driver::host_triple());
}
fn usage(argv0: &str) {
let message = format!("Usage: {} [OPTIONS] INPUT", argv0);
println!("{}\n\
Additional help:
-C help Print codegen options
-W help Print 'lint' options and default settings
-Z help Print internal options for debugging rustc\n",
getopts::usage(message, config::optgroups().as_slice()));
}
fn describe_warnings() {
println!("
Available lint options:
-W <foo> Warn about <foo>
-A <foo> Allow <foo>
-D <foo> Deny <foo>
-F <foo> Forbid <foo> (deny, and deny all overrides)
");
let lint_dict = lint::get_lint_dict();
let mut lint_dict = lint_dict.move_iter()
.map(|(k, v)| (v, k))
.collect::<Vec<(lint::LintSpec, &'static str)> >();
lint_dict.as_mut_slice().sort();
let mut max_key = 0;
for &(_, name) in lint_dict.iter() {
max_key = cmp::max(name.len(), max_key);
}
fn padded(max: uint, s: &str) -> ~str {
" ".repeat(max - s.len()) + s
}
println!("\nAvailable lint checks:\n");
println!(" {} {:7.7s} {}",
padded(max_key, "name"), "default", "meaning");
println!(" {} {:7.7s} {}\n",
padded(max_key, "----"), "-------", "-------");
for (spec, name) in lint_dict.move_iter() {
let name = name.replace("_", "-");
println!(" {} {:7.7s} {}",
padded(max_key, name),
lint::level_to_str(spec.default),
spec.desc);
}
println!("");
}
fn describe_debug_flags() {
println!("\nAvailable debug options:\n");
let r = config::debugging_opts_map();
for tuple in r.iter() {
match *tuple {
(ref name, ref desc, _) => {
println!(" -Z {:>20s} -- {}", *name, *desc);
}
}
}
}
fn describe_codegen_flags() {
println!("\nAvailable codegen options:\n");
let mut cg = config::basic_codegen_options();
for &(name, parser, desc) in config::CG_OPTIONS.iter() {
// we invoke the parser function on `None` to see if this option needs
// an argument or not.
let (width, extra) = if parser(&mut cg, None) {
(25, "")
} else {
(21, "=val")
};
println!(" -C {:>width$s}{} -- {}", name.replace("_", "-"),
extra, desc, width=width);
}
}
/// Process command line options. Emits messages as appropirate.If compilation
/// should continue, returns a getopts::Matches object parsed from args, otherwise
/// returns None.
pub fn handle_options(mut args: Vec<~str>) -> Option<getopts::Matches> {
let binary = args.shift().unwrap();
if args.is_empty() { usage(binary); return None; }
let matches =
match getopts::getopts(args.as_slice(), config::optgroups().as_slice()) {
Ok(m) => m,
Err(f) => {
early_error(f.to_err_msg());
}
};
if matches.opt_present("h") || matches.opt_present("help") {
usage(binary);
return None;
}
let lint_flags = matches.opt_strs("W").move_iter().collect::<Vec<_>>().append(
matches.opt_strs("warn").as_slice());
if lint_flags.iter().any(|x| x == &"help".to_owned()) {
describe_warnings();
return None;
}
let r = matches.opt_strs("Z");
if r.iter().any(|x| x == &"help".to_owned()) {
describe_debug_flags();
return None;
}
let cg_flags = matches.opt_strs("C");
if cg_flags.iter().any(|x| x == &"help".to_owned()) {
describe_codegen_flags();
return None;
}
if cg_flags.contains(&"passes=list".to_owned()) {
unsafe { ::lib::llvm::llvm::LLVMRustPrintPasses(); }
return None;
}
if matches.opt_present("v") || matches.opt_present("version") {
version(binary);
return None;
}
Some(matches)
}
fn print_crate_info(sess: &Session,
input: &Input,
odir: &Option<Path>,
ofile: &Option<Path>)
-> bool {
let (crate_id, crate_name, crate_file_name) = sess.opts.print_metas;
// these nasty nested conditions are to avoid doing extra work
if crate_id || crate_name || crate_file_name {
let attrs = parse_crate_attrs(sess, input);
let t_outputs = driver::build_output_filenames(input, odir, ofile,
attrs.as_slice(), sess);
let id = link::find_crate_id(attrs.as_slice(), t_outputs.out_filestem);
if crate_id {
println!("{}", id.to_str());
}
if crate_name {
println!("{}", id.name);
}
if crate_file_name {
let crate_types = driver::collect_crate_types(sess, attrs.as_slice());
for &style in crate_types.iter() {
let fname = link::filename_for_input(sess, style, &id,
&t_outputs.with_extension(""));
println!("{}", fname.filename_display());
}
}
true
} else {
false
}
}
pub enum PpMode {
PpmNormal,
PpmExpanded,
PpmTyped,
PpmIdentified,
PpmExpandedIdentified
}
pub fn parse_pretty(sess: &Session, name: &str) -> PpMode {
match name {
"normal" => PpmNormal,
"expanded" => PpmExpanded,
"typed" => PpmTyped,
"expanded,identified" => PpmExpandedIdentified,
"identified" => PpmIdentified,
_ => {
sess.fatal("argument to `pretty` must be one of `normal`, \
`expanded`, `typed`, `identified`, \
or `expanded,identified`");
}
}
}
fn parse_crate_attrs(sess: &Session, input: &Input) ->
Vec<ast::Attribute> {
let result = match *input {
FileInput(ref ifile) => {
parse::parse_crate_attrs_from_file(ifile,
Vec::new(),
&sess.parse_sess)
}
StrInput(ref src) => {
parse::parse_crate_attrs_from_source_str(
driver::anon_src().to_strbuf(),
src.to_strbuf(),
Vec::new(),
&sess.parse_sess)
}
};
result.move_iter().collect()
}
pub fn early_error(msg: &str) -> ! {
let mut emitter = diagnostic::EmitterWriter::stderr();
emitter.emit(None, msg, diagnostic::Fatal);
fail!(diagnostic::FatalError);
}
pub fn list_metadata(sess: &Session, path: &Path,
out: &mut io::Writer) -> io::IoResult<()> {
metadata::loader::list_file_metadata(
config::cfg_os_to_meta_os(sess.targ_cfg.os), path, out)
}
/// Run a procedure which will detect failures in the compiler and print nicer
/// error messages rather than just failing the test.
///
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
fn monitor(f: proc():Send) {
// FIXME: This is a hack for newsched since it doesn't support split stacks.
// rustc needs a lot of stack! When optimizations are disabled, it needs
// even *more* stack than usual as well.
#[cfg(rtopt)]
static STACK_SIZE: uint = 6000000; // 6MB
#[cfg(not(rtopt))]
static STACK_SIZE: uint = 20000000; // 20MB
let mut task_builder = TaskBuilder::new().named("rustc");
// FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
if os::getenv("RUST_MIN_STACK").is_none() {
task_builder.opts.stack_size = Some(STACK_SIZE);
}
let (tx, rx) = channel();
let w = io::ChanWriter::new(tx);
let mut r = io::ChanReader::new(rx);
match task_builder.try(proc() {
io::stdio::set_stderr(box w);
f()
}) {
Ok(()) => { /* fallthrough */ }
Err(value) => {
// Task failed without emitting a fatal diagnostic
if !value.is::<diagnostic::FatalError>() {
let mut emitter = diagnostic::EmitterWriter::stderr();
// a .span_bug or .bug call has already printed what
// it wants to print.
if !value.is::<diagnostic::ExplicitBug>() {
emitter.emit(
None,
"unexpected failure",
diagnostic::Bug);
}
let xs = [
"the compiler hit an unexpected failure path. this is a bug.".to_owned(),
"we would appreciate a bug report: " + BUG_REPORT_URL,
"run with `RUST_BACKTRACE=1` for a backtrace".to_owned(),
];
for note in xs.iter() {
emitter.emit(None, *note, diagnostic::Note)
}
match r.read_to_str() {
Ok(s) => println!("{}", s),
Err(e) => emitter.emit(None,
format!("failed to read internal stderr: {}", e),
diagnostic::Error),
}
}
// Fail so the process returns a failure code, but don't pollute the
// output with some unnecessary failure messages, we've already
// printed everything that we needed to.
io::stdio::set_stderr(box io::util::NullWriter);
fail!();
}
}
}

@ -9,179 +9,34 @@
// except according to those terms.
use back::target_strs;
use back;
use driver::driver::host_triple;
use driver::config;
use driver::driver;
use front;
use metadata::cstore::CStore;
use metadata::filesearch;
use metadata;
use middle::lint;
use util::nodemap::NodeMap;
use syntax::attr::AttrMetaMethods;
use syntax::ast::NodeId;
use syntax::ast::{IntTy, UintTy};
use syntax::codemap::Span;
use syntax::diagnostic;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::ParseSess;
use syntax::{abi, ast, codemap};
use syntax::{ast, codemap};
use std::os;
use std::cell::{Cell, RefCell};
use collections::HashSet;
pub struct Config {
pub os: abi::Os,
pub arch: abi::Architecture,
pub target_strs: target_strs::t,
pub int_type: IntTy,
pub uint_type: UintTy,
}
macro_rules! debugging_opts(
([ $opt:ident ] $cnt:expr ) => (
pub static $opt: u64 = 1 << $cnt;
);
([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
pub static $opt: u64 = 1 << $cnt;
debugging_opts!([ $($rest),* ] $cnt + 1)
)
)
debugging_opts!(
[
VERBOSE,
TIME_PASSES,
COUNT_LLVM_INSNS,
TIME_LLVM_PASSES,
TRANS_STATS,
ASM_COMMENTS,
NO_VERIFY,
BORROWCK_STATS,
NO_LANDING_PADS,
DEBUG_LLVM,
SHOW_SPAN,
COUNT_TYPE_SIZES,
META_STATS,
NO_OPT,
GC,
PRINT_LINK_ARGS,
PRINT_LLVM_PASSES,
LTO,
AST_JSON,
AST_JSON_NOEXPAND,
LS
]
0
)
pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
vec!(("verbose", "in general, enable more debug printouts", VERBOSE),
("time-passes", "measure time of each rustc pass", TIME_PASSES),
("count-llvm-insns", "count where LLVM \
instrs originate", COUNT_LLVM_INSNS),
("time-llvm-passes", "measure time of each LLVM pass",
TIME_LLVM_PASSES),
("trans-stats", "gather trans statistics", TRANS_STATS),
("asm-comments", "generate comments into the assembly (may change behavior)",
ASM_COMMENTS),
("no-verify", "skip LLVM verification", NO_VERIFY),
("borrowck-stats", "gather borrowck statistics", BORROWCK_STATS),
("no-landing-pads", "omit landing pads for unwinding",
NO_LANDING_PADS),
("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
("show-span", "show spans for compiler debugging", SHOW_SPAN),
("count-type-sizes", "count the sizes of aggregate types",
COUNT_TYPE_SIZES),
("meta-stats", "gather metadata statistics", META_STATS),
("no-opt", "do not optimize, even if -O is passed", NO_OPT),
("print-link-args", "Print the arguments passed to the linker",
PRINT_LINK_ARGS),
("gc", "Garbage collect shared data (experimental)", GC),
("print-llvm-passes",
"Prints the llvm optimization passes being run",
PRINT_LLVM_PASSES),
("lto", "Perform LLVM link-time optimizations", LTO),
("ast-json", "Print the AST as JSON and halt", AST_JSON),
("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
("ls", "List the symbols defined by a library crate", LS))
}
#[deriving(Clone, Eq)]
pub enum OptLevel {
No, // -O0
Less, // -O1
Default, // -O2
Aggressive // -O3
}
#[deriving(Clone, Eq)]
pub enum DebugInfoLevel {
NoDebugInfo,
LimitedDebugInfo,
FullDebugInfo,
}
#[deriving(Clone)]
pub struct Options {
// The crate config requested for the session, which may be combined
// with additional crate configurations during the compile process
pub crate_types: Vec<CrateType>,
pub gc: bool,
pub optimize: OptLevel,
pub debuginfo: DebugInfoLevel,
pub lint_opts: Vec<(lint::Lint, lint::level)> ,
pub output_types: Vec<back::link::OutputType> ,
// This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use
// this.
pub addl_lib_search_paths: RefCell<HashSet<Path>>,
pub maybe_sysroot: Option<Path>,
pub target_triple: ~str,
// User-specified cfg meta items. The compiler itself will add additional
// items to the crate config, and during parsing the entire crate config
// will be added to the crate AST node. This should not be used for
// anything except building the full crate config prior to parsing.
pub cfg: ast::CrateConfig,
pub test: bool,
pub parse_only: bool,
pub no_trans: bool,
pub no_analysis: bool,
pub debugging_opts: u64,
/// Whether to write dependency files. It's (enabled, optional filename).
pub write_dependency_info: (bool, Option<Path>),
/// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
pub print_metas: (bool, bool, bool),
pub cg: CodegenOptions,
}
// The type of entry function, so
// users can have their own entry
// functions that don't start a
// scheduler
#[deriving(Eq)]
pub enum EntryFnType {
EntryMain,
EntryStart,
EntryNone,
}
#[deriving(Eq, Ord, Clone, TotalOrd, TotalEq, Hash)]
pub enum CrateType {
CrateTypeExecutable,
CrateTypeDylib,
CrateTypeRlib,
CrateTypeStaticlib,
}
pub struct Session {
pub targ_cfg: Config,
pub opts: Options,
pub cstore: metadata::cstore::CStore,
pub targ_cfg: config::Config,
pub opts: config::Options,
pub cstore: CStore,
pub parse_sess: ParseSess,
// For a library crate, this is always none
pub entry_fn: RefCell<Option<(NodeId, codemap::Span)>>,
pub entry_type: Cell<Option<EntryFnType>>,
pub entry_type: Cell<Option<config::EntryFnType>>,
pub macro_registrar_fn: Cell<Option<ast::NodeId>>,
pub default_sysroot: Option<Path>,
// The name of the root source file of the crate, in the local file system. The path is always
@ -190,7 +45,7 @@ pub struct Session {
pub working_dir: Path,
pub lints: RefCell<NodeMap<Vec<(lint::Lint, codemap::Span, ~str)>>>,
pub node_id: Cell<ast::NodeId>,
pub crate_types: RefCell<Vec<CrateType>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub features: front::feature_gate::Features,
/// The maximum recursion limit for potentially infinitely recursive
@ -289,33 +144,33 @@ impl Session {
pub fn impossible_case(&self, sp: Span, msg: &str) -> ! {
self.span_bug(sp, format!("impossible case reached: {}", msg));
}
pub fn verbose(&self) -> bool { self.debugging_opt(VERBOSE) }
pub fn time_passes(&self) -> bool { self.debugging_opt(TIME_PASSES) }
pub fn verbose(&self) -> bool { self.debugging_opt(config::VERBOSE) }
pub fn time_passes(&self) -> bool { self.debugging_opt(config::TIME_PASSES) }
pub fn count_llvm_insns(&self) -> bool {
self.debugging_opt(COUNT_LLVM_INSNS)
self.debugging_opt(config::COUNT_LLVM_INSNS)
}
pub fn count_type_sizes(&self) -> bool {
self.debugging_opt(COUNT_TYPE_SIZES)
self.debugging_opt(config::COUNT_TYPE_SIZES)
}
pub fn time_llvm_passes(&self) -> bool {
self.debugging_opt(TIME_LLVM_PASSES)
self.debugging_opt(config::TIME_LLVM_PASSES)
}
pub fn trans_stats(&self) -> bool { self.debugging_opt(TRANS_STATS) }
pub fn meta_stats(&self) -> bool { self.debugging_opt(META_STATS) }
pub fn asm_comments(&self) -> bool { self.debugging_opt(ASM_COMMENTS) }
pub fn no_verify(&self) -> bool { self.debugging_opt(NO_VERIFY) }
pub fn borrowck_stats(&self) -> bool { self.debugging_opt(BORROWCK_STATS) }
pub fn trans_stats(&self) -> bool { self.debugging_opt(config::TRANS_STATS) }
pub fn meta_stats(&self) -> bool { self.debugging_opt(config::META_STATS) }
pub fn asm_comments(&self) -> bool { self.debugging_opt(config::ASM_COMMENTS) }
pub fn no_verify(&self) -> bool { self.debugging_opt(config::NO_VERIFY) }
pub fn borrowck_stats(&self) -> bool { self.debugging_opt(config::BORROWCK_STATS) }
pub fn print_llvm_passes(&self) -> bool {
self.debugging_opt(PRINT_LLVM_PASSES)
self.debugging_opt(config::PRINT_LLVM_PASSES)
}
pub fn lto(&self) -> bool {
self.debugging_opt(LTO)
self.debugging_opt(config::LTO)
}
pub fn no_landing_pads(&self) -> bool {
self.debugging_opt(NO_LANDING_PADS)
self.debugging_opt(config::NO_LANDING_PADS)
}
pub fn show_span(&self) -> bool {
self.debugging_opt(SHOW_SPAN)
self.debugging_opt(config::SHOW_SPAN)
}
pub fn sysroot<'a>(&'a self) -> &'a Path {
match self.opts.maybe_sysroot {
@ -333,142 +188,63 @@ impl Session {
pub fn host_filesearch<'a>(&'a self) -> filesearch::FileSearch<'a> {
filesearch::FileSearch::new(
self.sysroot(),
host_triple(),
driver::host_triple(),
&self.opts.addl_lib_search_paths)
}
}
/// Some reasonable defaults
pub fn basic_options() -> Options {
Options {
crate_types: Vec::new(),
gc: false,
optimize: No,
debuginfo: NoDebugInfo,
lint_opts: Vec::new(),
output_types: Vec::new(),
addl_lib_search_paths: RefCell::new(HashSet::new()),
maybe_sysroot: None,
target_triple: host_triple().to_owned(),
cfg: Vec::new(),
test: false,
parse_only: false,
no_trans: false,
no_analysis: false,
debugging_opts: 0,
write_dependency_info: (false, None),
print_metas: (false, false, false),
cg: basic_codegen_options(),
pub fn build_session(sopts: config::Options,
local_crate_source_file: Option<Path>)
-> Session {
let codemap = codemap::CodeMap::new();
let diagnostic_handler =
diagnostic::default_handler();
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
build_session_(sopts, local_crate_source_file, span_diagnostic_handler)
}
pub fn build_session_(sopts: config::Options,
local_crate_source_file: Option<Path>,
span_diagnostic: diagnostic::SpanHandler)
-> Session {
let target_cfg = config::build_target_config(&sopts);
let p_s = parse::new_parse_sess_special_handler(span_diagnostic);
let default_sysroot = match sopts.maybe_sysroot {
Some(_) => None,
None => Some(filesearch::get_or_default_sysroot())
};
// Make the path absolute, if necessary
let local_crate_source_file = local_crate_source_file.map(|path|
if path.is_absolute() {
path.clone()
} else {
os::getcwd().join(path.clone())
}
);
Session {
targ_cfg: target_cfg,
opts: sopts,
cstore: CStore::new(token::get_ident_interner()),
parse_sess: p_s,
// For a library crate, this is always none
entry_fn: RefCell::new(None),
entry_type: Cell::new(None),
macro_registrar_fn: Cell::new(None),
default_sysroot: default_sysroot,
local_crate_source_file: local_crate_source_file,
working_dir: os::getcwd(),
lints: RefCell::new(NodeMap::new()),
node_id: Cell::new(1),
crate_types: RefCell::new(Vec::new()),
features: front::feature_gate::Features::new(),
recursion_limit: Cell::new(64),
}
}
/// Declare a macro that will define all CodegenOptions fields and parsers all
/// at once. The goal of this macro is to define an interface that can be
/// programmatically used by the option parser in order to initialize the struct
/// without hardcoding field names all over the place.
///
/// The goal is to invoke this macro once with the correct fields, and then this
/// macro generates all necessary code. The main gotcha of this macro is the
/// cgsetters module which is a bunch of generated code to parse an option into
/// its respective field in the struct. There are a few hand-written parsers for
/// parsing specific types of values in this module.
macro_rules! cgoptions(
($($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
(
#[deriving(Clone)]
pub struct CodegenOptions { $(pub $opt: $t),* }
pub fn basic_codegen_options() -> CodegenOptions {
CodegenOptions { $($opt: $init),* }
}
pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool;
pub static CG_OPTIONS: &'static [(&'static str, CodegenSetter,
&'static str)] =
&[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];
mod cgsetters {
use super::CodegenOptions;
$(
pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
$parse(&mut cg.$opt, v)
}
)*
fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
match v {
Some(..) => false,
None => { *slot = true; true }
}
}
fn parse_opt_string(slot: &mut Option<~str>, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = Some(s.to_owned()); true },
None => false,
}
}
fn parse_string(slot: &mut ~str, v: Option<&str>) -> bool {
match v {
Some(s) => { *slot = s.to_owned(); true },
None => false,
}
}
fn parse_list(slot: &mut Vec<~str>, v: Option<&str>)
-> bool {
match v {
Some(s) => {
for s in s.words() {
slot.push(s.to_owned());
}
true
},
None => false,
}
}
}
) )
cgoptions!(
ar: Option<~str> = (None, parse_opt_string,
"tool to assemble archives with"),
linker: Option<~str> = (None, parse_opt_string,
"system linker to link outputs with"),
link_args: Vec<~str> = (Vec::new(), parse_list,
"extra arguments to pass to the linker (space separated)"),
target_cpu: ~str = ("generic".to_owned(), parse_string,
"select target processor (llc -mcpu=help for details)"),
target_feature: ~str = ("".to_owned(), parse_string,
"target specific attributes (llc -mattr=help for details)"),
passes: Vec<~str> = (Vec::new(), parse_list,
"a list of extra LLVM passes to run (space separated)"),
llvm_args: Vec<~str> = (Vec::new(), parse_list,
"a list of arguments to pass to llvm (space separated)"),
save_temps: bool = (false, parse_bool,
"save all temporary output files during compilation"),
android_cross_path: Option<~str> = (None, parse_opt_string,
"the path to the Android NDK"),
no_rpath: bool = (false, parse_bool,
"disables setting the rpath in libs/exes"),
no_prepopulate_passes: bool = (false, parse_bool,
"don't pre-populate the pass manager with a list of passes"),
no_vectorize_loops: bool = (false, parse_bool,
"don't run the loop vectorization optimization passes"),
no_vectorize_slp: bool = (false, parse_bool,
"don't run LLVM's SLP vectorization pass"),
soft_float: bool = (false, parse_bool,
"generate software floating point library calls"),
prefer_dynamic: bool = (false, parse_bool,
"prefer dynamic linking to static linking"),
no_integrated_as: bool = (false, parse_bool,
"use an external assembler rather than LLVM's integrated one"),
relocation_model: ~str = ("pic".to_owned(), parse_string,
"choose the relocation model to use (llc -relocation-model for details)"),
)
// Seems out of place, but it uses session, so I'm putting it here
pub fn expect<T:Clone>(sess: &Session, opt: Option<T>, msg: || -> StrBuf)
@ -476,72 +252,3 @@ pub fn expect<T:Clone>(sess: &Session, opt: Option<T>, msg: || -> StrBuf)
diagnostic::expect(sess.diagnostic(), opt, msg)
}
pub fn default_lib_output() -> CrateType {
CrateTypeRlib
}
pub fn collect_crate_types(session: &Session,
attrs: &[ast::Attribute]) -> Vec<CrateType> {
// If we're generating a test executable, then ignore all other output
// styles at all other locations
if session.opts.test {
return vec!(CrateTypeExecutable)
}
// Only check command line flags if present. If no types are specified by
// command line, then reuse the empty `base` Vec to hold the types that
// will be found in crate attributes.
let mut base = session.opts.crate_types.clone();
if base.len() > 0 {
return base
} else {
let iter = attrs.iter().filter_map(|a| {
if a.name().equiv(&("crate_type")) {
match a.value_str() {
Some(ref n) if n.equiv(&("rlib")) => Some(CrateTypeRlib),
Some(ref n) if n.equiv(&("dylib")) => Some(CrateTypeDylib),
Some(ref n) if n.equiv(&("lib")) => {
Some(default_lib_output())
}
Some(ref n) if n.equiv(&("staticlib")) => {
Some(CrateTypeStaticlib)
}
Some(ref n) if n.equiv(&("bin")) => Some(CrateTypeExecutable),
Some(_) => {
session.add_lint(lint::UnknownCrateType,
ast::CRATE_NODE_ID,
a.span,
"invalid `crate_type` value".to_owned());
None
}
_ => {
session.add_lint(lint::UnknownCrateType, ast::CRATE_NODE_ID,
a.span, "`crate_type` requires a value".to_owned());
None
}
}
} else {
None
}
});
base.extend(iter);
if base.len() == 0 {
base.push(CrateTypeExecutable);
}
base.as_mut_slice().sort();
base.dedup();
return base;
}
}
pub fn sess_os_to_meta_os(os: abi::Os) -> metadata::loader::Os {
use metadata::loader;
match os {
abi::OsWin32 => loader::OsWin32,
abi::OsLinux => loader::OsLinux,
abi::OsAndroid => loader::OsAndroid,
abi::OsMacos => loader::OsMacos,
abi::OsFreebsd => loader::OsFreebsd
}
}

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use driver::session;
use driver::config;
use driver::session::Session;
use syntax::ast;
@ -87,7 +87,7 @@ impl<'a> fold::Folder for StandardLibraryInjector<'a> {
});
let any_exe = self.sess.crate_types.borrow().iter().any(|ty| {
*ty == session::CrateTypeExecutable
*ty == config::CrateTypeExecutable
});
if use_start(&krate) && any_exe {
vis.push(ast::ViewItem {

@ -44,23 +44,6 @@ extern crate libc;
#[phase(syntax, link)]
extern crate log;
use back::link;
use driver::session;
use middle::lint;
use d = driver::driver;
use std::any::AnyRefExt;
use std::cmp;
use std::io;
use std::os;
use std::str;
use std::task::TaskBuilder;
use syntax::ast;
use syntax::diagnostic::Emitter;
use syntax::diagnostic;
use syntax::parse;
pub mod middle {
pub mod trans;
pub mod ty;
@ -136,309 +119,8 @@ pub mod lib {
pub mod llvmdeps;
}
static BUG_REPORT_URL: &'static str =
"http://static.rust-lang.org/doc/master/complement-bugreport.html";
pub fn version(argv0: &str) {
let vers = match option_env!("CFG_VERSION") {
Some(vers) => vers,
None => "unknown version"
};
println!("{} {}", argv0, vers);
println!("host: {}", d::host_triple());
}
pub fn usage(argv0: &str) {
let message = format!("Usage: {} [OPTIONS] INPUT", argv0);
println!("{}\n\
Additional help:
-C help Print codegen options
-W help Print 'lint' options and default settings
-Z help Print internal options for debugging rustc\n",
getopts::usage(message, d::optgroups().as_slice()));
}
pub fn describe_warnings() {
println!("
Available lint options:
-W <foo> Warn about <foo>
-A <foo> Allow <foo>
-D <foo> Deny <foo>
-F <foo> Forbid <foo> (deny, and deny all overrides)
");
let lint_dict = lint::get_lint_dict();
let mut lint_dict = lint_dict.move_iter()
.map(|(k, v)| (v, k))
.collect::<Vec<(lint::LintSpec, &'static str)> >();
lint_dict.as_mut_slice().sort();
let mut max_key = 0;
for &(_, name) in lint_dict.iter() {
max_key = cmp::max(name.len(), max_key);
}
fn padded(max: uint, s: &str) -> ~str {
" ".repeat(max - s.len()) + s
}
println!("\nAvailable lint checks:\n");
println!(" {} {:7.7s} {}",
padded(max_key, "name"), "default", "meaning");
println!(" {} {:7.7s} {}\n",
padded(max_key, "----"), "-------", "-------");
for (spec, name) in lint_dict.move_iter() {
let name = name.replace("_", "-");
println!(" {} {:7.7s} {}",
padded(max_key, name),
lint::level_to_str(spec.default),
spec.desc);
}
println!("");
}
pub fn describe_debug_flags() {
println!("\nAvailable debug options:\n");
let r = session::debugging_opts_map();
for tuple in r.iter() {
match *tuple {
(ref name, ref desc, _) => {
println!(" -Z {:>20s} -- {}", *name, *desc);
}
}
}
}
pub fn describe_codegen_flags() {
println!("\nAvailable codegen options:\n");
let mut cg = session::basic_codegen_options();
for &(name, parser, desc) in session::CG_OPTIONS.iter() {
// we invoke the parser function on `None` to see if this option needs
// an argument or not.
let (width, extra) = if parser(&mut cg, None) {
(25, "")
} else {
(21, "=val")
};
println!(" -C {:>width$s}{} -- {}", name.replace("_", "-"),
extra, desc, width=width);
}
}
pub fn run_compiler(args: &[~str]) {
let mut args = Vec::from_slice(args);
let binary = args.shift().unwrap();
if args.is_empty() { usage(binary); return; }
let matches =
&match getopts::getopts(args.as_slice(), d::optgroups().as_slice()) {
Ok(m) => m,
Err(f) => {
d::early_error(f.to_err_msg());
}
};
if matches.opt_present("h") || matches.opt_present("help") {
usage(binary);
return;
}
let lint_flags = matches.opt_strs("W").move_iter().collect::<Vec<_>>().append(
matches.opt_strs("warn").as_slice());
if lint_flags.iter().any(|x| x == &"help".to_owned()) {
describe_warnings();
return;
}
let r = matches.opt_strs("Z");
if r.iter().any(|x| x == &"help".to_owned()) {
describe_debug_flags();
return;
}
let cg_flags = matches.opt_strs("C");
if cg_flags.iter().any(|x| x == &"help".to_owned()) {
describe_codegen_flags();
return;
}
if cg_flags.contains(&"passes=list".to_owned()) {
unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
return;
}
if matches.opt_present("v") || matches.opt_present("version") {
version(binary);
return;
}
let (input, input_file_path) = match matches.free.len() {
0u => d::early_error("no input filename given"),
1u => {
let ifile = matches.free.get(0).as_slice();
if ifile == "-" {
let contents = io::stdin().read_to_end().unwrap();
let src = str::from_utf8(contents.as_slice()).unwrap().to_owned();
(d::StrInput(src), None)
} else {
(d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
}
}
_ => d::early_error("multiple input filenames provided")
};
let sopts = d::build_session_options(matches);
let sess = d::build_session(sopts, input_file_path);
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
let ofile = matches.opt_str("o").map(|o| Path::new(o));
let cfg = d::build_configuration(&sess);
let pretty = matches.opt_default("pretty", "normal").map(|a| {
d::parse_pretty(&sess, a)
});
match pretty {
Some::<d::PpMode>(ppm) => {
d::pretty_print_input(sess, cfg, &input, ppm, ofile);
return;
}
None::<d::PpMode> => {/* continue */ }
}
if r.contains(&("ls".to_owned())) {
match input {
d::FileInput(ref ifile) => {
let mut stdout = io::stdout();
d::list_metadata(&sess, &(*ifile), &mut stdout).unwrap();
}
d::StrInput(_) => {
d::early_error("can not list metadata for stdin");
}
}
return;
}
let (crate_id, crate_name, crate_file_name) = sess.opts.print_metas;
// these nasty nested conditions are to avoid doing extra work
if crate_id || crate_name || crate_file_name {
let attrs = parse_crate_attrs(&sess, &input);
let t_outputs = d::build_output_filenames(&input, &odir, &ofile,
attrs.as_slice(), &sess);
let id = link::find_crate_id(attrs.as_slice(), t_outputs.out_filestem);
if crate_id {
println!("{}", id.to_str());
}
if crate_name {
println!("{}", id.name);
}
if crate_file_name {
let crate_types = session::collect_crate_types(&sess,
attrs.as_slice());
for &style in crate_types.iter() {
let fname = link::filename_for_input(&sess, style, &id,
&t_outputs.with_extension(""));
println!("{}", fname.filename_display());
}
}
return;
}
d::compile_input(sess, cfg, &input, &odir, &ofile);
}
fn parse_crate_attrs(sess: &session::Session, input: &d::Input) ->
Vec<ast::Attribute> {
let result = match *input {
d::FileInput(ref ifile) => {
parse::parse_crate_attrs_from_file(ifile,
Vec::new(),
&sess.parse_sess)
}
d::StrInput(ref src) => {
parse::parse_crate_attrs_from_source_str(
d::anon_src().to_strbuf(),
src.to_strbuf(),
Vec::new(),
&sess.parse_sess)
}
};
result.move_iter().collect()
}
/// Run a procedure which will detect failures in the compiler and print nicer
/// error messages rather than just failing the test.
///
/// The diagnostic emitter yielded to the procedure should be used for reporting
/// errors of the compiler.
pub fn monitor(f: proc():Send) {
// FIXME: This is a hack for newsched since it doesn't support split stacks.
// rustc needs a lot of stack! When optimizations are disabled, it needs
// even *more* stack than usual as well.
#[cfg(rtopt)]
static STACK_SIZE: uint = 6000000; // 6MB
#[cfg(not(rtopt))]
static STACK_SIZE: uint = 20000000; // 20MB
let mut task_builder = TaskBuilder::new().named("rustc");
// FIXME: Hacks on hacks. If the env is trying to override the stack size
// then *don't* set it explicitly.
if os::getenv("RUST_MIN_STACK").is_none() {
task_builder.opts.stack_size = Some(STACK_SIZE);
}
let (tx, rx) = channel();
let w = io::ChanWriter::new(tx);
let mut r = io::ChanReader::new(rx);
match task_builder.try(proc() {
io::stdio::set_stderr(box w);
f()
}) {
Ok(()) => { /* fallthrough */ }
Err(value) => {
// Task failed without emitting a fatal diagnostic
if !value.is::<diagnostic::FatalError>() {
let mut emitter = diagnostic::EmitterWriter::stderr();
// a .span_bug or .bug call has already printed what
// it wants to print.
if !value.is::<diagnostic::ExplicitBug>() {
emitter.emit(
None,
"unexpected failure",
diagnostic::Bug);
}
let xs = [
"the compiler hit an unexpected failure path. this is a bug.".to_owned(),
"we would appreciate a bug report: " + BUG_REPORT_URL,
"run with `RUST_BACKTRACE=1` for a backtrace".to_owned(),
];
for note in xs.iter() {
emitter.emit(None, *note, diagnostic::Note)
}
match r.read_to_str() {
Ok(s) => println!("{}", s),
Err(e) => emitter.emit(None,
format!("failed to read internal stderr: {}", e),
diagnostic::Error),
}
}
// Fail so the process returns a failure code, but don't pollute the
// output with some unnecessary failure messages, we've already
// printed everything that we needed to.
io::stdio::set_stderr(box io::util::NullWriter);
fail!();
}
}
}
pub fn main() {
std::os::set_exit_status(main_args(std::os::args().as_slice()));
std::os::set_exit_status(driver::main_args(std::os::args().as_slice()));
}
pub fn main_args(args: &[~str]) -> int {
let owned_args = args.to_owned();
monitor(proc() run_compiler(owned_args));
0
}

@ -15,7 +15,7 @@
use back::link;
use back::svh::Svh;
use driver::session::Session;
use driver::{driver, session};
use driver::{driver, config};
use metadata::cstore;
use metadata::cstore::CStore;
use metadata::decoder;
@ -331,7 +331,7 @@ fn resolve_crate<'a>(e: &mut Env,
id_hash: id_hash,
hash: hash.map(|a| &*a),
filesearch: e.sess.target_filesearch(),
os: session::sess_os_to_meta_os(e.sess.targ_cfg.os),
os: config::cfg_os_to_meta_os(e.sess.targ_cfg.os),
triple: e.sess.targ_cfg.target_strs.target_triple.as_slice(),
root: root,
rejected_via_hash: vec!(),
@ -387,7 +387,7 @@ impl<'a> CrateLoader for Loader<'a> {
let is_cross = target_triple != driver::host_triple();
let mut should_link = info.should_link && !is_cross;
let id_hash = link::crate_id_hash(&info.crate_id);
let os = driver::get_os(driver::host_triple()).unwrap();
let os = config::get_os(driver::host_triple()).unwrap();
let mut load_ctxt = loader::Context {
sess: self.env.sess,
span: krate.span,
@ -397,7 +397,7 @@ impl<'a> CrateLoader for Loader<'a> {
hash: None,
filesearch: self.env.sess.host_filesearch(),
triple: driver::host_triple(),
os: session::sess_os_to_meta_os(os),
os: config::cfg_os_to_meta_os(os),
root: &None,
rejected_via_hash: vec!(),
rejected_via_triple: vec!(),
@ -408,7 +408,7 @@ impl<'a> CrateLoader for Loader<'a> {
// try loading from target crates (only valid if there are
// no syntax extensions)
load_ctxt.triple = target_triple;
load_ctxt.os = session::sess_os_to_meta_os(self.env.sess.targ_cfg.os);
load_ctxt.os = config::cfg_os_to_meta_os(self.env.sess.targ_cfg.os);
load_ctxt.filesearch = self.env.sess.target_filesearch();
let lib = load_ctxt.load_library_crate();
if decoder::get_macro_registrar_fn(lib.metadata.as_slice()).is_some() {

@ -14,7 +14,7 @@
#![allow(non_camel_case_types)]
use back::svh::Svh;
use driver::session;
use driver::config;
use metadata::common::*;
use metadata::cstore;
use metadata::decoder;
@ -1697,7 +1697,7 @@ fn encode_crate_triple(ebml_w: &mut Encoder, triple: &str) {
fn encode_dylib_dependency_formats(ebml_w: &mut Encoder, ecx: &EncodeContext) {
ebml_w.start_tag(tag_dylib_dependency_formats);
match ecx.tcx.dependency_formats.borrow().find(&session::CrateTypeDylib) {
match ecx.tcx.dependency_formats.borrow().find(&config::CrateTypeDylib) {
Some(arr) => {
let s = arr.iter().enumerate().filter_map(|(i, slot)| {
slot.map(|kind| format!("{}:{}", i + 1, match kind {

@ -65,6 +65,7 @@ use collections::HashMap;
use syntax::ast;
use driver::session;
use driver::config;
use metadata::cstore;
use metadata::csearch;
use middle::ty;
@ -80,7 +81,7 @@ pub type DependencyList = Vec<Option<cstore::LinkagePreference>>;
/// A mapping of all required dependencies for a particular flavor of output.
///
/// This is local to the tcx, and is generally relevant to one session.
pub type Dependencies = HashMap<session::CrateType, DependencyList>;
pub type Dependencies = HashMap<config::CrateType, DependencyList>;
pub fn calculate(tcx: &ty::ctxt) {
let mut fmts = tcx.dependency_formats.borrow_mut();
@ -91,11 +92,11 @@ pub fn calculate(tcx: &ty::ctxt) {
}
fn calculate_type(sess: &session::Session,
ty: session::CrateType) -> DependencyList {
ty: config::CrateType) -> DependencyList {
match ty {
// If the global prefer_dynamic switch is turned off, first attempt
// static linkage (this can fail).
session::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic => {
config::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic => {
match attempt_static(sess) {
Some(v) => return v,
None => {}
@ -104,11 +105,11 @@ fn calculate_type(sess: &session::Session,
// No linkage happens with rlibs, we just needed the metadata (which we
// got long ago), so don't bother with anything.
session::CrateTypeRlib => return Vec::new(),
config::CrateTypeRlib => return Vec::new(),
// Staticlibs must have all static dependencies. If any fail to be
// found, we generate some nice pretty errors.
session::CrateTypeStaticlib => {
config::CrateTypeStaticlib => {
match attempt_static(sess) {
Some(v) => return v,
None => {}
@ -123,7 +124,7 @@ fn calculate_type(sess: &session::Session,
}
// Everything else falls through below
session::CrateTypeExecutable | session::CrateTypeDylib => {},
config::CrateTypeExecutable | config::CrateTypeDylib => {},
}
let mut formats = HashMap::new();

@ -9,7 +9,7 @@
// except according to those terms.
use driver::session;
use driver::config;
use driver::session::Session;
use syntax::ast::{Crate, Name, NodeId, Item, ItemFn};
use syntax::ast_map;
@ -49,7 +49,7 @@ impl<'a> Visitor<()> for EntryContext<'a> {
pub fn find_entry_point(session: &Session, krate: &Crate, ast_map: &ast_map::Map) {
let any_exe = session.crate_types.borrow().iter().any(|ty| {
*ty == session::CrateTypeExecutable
*ty == config::CrateTypeExecutable
});
if !any_exe {
// No need to find a main function
@ -58,7 +58,7 @@ pub fn find_entry_point(session: &Session, krate: &Crate, ast_map: &ast_map::Map
// If the user wants no main function at all, then stop here.
if attr::contains_name(krate.attrs.as_slice(), "no_main") {
session.entry_type.set(Some(session::EntryNone));
session.entry_type.set(Some(config::EntryNone));
return
}
@ -127,13 +127,13 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
fn configure_main(this: &mut EntryContext) {
if this.start_fn.is_some() {
*this.session.entry_fn.borrow_mut() = this.start_fn;
this.session.entry_type.set(Some(session::EntryStart));
this.session.entry_type.set(Some(config::EntryStart));
} else if this.attr_main_fn.is_some() {
*this.session.entry_fn.borrow_mut() = this.attr_main_fn;
this.session.entry_type.set(Some(session::EntryMain));
this.session.entry_type.set(Some(config::EntryMain));
} else if this.main_fn.is_some() {
*this.session.entry_fn.borrow_mut() = this.main_fn;
this.session.entry_type.set(Some(session::EntryMain));
this.session.entry_type.set(Some(config::EntryMain));
} else {
// No main function
this.session.err("main function not found");

@ -15,7 +15,7 @@
// makes all other generics or inline functions that it references
// reachable as well.
use driver::session;
use driver::config;
use middle::ty;
use middle::typeck;
use middle::privacy;
@ -162,7 +162,7 @@ impl<'a> ReachableContext<'a> {
// Creates a new reachability computation context.
fn new(tcx: &'a ty::ctxt) -> ReachableContext<'a> {
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
*ty != session::CrateTypeExecutable
*ty != config::CrateTypeExecutable
});
ReachableContext {
tcx: tcx,

@ -195,7 +195,7 @@
#![allow(non_camel_case_types)]
use back::abi;
use driver::session::FullDebugInfo;
use driver::config::FullDebugInfo;
use lib::llvm::{llvm, ValueRef, BasicBlockRef};
use middle::const_eval;
use middle::lang_items::{UniqStrEqFnLangItem, StrEqFnLangItem};

@ -27,8 +27,9 @@
use back::link::{mangle_exported_name};
use back::{link, abi};
use driver::session;
use driver::session::{Session, NoDebugInfo, FullDebugInfo};
use driver::config;
use driver::config::{NoDebugInfo, FullDebugInfo};
use driver::session::Session;
use driver::driver::OutputFilenames;
use driver::driver::{CrateAnalysis, CrateTranslation};
use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef};
@ -1725,11 +1726,11 @@ pub fn create_entry_wrapper(ccx: &CrateContext,
main_llfn: ValueRef) {
let et = ccx.sess().entry_type.get().unwrap();
match et {
session::EntryMain => {
config::EntryMain => {
create_entry_fn(ccx, main_llfn, true);
}
session::EntryStart => create_entry_fn(ccx, main_llfn, false),
session::EntryNone => {} // Do nothing.
config::EntryStart => create_entry_fn(ccx, main_llfn, false),
config::EntryNone => {} // Do nothing.
}
fn create_entry_fn(ccx: &CrateContext,
@ -2068,7 +2069,7 @@ pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
use flate;
let any_library = cx.sess().crate_types.borrow().iter().any(|ty| {
*ty != session::CrateTypeExecutable
*ty != config::CrateTypeExecutable
});
if !any_library {
return Vec::new()

@ -11,7 +11,7 @@
use back::abi;
use back::link::mangle_internal_name_by_path_and_seq;
use driver::session::FullDebugInfo;
use driver::config::FullDebugInfo;
use lib::llvm::ValueRef;
use middle::freevars;
use middle::lang_items::ClosureExchangeMallocFnLangItem;

@ -9,7 +9,7 @@
// except according to those terms.
use driver::session::NoDebugInfo;
use driver::config::NoDebugInfo;
use driver::session::Session;
use lib::llvm::{ContextRef, ModuleRef, ValueRef};
use lib::llvm::{llvm, TargetData, TypeNames};

@ -9,7 +9,7 @@
// except according to those terms.
use lib::llvm::*;
use driver::session::FullDebugInfo;
use driver::config::FullDebugInfo;
use middle::lang_items::{FailFnLangItem, FailBoundsCheckFnLangItem};
use middle::trans::base::*;
use middle::trans::build::*;

@ -125,8 +125,8 @@ is still disabled, so there is no need to do anything special with source locati
*/
use driver::session;
use driver::session::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use driver::config;
use driver::config::{FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use lib::llvm::llvm;
use lib::llvm::{ModuleRef, ContextRef, ValueRef};
use lib::llvm::debuginfo::*;
@ -748,7 +748,7 @@ pub fn create_function_debug_context(cx: &CrateContext,
true,
scope_line as c_uint,
FlagPrototyped as c_uint,
cx.sess().opts.optimize != session::No,
cx.sess().opts.optimize != config::No,
llfn,
template_parameters,
ptr::null())
@ -981,7 +981,7 @@ fn compile_unit_metadata(cx: &CrateContext) {
compile_unit_name,
work_dir,
producer,
cx.sess().opts.optimize != session::No,
cx.sess().opts.optimize != config::No,
flags,
0,
split_name);
@ -1032,7 +1032,7 @@ fn declare_local(bcx: &Block,
file_metadata,
loc.line as c_uint,
type_metadata,
cx.sess().opts.optimize != session::No,
cx.sess().opts.optimize != config::No,
0,
argument_index)
}

@ -61,7 +61,7 @@ independently:
#![allow(non_camel_case_types)]
use driver::session;
use driver::config;
use middle::resolve;
use middle::ty;
@ -414,9 +414,9 @@ fn check_for_entry_fn(ccx: &CrateCtxt) {
let tcx = ccx.tcx;
match *tcx.sess.entry_fn.borrow() {
Some((id, sp)) => match tcx.sess.entry_type.get() {
Some(session::EntryMain) => check_main_fn_ty(ccx, id, sp),
Some(session::EntryStart) => check_start_fn_ty(ccx, id, sp),
Some(session::EntryNone) => {}
Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
Some(config::EntryNone) => {}
None => tcx.sess.bug("entry function without a type")
},
None => {}

@ -60,19 +60,20 @@ pub struct CrateAnalysis {
fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<~str>)
-> (DocContext, CrateAnalysis) {
use syntax::codemap::dummy_spanned;
use rustc::driver::driver::{FileInput, build_configuration,
use rustc::driver::driver::{FileInput,
phase_1_parse_input,
phase_2_configure_and_expand,
phase_3_run_analysis_passes};
use rustc::driver::config::build_configuration;
let input = FileInput(cpath.clone());
let sessopts = driver::session::Options {
let sessopts = driver::config::Options {
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: RefCell::new(libs),
crate_types: vec!(driver::session::CrateTypeDylib),
crate_types: vec!(driver::config::CrateTypeDylib),
lint_opts: vec!((lint::Warnings, lint::allow)),
..rustc::driver::session::basic_options().clone()
..rustc::driver::config::basic_options().clone()
};
@ -81,9 +82,9 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<~str>)
let span_diagnostic_handler =
syntax::diagnostic::mk_span_handler(diagnostic_handler, codemap);
let sess = driver::driver::build_session_(sessopts,
Some(cpath.clone()),
span_diagnostic_handler);
let sess = driver::session::build_session_(sessopts,
Some(cpath.clone()),
span_diagnostic_handler);
let mut cfg = build_configuration(&sess);
for cfg_ in cfgs.move_iter() {

@ -145,7 +145,7 @@ pub fn main_args(args: &[~str]) -> int {
usage(args[0]);
return 0;
} else if matches.opt_present("version") {
rustc::version(args[0]);
rustc::driver::version(args[0]);
return 0;
}

@ -19,6 +19,7 @@ use std::strbuf::StrBuf;
use collections::{HashSet, HashMap};
use testing;
use rustc::back::link;
use rustc::driver::config;
use rustc::driver::driver;
use rustc::driver::session;
use rustc::metadata::creader::Loader;
@ -43,11 +44,11 @@ pub fn run(input: &str,
let input_path = Path::new(input);
let input = driver::FileInput(input_path.clone());
let sessopts = session::Options {
let sessopts = config::Options {
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: RefCell::new(libs.clone()),
crate_types: vec!(session::CrateTypeDylib),
..session::basic_options().clone()
crate_types: vec!(config::CrateTypeDylib),
..config::basic_options().clone()
};
@ -56,11 +57,11 @@ pub fn run(input: &str,
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
let sess = driver::build_session_(sessopts,
let sess = session::build_session_(sessopts,
Some(input_path.clone()),
span_diagnostic_handler);
let mut cfg = driver::build_configuration(&sess);
let mut cfg = config::build_configuration(&sess);
cfg.extend(cfgs.move_iter().map(|cfg_| {
let cfg_ = token::intern_and_get_ident(cfg_);
@dummy_spanned(ast::MetaWord(cfg_))
@ -101,17 +102,17 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
let test = maketest(test, cratename, loose_feature_gating);
let input = driver::StrInput(test);
let sessopts = session::Options {
let sessopts = config::Options {
maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
addl_lib_search_paths: RefCell::new(libs),
crate_types: vec!(session::CrateTypeExecutable),
crate_types: vec!(config::CrateTypeExecutable),
output_types: vec!(link::OutputTypeExe),
no_trans: no_run,
cg: session::CodegenOptions {
cg: config::CodegenOptions {
prefer_dynamic: true,
.. session::basic_codegen_options()
.. config::basic_codegen_options()
},
..session::basic_options().clone()
..config::basic_options().clone()
};
// Shuffle around a few input and output handles here. We're going to pass
@ -142,13 +143,13 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
let span_diagnostic_handler =
diagnostic::mk_span_handler(diagnostic_handler, codemap);
let sess = driver::build_session_(sessopts,
let sess = session::build_session_(sessopts,
None,
span_diagnostic_handler);
let outdir = TempDir::new("rustdoctest").expect("rustdoc needs a tempdir");
let out = Some(outdir.path().clone());
let cfg = driver::build_configuration(&sess);
let cfg = config::build_configuration(&sess);
driver::compile_input(sess, cfg, &input, &out, &None);
if no_run { return }