Reorganise driver code.

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... fns easier to use by tools.

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:
Nick Cameron 2014-05-06 23:38:01 +12:00
parent 11571cd9c1
commit 37ca36783c
27 changed files with 1447 additions and 1377 deletions

View File

@ -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 => {

View File

@ -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 {

View File

@ -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");

View File

@ -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 => {

View File

@ -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 => {

View File

@ -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 => {

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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!();
}
}
}

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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() {

View File

@ -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 {

View File

@ -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();

View File

@ -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");

View File

@ -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,

View File

@ -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};

View File

@ -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};
@ -1724,11 +1725,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,
@ -2067,7 +2068,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()

View File

@ -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;

View File

@ -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};

View File

@ -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::*;

View File

@ -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)
}

View File

@ -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 => {}

View File

@ -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() {

View File

@ -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;
}

View File

@ -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 }