auto merge of #11077 : alexcrichton/rust/crate-id, r=cmr
Right now the --crate-id and related flags are all process *after* the entire crate is parsed. This is less than desirable when used with makefiles because it means that just to learn the output name of the crate you have to parse the entire crate (unnecessary). This commit changes the behavior to lift the handling of these flags much sooner in the compilation process. This allows us to not have to parse the entire crate and only have to worry about parsing the crate attributes themselves. The related methods have all been updated to take an array of attributes rather than a crate. Additionally, this ceases duplication of the "what output are we producing" logic in order to correctly handle things in the case of --test. Finally, this adds tests for all of this functionality to ensure that it does not regress.
This commit is contained in:
commit
9d1de0b699
@ -447,7 +447,7 @@ unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef,
|
||||
*/
|
||||
|
||||
pub fn build_link_meta(sess: Session,
|
||||
c: &ast::Crate,
|
||||
attrs: &[ast::Attribute],
|
||||
output: &Path,
|
||||
symbol_hasher: &mut Sha256)
|
||||
-> LinkMeta {
|
||||
@ -458,7 +458,7 @@ fn crate_hash(symbol_hasher: &mut Sha256, pkgid: &PkgId) -> @str {
|
||||
truncated_hash_result(symbol_hasher).to_managed()
|
||||
}
|
||||
|
||||
let pkgid = match attr::find_pkgid(c.attrs) {
|
||||
let pkgid = match attr::find_pkgid(attrs) {
|
||||
None => {
|
||||
let stem = session::expect(
|
||||
sess,
|
||||
|
@ -165,7 +165,7 @@ pub fn phase_2_configure_and_expand(sess: Session,
|
||||
let time_passes = sess.time_passes();
|
||||
|
||||
*sess.building_library = session::building_library(sess.opts, &crate);
|
||||
*sess.outputs = session::collect_outputs(sess.opts, &crate);
|
||||
*sess.outputs = session::collect_outputs(sess.opts, crate.attrs);
|
||||
|
||||
time(time_passes, "gated feature checking", (), |_|
|
||||
front::feature_gate::check_crate(sess, &crate));
|
||||
@ -446,42 +446,6 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
|
||||
let (outputs, trans) = {
|
||||
let expanded_crate = {
|
||||
let crate = phase_1_parse_input(sess, cfg.clone(), input);
|
||||
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 t_outputs = build_output_filenames(input, outdir, output, crate.attrs, sess);
|
||||
if crate_id || crate_name {
|
||||
let pkgid = match attr::find_pkgid(crate.attrs) {
|
||||
Some(pkgid) => pkgid,
|
||||
None => fail!("No crate_id and --crate-id or --crate-name requested")
|
||||
};
|
||||
if crate_id {
|
||||
println(pkgid.to_str());
|
||||
}
|
||||
if crate_name {
|
||||
println(pkgid.name);
|
||||
}
|
||||
}
|
||||
|
||||
if crate_file_name {
|
||||
let lm = link::build_link_meta(sess, &crate, &t_outputs.obj_filename,
|
||||
&mut ::util::sha2::Sha256::new());
|
||||
// if the vector is empty we default to OutputExecutable.
|
||||
let style = sess.opts.outputs.get_opt(0).unwrap_or(&OutputExecutable);
|
||||
let fname = link::filename_for_input(&sess, *style, &lm,
|
||||
&t_outputs.out_filename);
|
||||
println!("{}", fname.display());
|
||||
|
||||
// we already maybe printed the first one, so skip it
|
||||
for style in sess.opts.outputs.iter().skip(1) {
|
||||
let fname = link::filename_for_input(&sess, *style, &lm,
|
||||
&t_outputs.out_filename);
|
||||
println!("{}", fname.display());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if stop_after_phase_1(sess) { return; }
|
||||
phase_2_configure_and_expand(sess, cfg, crate)
|
||||
};
|
||||
|
@ -421,14 +421,15 @@ pub fn building_library(options: &options, crate: &ast::Crate) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_outputs(options: &options, crate: &ast::Crate) -> ~[OutputStyle] {
|
||||
pub fn collect_outputs(options: &options,
|
||||
attrs: &[ast::Attribute]) -> ~[OutputStyle] {
|
||||
// If we're generating a test executable, then ignore all other output
|
||||
// styles at all other locations
|
||||
if options.test {
|
||||
return ~[OutputExecutable];
|
||||
}
|
||||
let mut base = options.outputs.clone();
|
||||
let mut iter = crate.attrs.iter().filter_map(|a| {
|
||||
let mut iter = attrs.iter().filter_map(|a| {
|
||||
if "crate_type" == a.name() {
|
||||
match a.value_str() {
|
||||
Some(n) if "rlib" == n => Some(OutputRlib),
|
||||
|
@ -21,14 +21,12 @@
|
||||
extern mod extra;
|
||||
extern mod syntax;
|
||||
|
||||
use driver::driver::{host_triple, optgroups, early_error};
|
||||
use driver::driver::{str_input, file_input, build_session_options};
|
||||
use driver::driver::{build_session, build_configuration, parse_pretty};
|
||||
use driver::driver::{PpMode, pretty_print_input, list_metadata};
|
||||
use driver::driver::{compile_input};
|
||||
use back::link;
|
||||
use driver::session;
|
||||
use middle::lint;
|
||||
|
||||
use d = driver::driver;
|
||||
|
||||
use std::cast;
|
||||
use std::comm;
|
||||
use std::io;
|
||||
@ -41,9 +39,12 @@
|
||||
use std::vec;
|
||||
use extra::getopts::groups;
|
||||
use extra::getopts;
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
use syntax::codemap;
|
||||
use syntax::diagnostic::Emitter;
|
||||
use syntax::diagnostic;
|
||||
use syntax::parse;
|
||||
|
||||
pub mod middle {
|
||||
pub mod trans;
|
||||
@ -137,7 +138,7 @@ pub fn version(argv0: &str) {
|
||||
None => "unknown version"
|
||||
};
|
||||
println!("{} {}", argv0, vers);
|
||||
println!("host: {}", host_triple());
|
||||
println!("host: {}", d::host_triple());
|
||||
}
|
||||
|
||||
pub fn usage(argv0: &str) {
|
||||
@ -146,7 +147,7 @@ pub fn usage(argv0: &str) {
|
||||
Additional help:
|
||||
-W help Print 'lint' options and default settings
|
||||
-Z help Print internal options for debugging rustc\n",
|
||||
groups::usage(message, optgroups()));
|
||||
groups::usage(message, d::optgroups()));
|
||||
}
|
||||
|
||||
pub fn describe_warnings() {
|
||||
@ -206,10 +207,10 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
|
||||
if args.is_empty() { usage(binary); return; }
|
||||
|
||||
let matches =
|
||||
&match getopts::groups::getopts(args, optgroups()) {
|
||||
&match getopts::groups::getopts(args, d::optgroups()) {
|
||||
Ok(m) => m,
|
||||
Err(f) => {
|
||||
early_error(demitter, f.to_err_msg());
|
||||
d::early_error(demitter, f.to_err_msg());
|
||||
}
|
||||
};
|
||||
|
||||
@ -246,48 +247,97 @@ pub fn run_compiler(args: &[~str], demitter: @diagnostic::Emitter) {
|
||||
return;
|
||||
}
|
||||
let input = match matches.free.len() {
|
||||
0u => early_error(demitter, "no input filename given"),
|
||||
0u => d::early_error(demitter, "no input filename given"),
|
||||
1u => {
|
||||
let ifile = matches.free[0].as_slice();
|
||||
if "-" == ifile {
|
||||
let src = str::from_utf8_owned(io::stdin().read_to_end());
|
||||
str_input(src.to_managed())
|
||||
d::str_input(src.to_managed())
|
||||
} else {
|
||||
file_input(Path::new(ifile))
|
||||
d::file_input(Path::new(ifile))
|
||||
}
|
||||
}
|
||||
_ => early_error(demitter, "multiple input filenames provided")
|
||||
_ => d::early_error(demitter, "multiple input filenames provided")
|
||||
};
|
||||
|
||||
let sopts = build_session_options(binary, matches, demitter);
|
||||
let sess = build_session(sopts, demitter);
|
||||
let sopts = d::build_session_options(binary, matches, demitter);
|
||||
let sess = d::build_session(sopts, demitter);
|
||||
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 = build_configuration(sess);
|
||||
let cfg = d::build_configuration(sess);
|
||||
let pretty = matches.opt_default("pretty", "normal").map(|a| {
|
||||
parse_pretty(sess, a)
|
||||
d::parse_pretty(sess, a)
|
||||
});
|
||||
match pretty {
|
||||
Some::<PpMode>(ppm) => {
|
||||
pretty_print_input(sess, cfg, &input, ppm);
|
||||
Some::<d::PpMode>(ppm) => {
|
||||
d::pretty_print_input(sess, cfg, &input, ppm);
|
||||
return;
|
||||
}
|
||||
None::<PpMode> => {/* continue */ }
|
||||
None::<d::PpMode> => {/* continue */ }
|
||||
}
|
||||
let ls = matches.opt_present("ls");
|
||||
if ls {
|
||||
match input {
|
||||
file_input(ref ifile) => {
|
||||
list_metadata(sess, &(*ifile), @mut io::stdout() as @mut io::Writer);
|
||||
d::file_input(ref ifile) => {
|
||||
d::list_metadata(sess, &(*ifile),
|
||||
@mut io::stdout() as @mut io::Writer);
|
||||
}
|
||||
str_input(_) => {
|
||||
early_error(demitter, "can not list metadata for stdin");
|
||||
d::str_input(_) => {
|
||||
d::early_error(demitter, "can not list metadata for stdin");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
let (crate_id, crate_name, crate_file_name) = sopts.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, sess);
|
||||
if crate_id || crate_name {
|
||||
let pkgid = match attr::find_pkgid(attrs) {
|
||||
Some(pkgid) => pkgid,
|
||||
None => {
|
||||
sess.fatal("No crate_id and --crate-id or \
|
||||
--crate-name requested")
|
||||
}
|
||||
};
|
||||
if crate_id {
|
||||
println(pkgid.to_str());
|
||||
}
|
||||
if crate_name {
|
||||
println(pkgid.name);
|
||||
}
|
||||
}
|
||||
|
||||
compile_input(sess, cfg, &input, &odir, &ofile);
|
||||
if crate_file_name {
|
||||
let lm = link::build_link_meta(sess, attrs, &t_outputs.obj_filename,
|
||||
&mut ::util::sha2::Sha256::new());
|
||||
let outputs = session::collect_outputs(sopts, attrs);
|
||||
for &style in outputs.iter() {
|
||||
let fname = link::filename_for_input(&sess, style, &lm,
|
||||
&t_outputs.out_filename);
|
||||
println!("{}", fname.filename_display());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
d::compile_input(sess, cfg, &input, &odir, &ofile);
|
||||
}
|
||||
|
||||
fn parse_crate_attrs(sess: session::Session,
|
||||
input: &d::input) -> ~[ast::Attribute] {
|
||||
match *input {
|
||||
d::file_input(ref ifile) => {
|
||||
parse::parse_crate_attrs_from_file(ifile, ~[], sess.parse_sess)
|
||||
}
|
||||
d::str_input(src) => {
|
||||
parse::parse_crate_attrs_from_source_str(
|
||||
d::anon_src(), src, ~[], sess.parse_sess)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
|
@ -3096,7 +3096,7 @@ pub fn trans_crate(sess: session::Session,
|
||||
}
|
||||
|
||||
let mut symbol_hasher = Sha256::new();
|
||||
let link_meta = link::build_link_meta(sess, &crate, output,
|
||||
let link_meta = link::build_link_meta(sess, crate.attrs, output,
|
||||
&mut symbol_hasher);
|
||||
|
||||
// Append ".rc" to crate name as LLVM module identifier.
|
||||
|
@ -79,6 +79,16 @@ pub fn parse_crate_from_file(
|
||||
// why is there no p.abort_if_errors here?
|
||||
}
|
||||
|
||||
pub fn parse_crate_attrs_from_file(
|
||||
input: &Path,
|
||||
cfg: ast::CrateConfig,
|
||||
sess: @mut ParseSess
|
||||
) -> ~[ast::Attribute] {
|
||||
let parser = new_parser_from_file(sess, cfg, input);
|
||||
let (inner, _) = parser.parse_inner_attrs_and_next();
|
||||
return inner;
|
||||
}
|
||||
|
||||
pub fn parse_crate_from_source_str(
|
||||
name: @str,
|
||||
source: @str,
|
||||
@ -92,6 +102,20 @@ pub fn parse_crate_from_source_str(
|
||||
maybe_aborted(p.parse_crate_mod(),p)
|
||||
}
|
||||
|
||||
pub fn parse_crate_attrs_from_source_str(
|
||||
name: @str,
|
||||
source: @str,
|
||||
cfg: ast::CrateConfig,
|
||||
sess: @mut ParseSess
|
||||
) -> ~[ast::Attribute] {
|
||||
let p = new_parser_from_source_str(sess,
|
||||
/*bad*/ cfg.clone(),
|
||||
name,
|
||||
source);
|
||||
let (inner, _) = maybe_aborted(p.parse_inner_attrs_and_next(),p);
|
||||
return inner;
|
||||
}
|
||||
|
||||
pub fn parse_expr_from_source_str(
|
||||
name: @str,
|
||||
source: @str,
|
||||
|
10
src/test/run-make/crate-data-smoke/Makefile
Normal file
10
src/test/run-make/crate-data-smoke/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all:
|
||||
[ `$(RUSTC) --crate-id crate.rs` = "foo#0.9" ]
|
||||
[ `$(RUSTC) --crate-name crate.rs` = "foo" ]
|
||||
[ `$(RUSTC) --crate-file-name crate.rs` = "foo" ]
|
||||
[ `$(RUSTC) --crate-file-name --lib --test crate.rs` = "foo" ]
|
||||
[ `$(RUSTC) --crate-file-name --test lib.rs` = "mylib" ]
|
||||
$(RUSTC) --crate-file-name lib.rs
|
||||
$(RUSTC) --crate-file-name rlib.rs
|
7
src/test/run-make/crate-data-smoke/crate.rs
Normal file
7
src/test/run-make/crate-data-smoke/crate.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#[crate_id = "foo#0.9"];
|
||||
|
||||
// Querying about the crate metadata should *not* parse the entire crate, it
|
||||
// only needs the crate attributes (which are guaranteed to be at the top) be
|
||||
// sure that if we have an error like a missing module that we can still query
|
||||
// about the crate id.
|
||||
mod error;
|
2
src/test/run-make/crate-data-smoke/lib.rs
Normal file
2
src/test/run-make/crate-data-smoke/lib.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[crate_id = "mylib"];
|
||||
#[crate_type = "lib"];
|
2
src/test/run-make/crate-data-smoke/rlib.rs
Normal file
2
src/test/run-make/crate-data-smoke/rlib.rs
Normal file
@ -0,0 +1,2 @@
|
||||
#[crate_id = "mylib"];
|
||||
#[crate_type = "rlib"];
|
Loading…
Reference in New Issue
Block a user