mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-16 01:33:30 +00:00
Auto merge of #21876 - nick29581:driver-args, r=huonw
This allows people to write tools which are drop-in replacements for rustc by implementing `CompilerCalls` and three lines of code, rather than having to copy+paste a bunch of args parsing code. r? @alexcrichton
This commit is contained in:
commit
134e00be77
@ -33,9 +33,10 @@ use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler};
|
|||||||
use syntax::parse;
|
use syntax::parse;
|
||||||
use syntax::parse::token::InternedString;
|
use syntax::parse::token::InternedString;
|
||||||
|
|
||||||
|
use getopts;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use getopts;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use llvm;
|
use llvm;
|
||||||
@ -821,7 +822,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
|
|
||||||
let unparsed_crate_types = matches.opt_strs("crate-type");
|
let unparsed_crate_types = matches.opt_strs("crate-type");
|
||||||
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
||||||
.unwrap_or_else(|e| early_error(&e[]));
|
.unwrap_or_else(|e| early_error(&e[]));
|
||||||
@ -1041,7 +1041,22 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
|||||||
crate_name: crate_name,
|
crate_name: crate_name,
|
||||||
alt_std_name: None,
|
alt_std_name: None,
|
||||||
libs: libs,
|
libs: libs,
|
||||||
unstable_features: UnstableFeatures::Disallow
|
unstable_features: get_unstable_features_setting(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_unstable_features_setting() -> UnstableFeatures {
|
||||||
|
// Whether this is a feature-staged build, i.e. on the beta or stable channel
|
||||||
|
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
|
||||||
|
// The secret key needed to get through the rustc build itself by
|
||||||
|
// subverting the unstable features lints
|
||||||
|
let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
|
||||||
|
// The matching key to the above, only known by the build system
|
||||||
|
let bootstrap_provided_key = env::var_string("RUSTC_BOOTSTRAP_KEY").ok();
|
||||||
|
match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
|
||||||
|
(_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
|
||||||
|
(true, _, _) => UnstableFeatures::Disallow,
|
||||||
|
(false, _, _) => UnstableFeatures::Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@ -27,6 +27,7 @@ use rustc_trans::back::write;
|
|||||||
use rustc_trans::trans;
|
use rustc_trans::trans;
|
||||||
use rustc_typeck as typeck;
|
use rustc_typeck as typeck;
|
||||||
use rustc_privacy;
|
use rustc_privacy;
|
||||||
|
use super::Compilation;
|
||||||
|
|
||||||
use serialize::json;
|
use serialize::json;
|
||||||
|
|
||||||
@ -55,7 +56,7 @@ pub fn compile_input(sess: Session,
|
|||||||
let state = $make_state;
|
let state = $make_state;
|
||||||
(control.$point.callback)(state);
|
(control.$point.callback)(state);
|
||||||
}
|
}
|
||||||
if control.$point.stop {
|
if control.$point.stop == Compilation::Stop {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
@ -206,14 +207,14 @@ impl<'a> CompileController<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct PhaseController<'a> {
|
pub struct PhaseController<'a> {
|
||||||
pub stop: bool,
|
pub stop: Compilation,
|
||||||
pub callback: Box<Fn(CompileState) -> () + 'a>,
|
pub callback: Box<Fn(CompileState) -> () + 'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PhaseController<'a> {
|
impl<'a> PhaseController<'a> {
|
||||||
pub fn basic() -> PhaseController<'a> {
|
pub fn basic() -> PhaseController<'a> {
|
||||||
PhaseController {
|
PhaseController {
|
||||||
stop: false,
|
stop: Compilation::Continue,
|
||||||
callback: box |_| {},
|
callback: box |_| {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
//
|
//
|
||||||
@ -60,12 +60,13 @@ extern crate "rustc_llvm" as llvm;
|
|||||||
pub use syntax::diagnostic;
|
pub use syntax::diagnostic;
|
||||||
|
|
||||||
use driver::CompileController;
|
use driver::CompileController;
|
||||||
|
use pretty::{PpMode, UserIdentifiedItem};
|
||||||
|
|
||||||
use rustc_resolve as resolve;
|
use rustc_resolve as resolve;
|
||||||
use rustc_trans::back::link;
|
use rustc_trans::back::link;
|
||||||
use rustc_trans::save;
|
use rustc_trans::save;
|
||||||
use rustc::session::{config, Session, build_session};
|
use rustc::session::{config, Session, build_session};
|
||||||
use rustc::session::config::{Input, PrintRequest, UnstableFeatures};
|
use rustc::session::config::{Input, PrintRequest};
|
||||||
use rustc::lint::Lint;
|
use rustc::lint::Lint;
|
||||||
use rustc::lint;
|
use rustc::lint;
|
||||||
use rustc::metadata;
|
use rustc::metadata;
|
||||||
@ -92,95 +93,59 @@ pub mod test;
|
|||||||
pub mod driver;
|
pub mod driver;
|
||||||
pub mod pretty;
|
pub mod pretty;
|
||||||
|
|
||||||
pub fn run(args: Vec<String>) -> int {
|
|
||||||
monitor(move || run_compiler(&args));
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
static BUG_REPORT_URL: &'static str =
|
static BUG_REPORT_URL: &'static str =
|
||||||
"http://doc.rust-lang.org/complement-bugreport.html";
|
"http://doc.rust-lang.org/complement-bugreport.html";
|
||||||
|
|
||||||
fn run_compiler(args: &[String]) {
|
|
||||||
|
pub fn run(args: Vec<String>) -> int {
|
||||||
|
monitor(move || run_compiler(&args, &mut RustcDefaultCalls));
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse args and run the compiler. This is the primary entry point for rustc.
|
||||||
|
// See comments on CompilerCalls below for details about the callbacks argument.
|
||||||
|
pub fn run_compiler<'a>(args: &[String],
|
||||||
|
callbacks: &mut CompilerCalls<'a>) {
|
||||||
|
macro_rules! do_or_return {($expr: expr) => {
|
||||||
|
match $expr {
|
||||||
|
Compilation::Stop => return,
|
||||||
|
Compilation::Continue => {}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
let matches = match handle_options(args.to_vec()) {
|
let matches = match handle_options(args.to_vec()) {
|
||||||
Some(matches) => matches,
|
Some(matches) => matches,
|
||||||
None => return
|
None => return
|
||||||
};
|
};
|
||||||
|
|
||||||
let descriptions = diagnostics_registry();
|
let descriptions = diagnostics_registry();
|
||||||
match matches.opt_str("explain") {
|
|
||||||
Some(ref code) => {
|
do_or_return!(callbacks.early_callback(&matches, &descriptions));
|
||||||
match descriptions.find_description(&code[]) {
|
|
||||||
Some(ref description) => {
|
|
||||||
println!("{}", description);
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
early_error(&format!("no extended information for {}", code)[]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
None => ()
|
|
||||||
}
|
|
||||||
|
|
||||||
let sopts = config::build_session_options(&matches);
|
let sopts = config::build_session_options(&matches);
|
||||||
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
|
||||||
let ofile = matches.opt_str("o").map(|o| Path::new(o));
|
|
||||||
let (input, input_file_path) = match matches.free.len() {
|
|
||||||
0 => {
|
|
||||||
if sopts.describe_lints {
|
|
||||||
let mut ls = lint::LintStore::new();
|
|
||||||
ls.register_builtin(None);
|
|
||||||
describe_lints(&ls, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let sess = build_session(sopts, None, descriptions);
|
|
||||||
if print_crate_info(&sess, None, &odir, &ofile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
early_error("no input filename given");
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
let ifile = &matches.free[0][];
|
|
||||||
if ifile == "-" {
|
|
||||||
let contents = old_io::stdin().read_to_end().unwrap();
|
|
||||||
let src = String::from_utf8(contents).unwrap();
|
|
||||||
(Input::Str(src), None)
|
|
||||||
} else {
|
|
||||||
(Input::File(Path::new(ifile)), Some(Path::new(ifile)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => early_error("multiple input filenames provided")
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut sopts = sopts;
|
let (odir, ofile) = make_output(&matches);
|
||||||
sopts.unstable_features = get_unstable_features_setting();
|
let (input, input_file_path) = match make_input(&matches.free[]) {
|
||||||
|
Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
|
||||||
|
None => match callbacks.no_input(&matches, &sopts, &odir, &ofile, &descriptions) {
|
||||||
|
Some((input, input_file_path)) => (input, input_file_path),
|
||||||
|
None => return
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut sess = build_session(sopts, input_file_path, descriptions);
|
let mut sess = build_session(sopts, input_file_path, descriptions);
|
||||||
|
if sess.unstable_options() {
|
||||||
let cfg = config::build_configuration(&sess);
|
sess.opts.show_span = matches.opt_str("show-span");
|
||||||
if print_crate_info(&sess, Some(&input), &odir, &ofile) {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
let cfg = config::build_configuration(&sess);
|
||||||
|
|
||||||
let pretty = if sess.opts.debugging_opts.unstable_options {
|
do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile));
|
||||||
matches.opt_default("pretty", "normal").map(|a| {
|
|
||||||
// stable pretty-print variants only
|
|
||||||
pretty::parse_pretty(&sess, &a, false)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let pretty = if pretty.is_none() &&
|
|
||||||
sess.unstable_options() {
|
|
||||||
matches.opt_str("xpretty").map(|a| {
|
|
||||||
// extended with unstable pretty-print variants
|
|
||||||
pretty::parse_pretty(&sess, &a, true)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
pretty
|
|
||||||
};
|
|
||||||
|
|
||||||
match pretty.into_iter().next() {
|
// It is somewhat unfortunate that this is hardwired in - this is forced by
|
||||||
|
// the fact that pretty_print_input requires the session by value.
|
||||||
|
let pretty = callbacks.parse_pretty(&sess, &matches);
|
||||||
|
match pretty {
|
||||||
Some((ppm, opt_uii)) => {
|
Some((ppm, opt_uii)) => {
|
||||||
pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
|
pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
|
||||||
return;
|
return;
|
||||||
@ -188,76 +153,313 @@ fn run_compiler(args: &[String]) {
|
|||||||
None => {/* continue */ }
|
None => {/* continue */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
if sess.unstable_options() {
|
|
||||||
sess.opts.show_span = matches.opt_str("show-span");
|
|
||||||
}
|
|
||||||
|
|
||||||
let r = matches.opt_strs("Z");
|
|
||||||
if r.contains(&("ls".to_string())) {
|
|
||||||
match input {
|
|
||||||
Input::File(ref ifile) => {
|
|
||||||
let mut stdout = old_io::stdout();
|
|
||||||
list_metadata(&sess, &(*ifile), &mut stdout).unwrap();
|
|
||||||
}
|
|
||||||
Input::Str(_) => {
|
|
||||||
early_error("cannot list metadata for stdin");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
|
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
|
||||||
let control = build_controller(&sess);
|
let control = callbacks.build_controller(&sess);
|
||||||
driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control);
|
driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_controller<'a>(sess: &Session) -> CompileController<'a> {
|
// Extract output directory and file from matches.
|
||||||
let mut control = CompileController::basic();
|
fn make_output(matches: &getopts::Matches) -> (Option<Path>, Option<Path>) {
|
||||||
|
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
||||||
if sess.opts.parse_only ||
|
let ofile = matches.opt_str("o").map(|o| Path::new(o));
|
||||||
sess.opts.show_span.is_some() ||
|
(odir, ofile)
|
||||||
sess.opts.debugging_opts.ast_json_noexpand {
|
|
||||||
control.after_parse.stop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json {
|
|
||||||
control.after_write_deps.stop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if sess.opts.no_trans {
|
|
||||||
control.after_analysis.stop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) {
|
|
||||||
control.after_llvm.stop = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if sess.opts.debugging_opts.save_analysis {
|
|
||||||
control.after_analysis.callback = box |state| {
|
|
||||||
time(state.session.time_passes(), "save analysis", state.krate.unwrap(), |krate|
|
|
||||||
save::process_crate(state.session,
|
|
||||||
krate,
|
|
||||||
state.analysis.unwrap(),
|
|
||||||
state.out_dir));
|
|
||||||
};
|
|
||||||
control.make_glob_map = resolve::MakeGlobMap::Yes;
|
|
||||||
}
|
|
||||||
|
|
||||||
control
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_unstable_features_setting() -> UnstableFeatures {
|
// Extract input (string or file and optional path) from matches.
|
||||||
// Whether this is a feature-staged build, i.e. on the beta or stable channel
|
fn make_input(free_matches: &[String]) -> Option<(Input, Option<Path>)> {
|
||||||
let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
|
if free_matches.len() == 1 {
|
||||||
// The secret key needed to get through the rustc build itself by
|
let ifile = &free_matches[0][];
|
||||||
// subverting the unstable features lints
|
if ifile == "-" {
|
||||||
let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
|
let contents = old_io::stdin().read_to_end().unwrap();
|
||||||
// The matching key to the above, only known by the build system
|
let src = String::from_utf8(contents).unwrap();
|
||||||
let bootstrap_provided_key = env::var_string("RUSTC_BOOTSTRAP_KEY").ok();
|
Some((Input::Str(src), None))
|
||||||
match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
|
} else {
|
||||||
(_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
|
Some((Input::File(Path::new(ifile)), Some(Path::new(ifile))))
|
||||||
(true, _, _) => UnstableFeatures::Disallow,
|
}
|
||||||
(false, _, _) => UnstableFeatures::Default
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether to stop or continue compilation.
|
||||||
|
#[derive(Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub enum Compilation {
|
||||||
|
Stop,
|
||||||
|
Continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compilation {
|
||||||
|
pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
|
||||||
|
match self {
|
||||||
|
Compilation::Stop => Compilation::Stop,
|
||||||
|
Compilation::Continue => next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A trait for customising the compilation process. Offers a number of hooks for
|
||||||
|
// executing custom code or customising input.
|
||||||
|
pub trait CompilerCalls<'a> {
|
||||||
|
// Hook for a callback early in the process of handling arguments. This will
|
||||||
|
// be called straight after options have been parsed but before anything
|
||||||
|
// else (e.g., selecting input and output).
|
||||||
|
fn early_callback(&mut self,
|
||||||
|
&getopts::Matches,
|
||||||
|
&diagnostics::registry::Registry)
|
||||||
|
-> Compilation;
|
||||||
|
|
||||||
|
// Hook for a callback late in the process of handling arguments. This will
|
||||||
|
// be called just before actual compilation starts (and before build_controller
|
||||||
|
// is called), after all arguments etc. have been completely handled.
|
||||||
|
fn late_callback(&mut self,
|
||||||
|
&getopts::Matches,
|
||||||
|
&Session,
|
||||||
|
&Input,
|
||||||
|
&Option<Path>,
|
||||||
|
&Option<Path>)
|
||||||
|
-> Compilation;
|
||||||
|
|
||||||
|
// Called after we extract the input from the arguments. Gives the implementer
|
||||||
|
// an opportunity to change the inputs or to add some custom input handling.
|
||||||
|
// The default behaviour is to simply pass through the inputs.
|
||||||
|
fn some_input(&mut self, input: Input, input_path: Option<Path>) -> (Input, Option<Path>) {
|
||||||
|
(input, input_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called after we extract the input from the arguments if there is no valid
|
||||||
|
// input. Gives the implementer an opportunity to supply alternate input (by
|
||||||
|
// returning a Some value) or to add custom behaviour for this error such as
|
||||||
|
// emitting error messages. Returning None will cause compilation to stop
|
||||||
|
// at this point.
|
||||||
|
fn no_input(&mut self,
|
||||||
|
&getopts::Matches,
|
||||||
|
&config::Options,
|
||||||
|
&Option<Path>,
|
||||||
|
&Option<Path>,
|
||||||
|
&diagnostics::registry::Registry)
|
||||||
|
-> Option<(Input, Option<Path>)>;
|
||||||
|
|
||||||
|
// Parse pretty printing information from the arguments. The implementer can
|
||||||
|
// choose to ignore this (the default will return None) which will skip pretty
|
||||||
|
// printing. If you do want to pretty print, it is recommended to use the
|
||||||
|
// implementation of this method from RustcDefaultCalls.
|
||||||
|
// FIXME, this is a terrible bit of API. Parsing of pretty printing stuff
|
||||||
|
// should be done as part of the framework and the implementor should customise
|
||||||
|
// handling of it. However, that is not possible atm because pretty printing
|
||||||
|
// essentially goes off and takes another path through the compiler which
|
||||||
|
// means the session is either moved or not depending on what parse_pretty
|
||||||
|
// returns (we could fix this by cloning, but it's another hack). The proper
|
||||||
|
// solution is to handle pretty printing as if it were a compiler extension,
|
||||||
|
// extending CompileController to make this work (see for example the treatment
|
||||||
|
// of save-analysis in RustcDefaultCalls::build_controller).
|
||||||
|
fn parse_pretty(&mut self,
|
||||||
|
_sess: &Session,
|
||||||
|
_matches: &getopts::Matches)
|
||||||
|
-> Option<(PpMode, Option<UserIdentifiedItem>)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a CompilController struct for controlling the behaviour of compilation.
|
||||||
|
fn build_controller(&mut self, &Session) -> CompileController<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompilerCalls instance for a regular rustc build.
|
||||||
|
#[derive(Copy)]
|
||||||
|
pub struct RustcDefaultCalls;
|
||||||
|
|
||||||
|
impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
|
||||||
|
fn early_callback(&mut self,
|
||||||
|
matches: &getopts::Matches,
|
||||||
|
descriptions: &diagnostics::registry::Registry)
|
||||||
|
-> Compilation {
|
||||||
|
match matches.opt_str("explain") {
|
||||||
|
Some(ref code) => {
|
||||||
|
match descriptions.find_description(&code[]) {
|
||||||
|
Some(ref description) => {
|
||||||
|
println!("{}", description);
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
early_error(&format!("no extended information for {}", code)[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Compilation::Stop;
|
||||||
|
},
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
|
||||||
|
return Compilation::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn no_input(&mut self,
|
||||||
|
matches: &getopts::Matches,
|
||||||
|
sopts: &config::Options,
|
||||||
|
odir: &Option<Path>,
|
||||||
|
ofile: &Option<Path>,
|
||||||
|
descriptions: &diagnostics::registry::Registry)
|
||||||
|
-> Option<(Input, Option<Path>)> {
|
||||||
|
match matches.free.len() {
|
||||||
|
0 => {
|
||||||
|
if sopts.describe_lints {
|
||||||
|
let mut ls = lint::LintStore::new();
|
||||||
|
ls.register_builtin(None);
|
||||||
|
describe_lints(&ls, false);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let sess = build_session(sopts.clone(), None, descriptions.clone());
|
||||||
|
let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile);
|
||||||
|
if should_stop == Compilation::Stop {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
early_error("no input filename given");
|
||||||
|
}
|
||||||
|
1 => panic!("make_input should have provided valid inputs"),
|
||||||
|
_ => early_error("multiple input filenames provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_pretty(&mut self,
|
||||||
|
sess: &Session,
|
||||||
|
matches: &getopts::Matches)
|
||||||
|
-> Option<(PpMode, Option<UserIdentifiedItem>)> {
|
||||||
|
let pretty = if sess.opts.debugging_opts.unstable_options {
|
||||||
|
matches.opt_default("pretty", "normal").map(|a| {
|
||||||
|
// stable pretty-print variants only
|
||||||
|
pretty::parse_pretty(sess, &a, false)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if pretty.is_none() && sess.unstable_options() {
|
||||||
|
matches.opt_str("xpretty").map(|a| {
|
||||||
|
// extended with unstable pretty-print variants
|
||||||
|
pretty::parse_pretty(sess, &a, true)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
pretty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn late_callback(&mut self,
|
||||||
|
matches: &getopts::Matches,
|
||||||
|
sess: &Session,
|
||||||
|
input: &Input,
|
||||||
|
odir: &Option<Path>,
|
||||||
|
ofile: &Option<Path>)
|
||||||
|
-> Compilation {
|
||||||
|
RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile).and_then(
|
||||||
|
|| RustcDefaultCalls::list_metadata(sess, matches, input))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_controller(&mut self, sess: &Session) -> CompileController<'a> {
|
||||||
|
let mut control = CompileController::basic();
|
||||||
|
|
||||||
|
if sess.opts.parse_only ||
|
||||||
|
sess.opts.show_span.is_some() ||
|
||||||
|
sess.opts.debugging_opts.ast_json_noexpand {
|
||||||
|
control.after_parse.stop = Compilation::Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json {
|
||||||
|
control.after_write_deps.stop = Compilation::Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if sess.opts.no_trans {
|
||||||
|
control.after_analysis.stop = Compilation::Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) {
|
||||||
|
control.after_llvm.stop = Compilation::Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
if sess.opts.debugging_opts.save_analysis {
|
||||||
|
control.after_analysis.callback = box |state| {
|
||||||
|
time(state.session.time_passes(), "save analysis", state.krate.unwrap(), |krate|
|
||||||
|
save::process_crate(state.session,
|
||||||
|
krate,
|
||||||
|
state.analysis.unwrap(),
|
||||||
|
state.out_dir));
|
||||||
|
};
|
||||||
|
control.make_glob_map = resolve::MakeGlobMap::Yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
control
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RustcDefaultCalls {
|
||||||
|
pub fn list_metadata(sess: &Session,
|
||||||
|
matches: &getopts::Matches,
|
||||||
|
input: &Input)
|
||||||
|
-> Compilation {
|
||||||
|
let r = matches.opt_strs("Z");
|
||||||
|
if r.contains(&("ls".to_string())) {
|
||||||
|
match input {
|
||||||
|
&Input::File(ref ifile) => {
|
||||||
|
let mut stdout = old_io::stdout();
|
||||||
|
let path = &(*ifile);
|
||||||
|
metadata::loader::list_file_metadata(sess.target.target.options.is_like_osx,
|
||||||
|
path,
|
||||||
|
&mut stdout).unwrap();
|
||||||
|
}
|
||||||
|
&Input::Str(_) => {
|
||||||
|
early_error("cannot list metadata for stdin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Compilation::Stop;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Compilation::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn print_crate_info(sess: &Session,
|
||||||
|
input: Option<&Input>,
|
||||||
|
odir: &Option<Path>,
|
||||||
|
ofile: &Option<Path>)
|
||||||
|
-> Compilation {
|
||||||
|
if sess.opts.prints.len() == 0 {
|
||||||
|
return Compilation::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let attrs = input.map(|input| parse_crate_attrs(sess, input));
|
||||||
|
for req in &sess.opts.prints {
|
||||||
|
match *req {
|
||||||
|
PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
|
||||||
|
PrintRequest::FileNames |
|
||||||
|
PrintRequest::CrateName => {
|
||||||
|
let input = match input {
|
||||||
|
Some(input) => input,
|
||||||
|
None => early_error("no input file provided"),
|
||||||
|
};
|
||||||
|
let attrs = attrs.as_ref().unwrap();
|
||||||
|
let t_outputs = driver::build_output_filenames(input,
|
||||||
|
odir,
|
||||||
|
ofile,
|
||||||
|
attrs,
|
||||||
|
sess);
|
||||||
|
let id = link::find_crate_name(Some(sess),
|
||||||
|
attrs,
|
||||||
|
input);
|
||||||
|
if *req == PrintRequest::CrateName {
|
||||||
|
println!("{}", id);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let crate_types = driver::collect_crate_types(sess, attrs);
|
||||||
|
let metadata = driver::collect_crate_metadata(sess, attrs);
|
||||||
|
*sess.crate_metadata.borrow_mut() = metadata;
|
||||||
|
for &style in &crate_types {
|
||||||
|
let fname = link::filename_for_input(sess,
|
||||||
|
style,
|
||||||
|
&id,
|
||||||
|
&t_outputs.with_extension(""));
|
||||||
|
println!("{}", fname.filename_display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Compilation::Stop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -535,50 +737,6 @@ pub fn handle_options(mut args: Vec<String>) -> Option<getopts::Matches> {
|
|||||||
Some(matches)
|
Some(matches)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_crate_info(sess: &Session,
|
|
||||||
input: Option<&Input>,
|
|
||||||
odir: &Option<Path>,
|
|
||||||
ofile: &Option<Path>)
|
|
||||||
-> bool {
|
|
||||||
if sess.opts.prints.len() == 0 { return false }
|
|
||||||
|
|
||||||
let attrs = input.map(|input| parse_crate_attrs(sess, input));
|
|
||||||
for req in &sess.opts.prints {
|
|
||||||
match *req {
|
|
||||||
PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
|
|
||||||
PrintRequest::FileNames |
|
|
||||||
PrintRequest::CrateName => {
|
|
||||||
let input = match input {
|
|
||||||
Some(input) => input,
|
|
||||||
None => early_error("no input file provided"),
|
|
||||||
};
|
|
||||||
let attrs = attrs.as_ref().unwrap();
|
|
||||||
let t_outputs = driver::build_output_filenames(input,
|
|
||||||
odir,
|
|
||||||
ofile,
|
|
||||||
attrs,
|
|
||||||
sess);
|
|
||||||
let id = link::find_crate_name(Some(sess), attrs,
|
|
||||||
input);
|
|
||||||
if *req == PrintRequest::CrateName {
|
|
||||||
println!("{}", id);
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
let crate_types = driver::collect_crate_types(sess, attrs);
|
|
||||||
let metadata = driver::collect_crate_metadata(sess, attrs);
|
|
||||||
*sess.crate_metadata.borrow_mut() = metadata;
|
|
||||||
for &style in &crate_types {
|
|
||||||
let fname = link::filename_for_input(sess, style,
|
|
||||||
&id,
|
|
||||||
&t_outputs.with_extension(""));
|
|
||||||
println!("{}", fname.filename_display());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_crate_attrs(sess: &Session, input: &Input) ->
|
fn parse_crate_attrs(sess: &Session, input: &Input) ->
|
||||||
Vec<ast::Attribute> {
|
Vec<ast::Attribute> {
|
||||||
let result = match *input {
|
let result = match *input {
|
||||||
@ -598,11 +756,6 @@ fn parse_crate_attrs(sess: &Session, input: &Input) ->
|
|||||||
result.into_iter().collect()
|
result.into_iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_metadata(sess: &Session, path: &Path,
|
|
||||||
out: &mut old_io::Writer) -> old_io::IoResult<()> {
|
|
||||||
metadata::loader::list_file_metadata(sess.target.target.options.is_like_osx, path, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a procedure which will detect panics in the compiler and print nicer
|
/// Run a procedure which will detect panics in the compiler and print nicer
|
||||||
/// error messages rather than just failing the test.
|
/// error messages rather than just failing the test.
|
||||||
///
|
///
|
||||||
|
@ -21,9 +21,9 @@ use std::thunk::Thunk;
|
|||||||
use std::collections::{HashSet, HashMap};
|
use std::collections::{HashSet, HashMap};
|
||||||
use testing;
|
use testing;
|
||||||
use rustc::session::{self, config};
|
use rustc::session::{self, config};
|
||||||
|
use rustc::session::config::get_unstable_features_setting;
|
||||||
use rustc::session::search_paths::{SearchPaths, PathKind};
|
use rustc::session::search_paths::{SearchPaths, PathKind};
|
||||||
use rustc_driver::get_unstable_features_setting;
|
use rustc_driver::{driver, Compilation};
|
||||||
use rustc_driver::driver;
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::codemap::{CodeMap, dummy_spanned};
|
use syntax::codemap::{CodeMap, dummy_spanned};
|
||||||
use syntax::diagnostic;
|
use syntax::diagnostic;
|
||||||
@ -178,7 +178,7 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
|
|||||||
let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
|
let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
|
||||||
let mut control = driver::CompileController::basic();
|
let mut control = driver::CompileController::basic();
|
||||||
if no_run {
|
if no_run {
|
||||||
control.after_analysis.stop = true;
|
control.after_analysis.stop = Compilation::Stop;
|
||||||
}
|
}
|
||||||
driver::compile_input(sess, cfg, &input, &out, &None, None, control);
|
driver::compile_input(sess, cfg, &input, &out, &None, None, control);
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Registry {
|
pub struct Registry {
|
||||||
descriptions: HashMap<&'static str, &'static str>
|
descriptions: HashMap<&'static str, &'static str>
|
||||||
}
|
}
|
||||||
|
81
src/test/run-pass-fulldeps/compiler-calls.rs
Normal file
81
src/test/run-pass-fulldeps/compiler-calls.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright 2015 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.
|
||||||
|
|
||||||
|
// Test that the CompilerCalls interface to the compiler works.
|
||||||
|
|
||||||
|
// ignore-android
|
||||||
|
|
||||||
|
#![feature(rustc_private)]
|
||||||
|
#![feature(core)]
|
||||||
|
|
||||||
|
extern crate getopts;
|
||||||
|
extern crate rustc;
|
||||||
|
extern crate rustc_driver;
|
||||||
|
extern crate syntax;
|
||||||
|
|
||||||
|
use rustc::session::Session;
|
||||||
|
use rustc::session::config::{self, Input};
|
||||||
|
use rustc_driver::{driver, CompilerCalls, Compilation};
|
||||||
|
use syntax::diagnostics;
|
||||||
|
|
||||||
|
|
||||||
|
struct TestCalls {
|
||||||
|
count: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CompilerCalls<'a> for TestCalls {
|
||||||
|
fn early_callback(&mut self,
|
||||||
|
_: &getopts::Matches,
|
||||||
|
_: &diagnostics::registry::Registry)
|
||||||
|
-> Compilation {
|
||||||
|
self.count *= 2;
|
||||||
|
Compilation::Continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn late_callback(&mut self,
|
||||||
|
_: &getopts::Matches,
|
||||||
|
_: &Session,
|
||||||
|
_: &Input,
|
||||||
|
_: &Option<Path>,
|
||||||
|
_: &Option<Path>)
|
||||||
|
-> Compilation {
|
||||||
|
self.count *= 3;
|
||||||
|
Compilation::Stop
|
||||||
|
}
|
||||||
|
|
||||||
|
fn some_input(&mut self, input: Input, input_path: Option<Path>) -> (Input, Option<Path>) {
|
||||||
|
self.count *= 5;
|
||||||
|
(input, input_path)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn no_input(&mut self,
|
||||||
|
_: &getopts::Matches,
|
||||||
|
_: &config::Options,
|
||||||
|
_: &Option<Path>,
|
||||||
|
_: &Option<Path>,
|
||||||
|
_: &diagnostics::registry::Registry)
|
||||||
|
-> Option<(Input, Option<Path>)> {
|
||||||
|
panic!("This shouldn't happen");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
|
||||||
|
panic!("This shouldn't be called");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut tc = TestCalls { count: 1 };
|
||||||
|
// we should never get use this filename, but lets make sure they are valid args.
|
||||||
|
let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()];
|
||||||
|
rustc_driver::run_compiler(args.as_slice(), &mut tc);
|
||||||
|
assert!(tc.count == 30);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user