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::token::InternedString;
|
||||
|
||||
use getopts;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||
use getopts;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
|
||||
use llvm;
|
||||
@ -821,7 +822,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
|
||||
}
|
||||
|
||||
pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
|
||||
let unparsed_crate_types = matches.opt_strs("crate-type");
|
||||
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
|
||||
.unwrap_or_else(|e| early_error(&e[]));
|
||||
@ -1041,7 +1041,22 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
crate_name: crate_name,
|
||||
alt_std_name: None,
|
||||
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
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -27,6 +27,7 @@ use rustc_trans::back::write;
|
||||
use rustc_trans::trans;
|
||||
use rustc_typeck as typeck;
|
||||
use rustc_privacy;
|
||||
use super::Compilation;
|
||||
|
||||
use serialize::json;
|
||||
|
||||
@ -55,7 +56,7 @@ pub fn compile_input(sess: Session,
|
||||
let state = $make_state;
|
||||
(control.$point.callback)(state);
|
||||
}
|
||||
if control.$point.stop {
|
||||
if control.$point.stop == Compilation::Stop {
|
||||
return;
|
||||
}
|
||||
})}
|
||||
@ -206,14 +207,14 @@ impl<'a> CompileController<'a> {
|
||||
}
|
||||
|
||||
pub struct PhaseController<'a> {
|
||||
pub stop: bool,
|
||||
pub stop: Compilation,
|
||||
pub callback: Box<Fn(CompileState) -> () + 'a>,
|
||||
}
|
||||
|
||||
impl<'a> PhaseController<'a> {
|
||||
pub fn basic() -> PhaseController<'a> {
|
||||
PhaseController {
|
||||
stop: false,
|
||||
stop: Compilation::Continue,
|
||||
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
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -60,12 +60,13 @@ extern crate "rustc_llvm" as llvm;
|
||||
pub use syntax::diagnostic;
|
||||
|
||||
use driver::CompileController;
|
||||
use pretty::{PpMode, UserIdentifiedItem};
|
||||
|
||||
use rustc_resolve as resolve;
|
||||
use rustc_trans::back::link;
|
||||
use rustc_trans::save;
|
||||
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;
|
||||
use rustc::metadata;
|
||||
@ -92,95 +93,59 @@ pub mod test;
|
||||
pub mod driver;
|
||||
pub mod pretty;
|
||||
|
||||
pub fn run(args: Vec<String>) -> int {
|
||||
monitor(move || run_compiler(&args));
|
||||
0
|
||||
}
|
||||
|
||||
static BUG_REPORT_URL: &'static str =
|
||||
"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()) {
|
||||
Some(matches) => matches,
|
||||
None => return
|
||||
};
|
||||
|
||||
let descriptions = diagnostics_registry();
|
||||
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;
|
||||
},
|
||||
None => ()
|
||||
}
|
||||
|
||||
do_or_return!(callbacks.early_callback(&matches, &descriptions));
|
||||
|
||||
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;
|
||||
sopts.unstable_features = get_unstable_features_setting();
|
||||
let (odir, ofile) = make_output(&matches);
|
||||
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 cfg = config::build_configuration(&sess);
|
||||
if print_crate_info(&sess, Some(&input), &odir, &ofile) {
|
||||
return
|
||||
if sess.unstable_options() {
|
||||
sess.opts.show_span = matches.opt_str("show-span");
|
||||
}
|
||||
let cfg = config::build_configuration(&sess);
|
||||
|
||||
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
|
||||
};
|
||||
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
|
||||
};
|
||||
do_or_return!(callbacks.late_callback(&matches, &sess, &input, &odir, &ofile));
|
||||
|
||||
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)) => {
|
||||
pretty::pretty_print_input(sess, cfg, &input, ppm, opt_uii, ofile);
|
||||
return;
|
||||
@ -188,76 +153,313 @@ fn run_compiler(args: &[String]) {
|
||||
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 control = build_controller(&sess);
|
||||
let control = callbacks.build_controller(&sess);
|
||||
driver::compile_input(sess, cfg, &input, &odir, &ofile, Some(plugins), control);
|
||||
}
|
||||
|
||||
fn build_controller<'a>(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 = 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
|
||||
// Extract output directory and file from matches.
|
||||
fn make_output(matches: &getopts::Matches) -> (Option<Path>, Option<Path>) {
|
||||
let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
|
||||
let ofile = matches.opt_str("o").map(|o| Path::new(o));
|
||||
(odir, ofile)
|
||||
}
|
||||
|
||||
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
|
||||
// Extract input (string or file and optional path) from matches.
|
||||
fn make_input(free_matches: &[String]) -> Option<(Input, Option<Path>)> {
|
||||
if free_matches.len() == 1 {
|
||||
let ifile = &free_matches[0][];
|
||||
if ifile == "-" {
|
||||
let contents = old_io::stdin().read_to_end().unwrap();
|
||||
let src = String::from_utf8(contents).unwrap();
|
||||
Some((Input::Str(src), None))
|
||||
} else {
|
||||
Some((Input::File(Path::new(ifile)), Some(Path::new(ifile))))
|
||||
}
|
||||
} 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)
|
||||
}
|
||||
|
||||
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) ->
|
||||
Vec<ast::Attribute> {
|
||||
let result = match *input {
|
||||
@ -598,11 +756,6 @@ fn parse_crate_attrs(sess: &Session, input: &Input) ->
|
||||
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
|
||||
/// error messages rather than just failing the test.
|
||||
///
|
||||
|
@ -21,9 +21,9 @@ use std::thunk::Thunk;
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use testing;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::session::config::get_unstable_features_setting;
|
||||
use rustc::session::search_paths::{SearchPaths, PathKind};
|
||||
use rustc_driver::get_unstable_features_setting;
|
||||
use rustc_driver::driver;
|
||||
use rustc_driver::{driver, Compilation};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{CodeMap, dummy_spanned};
|
||||
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 mut control = driver::CompileController::basic();
|
||||
if no_run {
|
||||
control.after_analysis.stop = true;
|
||||
control.after_analysis.stop = Compilation::Stop;
|
||||
}
|
||||
driver::compile_input(sess, cfg, &input, &out, &None, None, control);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Registry {
|
||||
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