提交 c120464b 编写于 作者: T Tim Chevalier

rustc/rusti/rustpkg: Infer packages from `extern mod` directives

This commit won't be quite as useful until I implement RUST_PATH and
until we change `extern mod` to take a general string instead of
an identifier (#5682 and #6407).

With that said, now if you're using rustpkg and a program contains:

extern mod foo;

rustpkg will attempt to search for `foo`, so that you don't have to
provide a -L directory explicitly. In addition, rustpkg will
actually try to build and install `foo`, unless it's already
installed (specifically, I tested that `extern mod extra;` would
not cause it to try to find source for `extra` and compile it
again).

This is as per #5681.

Incidentally, I changed some driver code to infer the link name
from the crate link_meta attributes. If that change isn't ok, say
something. Also, I changed the addl_lib_search_paths field in the
session options to be an @mut ~[Path] so that it can be modified
after expansion but before later phases.
上级 341678b8
...@@ -161,8 +161,15 @@ pub fn parse_input(sess: Session, cfg: ast::crate_cfg, input: &input) ...@@ -161,8 +161,15 @@ pub fn parse_input(sess: Session, cfg: ast::crate_cfg, input: &input)
} }
} }
/// First phase to do, last phase to do
#[deriving(Eq)] #[deriving(Eq)]
pub enum compile_upto { pub struct compile_upto {
from: compile_phase,
to: compile_phase
}
#[deriving(Eq)]
pub enum compile_phase {
cu_parse, cu_parse,
cu_expand, cu_expand,
cu_typeck, cu_typeck,
...@@ -177,138 +184,147 @@ pub enum compile_upto { ...@@ -177,138 +184,147 @@ pub enum compile_upto {
#[fixed_stack_segment] #[fixed_stack_segment]
pub fn compile_rest(sess: Session, pub fn compile_rest(sess: Session,
cfg: ast::crate_cfg, cfg: ast::crate_cfg,
upto: compile_upto, phases: compile_upto,
outputs: Option<@OutputFilenames>, outputs: Option<@OutputFilenames>,
curr: Option<@ast::crate>) curr: Option<@ast::crate>)
-> (Option<@ast::crate>, Option<ty::ctxt>) { -> (Option<@ast::crate>, Option<ty::ctxt>) {
let time_passes = sess.time_passes(); let time_passes = sess.time_passes();
let (llmod, link_meta) = { let mut crate_opt = curr;
let mut crate = curr.unwrap(); if phases.from == cu_parse || phases.from == cu_everything {
*sess.building_library = session::building_library( *sess.building_library = session::building_library(
sess.opts.crate_type, crate, sess.opts.test); sess.opts.crate_type, crate_opt.unwrap(), sess.opts.test);
crate = time(time_passes, ~"expansion", || crate_opt = Some(time(time_passes, ~"expansion", ||
syntax::ext::expand::expand_crate(sess.parse_sess, copy cfg, syntax::ext::expand::expand_crate(sess.parse_sess, copy cfg,
crate)); crate_opt.unwrap())));
crate_opt = Some(time(time_passes, ~"configuration", ||
front::config::strip_unconfigured_items(crate_opt.unwrap())));
crate_opt = Some(time(time_passes, ~"maybe building test harness", ||
front::test::modify_for_testing(sess, crate_opt.unwrap())));
}
crate = time(time_passes, ~"configuration", || if phases.to == cu_expand { return (crate_opt, None); }
front::config::strip_unconfigured_items(crate));
crate = time(time_passes, ~"maybe building test harness", || assert!(phases.from != cu_no_trans);
front::test::modify_for_testing(sess, crate));
if upto == cu_expand { return (Some(crate), None); } let mut crate = crate_opt.unwrap();
crate = time(time_passes, ~"intrinsic injection", || let (llmod, link_meta) = {
front::intrinsic_inject::inject_intrinsic(sess, crate)); crate = time(time_passes, ~"intrinsic injection", ||
front::intrinsic_inject::inject_intrinsic(sess, crate));
crate = time(time_passes, ~"extra injection", || crate = time(time_passes, ~"extra injection", ||
front::std_inject::maybe_inject_libstd_ref(sess, crate)); front::std_inject::maybe_inject_libstd_ref(sess, crate));
let ast_map = time(time_passes, ~"ast indexing", || let ast_map = time(time_passes, ~"ast indexing", ||
syntax::ast_map::map_crate(sess.diagnostic(), crate)); syntax::ast_map::map_crate(sess.diagnostic(), crate));
time(time_passes, ~"external crate/lib resolution", || time(time_passes, ~"external crate/lib resolution", ||
creader::read_crates(sess.diagnostic(), crate, sess.cstore, creader::read_crates(sess.diagnostic(), crate, sess.cstore,
sess.filesearch, sess.filesearch,
session::sess_os_to_meta_os(sess.targ_cfg.os), session::sess_os_to_meta_os(sess.targ_cfg.os),
sess.opts.is_static, sess.opts.is_static,
sess.parse_sess.interner)); sess.parse_sess.interner));
let lang_items = time(time_passes, ~"language item collection", || let lang_items = time(time_passes, ~"language item collection", ||
middle::lang_items::collect_language_items(crate, sess)); middle::lang_items::collect_language_items(crate, sess));
let middle::resolve::CrateMap { let middle::resolve::CrateMap {
def_map: def_map, def_map: def_map,
exp_map2: exp_map2, exp_map2: exp_map2,
trait_map: trait_map trait_map: trait_map
} = } =
time(time_passes, ~"resolution", || time(time_passes, ~"resolution", ||
middle::resolve::resolve_crate(sess, lang_items, crate)); middle::resolve::resolve_crate(sess, lang_items, crate));
time(time_passes, ~"looking for entry point", time(time_passes, ~"looking for entry point",
|| middle::entry::find_entry_point(sess, crate, ast_map)); || middle::entry::find_entry_point(sess, crate, ast_map));
let freevars = time(time_passes, ~"freevar finding", || let freevars = time(time_passes, ~"freevar finding", ||
freevars::annotate_freevars(def_map, crate)); freevars::annotate_freevars(def_map, crate));
let region_map = time(time_passes, ~"region resolution", || let freevars = time(time_passes, ~"freevar finding", ||
middle::region::resolve_crate(sess, def_map, crate)); freevars::annotate_freevars(def_map, crate));
let rp_set = time(time_passes, ~"region parameterization inference", || let region_map = time(time_passes, ~"region resolution", ||
middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); middle::region::resolve_crate(sess, def_map, crate));
let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars, let rp_set = time(time_passes, ~"region parameterization inference", ||
region_map, rp_set, lang_items); middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate));
// passes are timed inside typeck let ty_cx = ty::mk_ctxt(sess, def_map, ast_map, freevars,
let (method_map, vtable_map) = typeck::check_crate( region_map, rp_set, lang_items);
ty_cx, trait_map, crate);
// These next two const passes can probably be merged // passes are timed inside typeck
time(time_passes, ~"const marking", || let (method_map, vtable_map) = typeck::check_crate(
middle::const_eval::process_crate(crate, ty_cx)); ty_cx, trait_map, crate);
time(time_passes, ~"const checking", || // These next two const passes can probably be merged
middle::check_const::check_crate(sess, crate, ast_map, def_map, time(time_passes, ~"const marking", ||
method_map, ty_cx)); middle::const_eval::process_crate(crate, ty_cx));
if upto == cu_typeck { return (Some(crate), Some(ty_cx)); } time(time_passes, ~"const checking", ||
middle::check_const::check_crate(sess, crate, ast_map, def_map,
method_map, ty_cx));
time(time_passes, ~"privacy checking", || if phases.to == cu_typeck { return (Some(crate), Some(ty_cx)); }
middle::privacy::check_crate(ty_cx, &method_map, crate));
time(time_passes, ~"effect checking", || time(time_passes, ~"privacy checking", ||
middle::effect::check_crate(ty_cx, method_map, crate)); middle::privacy::check_crate(ty_cx, &method_map, crate));
time(time_passes, ~"loop checking", || time(time_passes, ~"effect checking", ||
middle::check_loop::check_crate(ty_cx, crate)); middle::effect::check_crate(ty_cx, method_map, crate));
let middle::moves::MoveMaps {moves_map, moved_variables_set, time(time_passes, ~"loop checking", ||
capture_map} = middle::check_loop::check_crate(ty_cx, crate));
time(time_passes, ~"compute moves", ||
middle::moves::compute_moves(ty_cx, method_map, crate));
time(time_passes, ~"match checking", || let middle::moves::MoveMaps {moves_map, moved_variables_set,
middle::check_match::check_crate(ty_cx, method_map, capture_map} =
moves_map, crate)); time(time_passes, ~"compute moves", ||
middle::moves::compute_moves(ty_cx, method_map, crate));
time(time_passes, ~"liveness checking", || time(time_passes, ~"match checking", ||
middle::liveness::check_crate(ty_cx, method_map, middle::check_match::check_crate(ty_cx, method_map,
capture_map, crate)); moves_map, crate));
let (root_map, write_guard_map) = time(time_passes, ~"liveness checking", ||
time(time_passes, ~"borrow checking", || middle::liveness::check_crate(ty_cx, method_map,
middle::borrowck::check_crate(ty_cx, method_map, capture_map, crate));
moves_map, moved_variables_set,
capture_map, crate));
time(time_passes, ~"kind checking", || let (root_map, write_guard_map) =
kind::check_crate(ty_cx, method_map, crate)); time(time_passes, ~"borrow checking", ||
middle::borrowck::check_crate(ty_cx, method_map,
moves_map, moved_variables_set,
capture_map, crate));
time(time_passes, ~"lint checking", || time(time_passes, ~"kind checking", ||
lint::check_crate(ty_cx, crate)); kind::check_crate(ty_cx, method_map, crate));
if upto == cu_no_trans { return (Some(crate), Some(ty_cx)); } time(time_passes, ~"lint checking", ||
lint::check_crate(ty_cx, crate));
let maps = astencode::Maps { if phases.to == cu_no_trans { return (Some(crate), Some(ty_cx)); }
root_map: root_map,
method_map: method_map, let maps = astencode::Maps {
vtable_map: vtable_map, root_map: root_map,
write_guard_map: write_guard_map, method_map: method_map,
moves_map: moves_map, vtable_map: vtable_map,
capture_map: capture_map write_guard_map: write_guard_map,
}; moves_map: moves_map,
capture_map: capture_map
};
let outputs = outputs.get_ref(); let outputs = outputs.get_ref();
time(time_passes, ~"translation", || time(time_passes, ~"translation", ||
trans::base::trans_crate(sess, crate, ty_cx, trans::base::trans_crate(sess, crate, ty_cx,
&outputs.obj_filename, &outputs.obj_filename,
exp_map2, maps)) exp_map2, maps))
}; };
let outputs = outputs.get_ref(); let outputs = outputs.get_ref();
...@@ -351,7 +367,7 @@ pub fn compile_rest(sess: Session, ...@@ -351,7 +367,7 @@ pub fn compile_rest(sess: Session,
} }
pub fn compile_upto(sess: Session, cfg: ast::crate_cfg, pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
input: &input, upto: compile_upto, input: &input, upto: compile_phase,
outputs: Option<@OutputFilenames>) outputs: Option<@OutputFilenames>)
-> (Option<@ast::crate>, Option<ty::ctxt>) { -> (Option<@ast::crate>, Option<ty::ctxt>) {
let time_passes = sess.time_passes(); let time_passes = sess.time_passes();
...@@ -359,7 +375,8 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg, ...@@ -359,7 +375,8 @@ pub fn compile_upto(sess: Session, cfg: ast::crate_cfg,
|| parse_input(sess, copy cfg, input) ); || parse_input(sess, copy cfg, input) );
if upto == cu_parse { return (Some(crate), None); } if upto == cu_parse { return (Some(crate), None); }
compile_rest(sess, cfg, upto, outputs, Some(crate)) compile_rest(sess, cfg, compile_upto { from: cu_parse, to: upto },
outputs, Some(crate))
} }
pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input, pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input,
...@@ -367,7 +384,7 @@ pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input, ...@@ -367,7 +384,7 @@ pub fn compile_input(sess: Session, cfg: ast::crate_cfg, input: &input,
let upto = if sess.opts.parse_only { cu_parse } let upto = if sess.opts.parse_only { cu_parse }
else if sess.opts.no_trans { cu_no_trans } else if sess.opts.no_trans { cu_no_trans }
else { cu_everything }; else { cu_everything };
let outputs = build_output_filenames(input, outdir, output, sess); let outputs = build_output_filenames(input, outdir, output, [], sess); // ???
compile_upto(sess, cfg, input, upto, Some(outputs)); compile_upto(sess, cfg, input, upto, Some(outputs));
} }
...@@ -645,8 +662,7 @@ pub fn build_session_options(binary: @~str, ...@@ -645,8 +662,7 @@ pub fn build_session_options(binary: @~str,
~"2" => Default, ~"2" => Default,
~"3" => Aggressive, ~"3" => Aggressive,
_ => { _ => {
early_error(demitter, ~"optimization level needs " + early_error(demitter, ~"optimization level needs to be between 0-3")
"to be between 0-3")
} }
} }
} else { No } } else { No }
...@@ -706,7 +722,7 @@ pub fn build_session_options(binary: @~str, ...@@ -706,7 +722,7 @@ pub fn build_session_options(binary: @~str,
save_temps: save_temps, save_temps: save_temps,
jit: jit, jit: jit,
output_type: output_type, output_type: output_type,
addl_lib_search_paths: addl_lib_search_paths, addl_lib_search_paths: @mut addl_lib_search_paths,
linker: linker, linker: linker,
linker_args: linker_args, linker_args: linker_args,
maybe_sysroot: sysroot_opt, maybe_sysroot: sysroot_opt,
...@@ -745,7 +761,7 @@ pub fn build_session_(sopts: @session::options, ...@@ -745,7 +761,7 @@ pub fn build_session_(sopts: @session::options,
let filesearch = filesearch::mk_filesearch( let filesearch = filesearch::mk_filesearch(
&sopts.maybe_sysroot, &sopts.maybe_sysroot,
sopts.target_triple, sopts.target_triple,
/*bad*/copy sopts.addl_lib_search_paths); sopts.addl_lib_search_paths);
@Session_ { @Session_ {
targ_cfg: target_cfg, targ_cfg: target_cfg,
opts: sopts, opts: sopts,
...@@ -854,6 +870,7 @@ pub struct OutputFilenames { ...@@ -854,6 +870,7 @@ pub struct OutputFilenames {
pub fn build_output_filenames(input: &input, pub fn build_output_filenames(input: &input,
odir: &Option<Path>, odir: &Option<Path>,
ofile: &Option<Path>, ofile: &Option<Path>,
attrs: &[ast::attribute],
sess: Session) sess: Session)
-> @OutputFilenames { -> @OutputFilenames {
let obj_path; let obj_path;
...@@ -863,7 +880,6 @@ pub fn build_output_filenames(input: &input, ...@@ -863,7 +880,6 @@ pub fn build_output_filenames(input: &input,
sopts.output_type != link::output_type_exe || sopts.output_type != link::output_type_exe ||
sopts.is_static && *sess.building_library; sopts.is_static && *sess.building_library;
let obj_suffix = let obj_suffix =
match sopts.output_type { match sopts.output_type {
link::output_type_none => ~"none", link::output_type_none => ~"none",
...@@ -876,29 +892,44 @@ pub fn build_output_filenames(input: &input, ...@@ -876,29 +892,44 @@ pub fn build_output_filenames(input: &input,
match *ofile { match *ofile {
None => { None => {
// "-" as input file will cause the parser to read from stdin so we // "-" as input file will cause the parser to read from stdin so we
// have to make up a name // have to make up a name
// We want to toss everything after the final '.' // We want to toss everything after the final '.'
let dirpath = match *odir { let dirpath = match *odir {
Some(ref d) => (/*bad*/copy *d), Some(ref d) => (/*bad*/copy *d),
None => match *input { None => match *input {
str_input(_) => os::getcwd(), str_input(_) => os::getcwd(),
file_input(ref ifile) => (*ifile).dir_path() file_input(ref ifile) => (*ifile).dir_path()
}
};
let mut stem = match *input {
file_input(ref ifile) => (*ifile).filestem().get(),
str_input(_) => ~"rust_out"
};
// If a linkage name meta is present, we use it as the link name
let linkage_metas = attr::find_linkage_metas(attrs);
if !linkage_metas.is_empty() {
// But if a linkage meta is present, that overrides
let maybe_matches = attr::find_meta_items_by_name(linkage_metas, "name");
if !maybe_matches.is_empty() {
match attr::get_meta_item_value_str(maybe_matches[0]) {
Some(s) => stem = copy *s,
_ => ()
}
}
// If the name is missing, we just default to the filename
// version
} }
};
let stem = match *input { if *sess.building_library {
file_input(ref ifile) => (*ifile).filestem().get(), out_path = dirpath.push(os::dll_filename(stem));
str_input(_) => ~"rust_out" obj_path = dirpath.push(stem).with_filetype(obj_suffix);
}; } else {
out_path = dirpath.push(stem);
if *sess.building_library { obj_path = dirpath.push(stem).with_filetype(obj_suffix);
out_path = dirpath.push(os::dll_filename(stem)); }
obj_path = dirpath.push(stem).with_filetype(obj_suffix);
} else {
out_path = dirpath.push(stem);
obj_path = dirpath.push(stem).with_filetype(obj_suffix);
}
} }
Some(ref out_file) => { Some(ref out_file) => {
......
...@@ -136,7 +136,9 @@ pub struct options { ...@@ -136,7 +136,9 @@ pub struct options {
save_temps: bool, save_temps: bool,
jit: bool, jit: bool,
output_type: back::link::output_type, output_type: back::link::output_type,
addl_lib_search_paths: ~[Path], addl_lib_search_paths: @mut ~[Path], // This is mutable for rustpkg, which
// updates search paths based on the
// parsed code
linker: Option<~str>, linker: Option<~str>,
linker_args: ~[~str], linker_args: ~[~str],
maybe_sysroot: Option<@Path>, maybe_sysroot: Option<@Path>,
...@@ -316,7 +318,7 @@ pub fn basic_options() -> @options { ...@@ -316,7 +318,7 @@ pub fn basic_options() -> @options {
save_temps: false, save_temps: false,
jit: false, jit: false,
output_type: link::output_type_exe, output_type: link::output_type_exe,
addl_lib_search_paths: ~[], addl_lib_search_paths: @mut ~[],
linker: None, linker: None,
linker_args: ~[], linker_args: ~[],
maybe_sysroot: None, maybe_sysroot: None,
......
...@@ -35,17 +35,18 @@ pub trait FileSearch { ...@@ -35,17 +35,18 @@ pub trait FileSearch {
pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, pub fn mk_filesearch(maybe_sysroot: &Option<@Path>,
target_triple: &str, target_triple: &str,
addl_lib_search_paths: ~[Path]) addl_lib_search_paths: @mut ~[Path])
-> @FileSearch { -> @FileSearch {
struct FileSearchImpl { struct FileSearchImpl {
sysroot: @Path, sysroot: @Path,
addl_lib_search_paths: ~[Path], addl_lib_search_paths: @mut ~[Path],
target_triple: ~str target_triple: ~str
} }
impl FileSearch for FileSearchImpl { impl FileSearch for FileSearchImpl {
fn sysroot(&self) -> @Path { self.sysroot } fn sysroot(&self) -> @Path { self.sysroot }
fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool { fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) -> bool {
debug!("filesearch: searching additional lib search paths"); debug!("filesearch: searching additional lib search paths [%?]",
self.addl_lib_search_paths.len());
// a little weird // a little weird
self.addl_lib_search_paths.each(f); self.addl_lib_search_paths.each(f);
......
...@@ -183,11 +183,11 @@ pub fn version(argv0: &str) { ...@@ -183,11 +183,11 @@ pub fn version(argv0: &str) {
pub fn usage(argv0: &str) { pub fn usage(argv0: &str) {
let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0); let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
io::println(groups::usage(message, optgroups()) + io::println(fmt!("%s \
"Additional help: Additional help: \
-W help Print 'lint' options and default settings -W help Print 'lint' options and default settings \
-Z help Print internal options for debugging rustc -Z help Print internal options for debugging rustc",
"); groups::usage(message, optgroups())));
} }
pub fn describe_warnings() { pub fn describe_warnings() {
......
...@@ -121,7 +121,7 @@ fn run(repl: Repl, input: ~str) -> Repl { ...@@ -121,7 +121,7 @@ fn run(repl: Repl, input: ~str) -> Repl {
let options = @session::options { let options = @session::options {
crate_type: session::unknown_crate, crate_type: session::unknown_crate,
binary: binary, binary: binary,
addl_lib_search_paths: repl.lib_search_paths.map(|p| Path(*p)), addl_lib_search_paths: @mut repl.lib_search_paths.map(|p| Path(*p)),
jit: true, jit: true,
.. copy *session::basic_options() .. copy *session::basic_options()
}; };
...@@ -142,12 +142,13 @@ fn run(repl: Repl, input: ~str) -> Repl { ...@@ -142,12 +142,13 @@ fn run(repl: Repl, input: ~str) -> Repl {
binary, binary,
&wrapped); &wrapped);
let outputs = driver::build_output_filenames(&wrapped, &None, &None, sess); let outputs = driver::build_output_filenames(&wrapped, &None, &None, [], sess);
debug!("calling compile_upto"); debug!("calling compile_upto");
let crate = driver::parse_input(sess, copy cfg, &wrapped); let crate = driver::parse_input(sess, copy cfg, &wrapped);
driver::compile_rest(sess, cfg, driver::cu_everything, driver::compile_rest(sess, cfg, driver::compile_upto { from: driver::cu_parse,
Some(outputs), Some(crate)); to: driver::cu_everything },
Some(outputs), Some(crate));
let mut opt = None; let mut opt = None;
...@@ -188,7 +189,7 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> { ...@@ -188,7 +189,7 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
let binary = @copy binary; let binary = @copy binary;
let options = @session::options { let options = @session::options {
binary: binary, binary: binary,
addl_lib_search_paths: ~[os::getcwd()], addl_lib_search_paths: @mut ~[os::getcwd()],
.. copy *session::basic_options() .. copy *session::basic_options()
}; };
let input = driver::file_input(copy src_path); let input = driver::file_input(copy src_path);
...@@ -196,7 +197,7 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> { ...@@ -196,7 +197,7 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option<bool> {
*sess.building_library = true; *sess.building_library = true;
let cfg = driver::build_configuration(sess, binary, &input); let cfg = driver::build_configuration(sess, binary, &input);
let outputs = driver::build_output_filenames( let outputs = driver::build_output_filenames(
&input, &None, &None, sess); &input, &None, &None, [], sess);
// If the library already exists and is newer than the source // If the library already exists and is newer than the source
// file, skip compilation and return None. // file, skip compilation and return None.
let mut should_compile = true; let mut should_compile = true;
......
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
// Useful conditions // Useful conditions
pub use core::path::Path; pub use core::path::Path;
pub use util::PkgId; pub use package_id::PkgId;
condition! { condition! {
bad_path: (super::Path, ~str) -> super::Path; bad_path: (super::Path, ~str) -> super::Path;
} }
condition! { condition! {
nonexistent_package: (super::PkgId, ~str) -> (); nonexistent_package: (super::PkgId, ~str) -> super::Path;
} }
condition! { condition! {
...@@ -30,5 +30,5 @@ ...@@ -30,5 +30,5 @@
} }
condition! { condition! {
bad_pkg_id: (super::Path, ~str) -> ::util::PkgId; bad_pkg_id: (super::Path, ~str) -> super::PkgId;
} }
// Copyright 2013 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.
pub use package_path::{RemotePath, LocalPath, normalize, hash};
use extra::semver;
use core::prelude::*;
use core::result;
/// Placeholder
pub fn default_version() -> Version { ExactRevision(0.1) }
/// Path-fragment identifier of a package such as
/// 'github.com/graydon/test'; path must be a relative
/// path with >=1 component.
pub struct PkgId {
/// Remote path: for example, github.com/mozilla/quux-whatever
remote_path: RemotePath,
/// Local path: for example, /home/quux/github.com/mozilla/quux_whatever
/// Note that '-' normalizes to '_' when mapping a remote path
/// onto a local path
/// Also, this will change when we implement #6407, though we'll still
/// need to keep track of separate local and remote paths
local_path: LocalPath,
/// Short name. This is the local path's filestem, but we store it
/// redundantly so as to not call get() everywhere (filestem() returns an
/// option)
short_name: ~str,
version: Version
}
pub impl PkgId {
fn new(s: &str) -> PkgId {
use conditions::bad_pkg_id::cond;
let p = Path(s);
if p.is_absolute {
return cond.raise((p, ~"absolute pkgid"));
}
if p.components.len() < 1 {
return cond.raise((p, ~"0-length pkgid"));
}
let remote_path = RemotePath(p);
let local_path = normalize(copy remote_path);
let short_name = (copy local_path).filestem().expect(fmt!("Strange path! %s", s));
PkgId {
local_path: local_path,
remote_path: remote_path,
short_name: short_name,
version: default_version()
}
}
fn hash(&self) -> ~str {
fmt!("%s-%s-%s", self.remote_path.to_str(),
hash(self.remote_path.to_str() + self.version.to_str()),
self.version.to_str())
}
fn short_name_with_version(&self) -> ~str {
fmt!("%s-%s", self.short_name, self.version.to_str())
}
}
impl ToStr for PkgId {
fn to_str(&self) -> ~str {
// should probably use the filestem and not the whole path
fmt!("%s-%s", self.local_path.to_str(), self.version.to_str())
}
}
/// A version is either an exact revision,
/// or a semantic version
pub enum Version {
ExactRevision(float),
SemVersion(semver::Version)
}
impl Ord for Version {
fn lt(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 < f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 < v2,
_ => false // incomparable, really
}
}
fn le(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 <= f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 <= v2,
_ => false // incomparable, really
}
}
fn ge(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 > f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 > v2,
_ => false // incomparable, really
}
}
fn gt(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 >= f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 >= v2,
_ => false // incomparable, really
}
}
}
impl ToStr for Version {
fn to_str(&self) -> ~str {
match *self {
ExactRevision(ref n) => n.to_str(),
SemVersion(ref v) => v.to_str()
}
}
}
pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
match semver::parse(vers) {
Some(vers) => result::Ok(vers),
None => result::Err(~"could not parse version: invalid")
}
}
// Copyright 2013 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.
// rustpkg utilities having to do with local and remote paths
use core::path::Path;
use core::option::Some;
use core::{hash, str};
use core::rt::io::Writer;
use core::hash::Streaming;
/// Wrappers to prevent local and remote paths from getting confused
/// (These will go away after #6407)
pub struct RemotePath (Path);
pub struct LocalPath (Path);
// normalize should be the only way to construct a LocalPath
// (though this isn't enforced)
/// Replace all occurrences of '-' in the stem part of path with '_'
/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux
/// as the same name
pub fn normalize(p_: RemotePath) -> LocalPath {
let RemotePath(p) = p_;
match p.filestem() {
None => LocalPath(p),
Some(st) => {
let replaced = str::replace(st, "-", "_");
if replaced != st {
LocalPath(p.with_filestem(replaced))
}
else {
LocalPath(p)
}
}
}
}
pub fn write<W: Writer>(writer: &mut W, string: &str) {
let buffer = str::as_bytes_slice(string);
writer.write(buffer);
}
pub fn hash(data: ~str) -> ~str {
let hasher = &mut hash::default_state();
write(hasher, data);
hasher.result_str()
}
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
// rustpkg utilities having to do with paths and directories // rustpkg utilities having to do with paths and directories
use core::prelude::*; use core::prelude::*;
pub use package_path::{RemotePath, LocalPath};
pub use util::{PkgId, RemotePath, LocalPath}; pub use package_id::{PkgId, Version};
pub use util::{normalize, OutputType, Main, Lib, Bench, Test}; pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
use core::os::mkdir_recursive; use core::os::mkdir_recursive;
use core::os; use core::os;
...@@ -32,22 +32,38 @@ pub fn rust_path() -> ~[Path] { ...@@ -32,22 +32,38 @@ pub fn rust_path() -> ~[Path] {
/// succeeded. /// succeeded.
pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) } pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) }
// n.b. So far this only handles local workspaces
// n.b. The next three functions ignore the package version right // n.b. The next three functions ignore the package version right
// now. Should fix that. // now. Should fix that.
/// True if there's a directory in <workspace> with /// True if there's a directory in <workspace> with
/// pkgid's short name /// pkgid's short name
pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool {
let pkgpath = workspace.push("src").push(pkgid.local_path.to_str()); let pkgpath = workspace.push("src").push(pkgid.remote_path.to_str());
os::path_is_dir(&pkgpath) os::path_is_dir(&pkgpath)
} }
/// Return the directory for <pkgid>'s source files in <workspace>. /// Returns a list of possible directories
/// Doesn't check that it exists. /// for <pkgid>'s source files in <workspace>.
pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { /// Doesn't check that any of them exist.
let result = workspace.push("src"); /// (for example, try both with and without the version)
result.push(pkgid.local_path.to_str()) pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> ~[Path] {
let mut results = ~[];
let result = workspace.push("src").push(fmt!("%s-%s",
pkgid.local_path.to_str(), pkgid.version.to_str()));
results.push(result);
results.push(workspace.push("src").push_rel(&*pkgid.remote_path));
results
}
/// Returns a src for pkgid that does exist -- None if none of them do
pub fn first_pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
let rs = pkgid_src_in_workspace(pkgid, workspace);
for rs.each |p| {
if os::path_exists(p) {
return Some(copy *p);
}
}
None
} }
/// Figure out what the executable name for <pkgid> in <workspace>'s build /// Figure out what the executable name for <pkgid> in <workspace>'s build
...@@ -55,7 +71,7 @@ pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { ...@@ -55,7 +71,7 @@ pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
let mut result = workspace.push("build"); let mut result = workspace.push("build");
// should use a target-specific subdirectory // should use a target-specific subdirectory
result = mk_output_path(Main, pkgid, &result); result = mk_output_path(Main, Build, pkgid, &result);
debug!("built_executable_in_workspace: checking whether %s exists", debug!("built_executable_in_workspace: checking whether %s exists",
result.to_str()); result.to_str());
if os::path_exists(&result) { if os::path_exists(&result) {
...@@ -83,7 +99,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> ...@@ -83,7 +99,7 @@ pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path>
fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> { fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> {
let mut result = workspace.push("build"); let mut result = workspace.push("build");
// should use a target-specific subdirectory // should use a target-specific subdirectory
result = mk_output_path(what, pkgid, &result); result = mk_output_path(what, Build, pkgid, &result);
debug!("output_in_workspace: checking whether %s exists", debug!("output_in_workspace: checking whether %s exists",
result.to_str()); result.to_str());
if os::path_exists(&result) { if os::path_exists(&result) {
...@@ -98,17 +114,39 @@ fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Opt ...@@ -98,17 +114,39 @@ fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Opt
/// Figure out what the library name for <pkgid> in <workspace>'s build /// Figure out what the library name for <pkgid> in <workspace>'s build
/// directory is, and if the file exists, return it. /// directory is, and if the file exists, return it.
pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
let result = mk_output_path(Lib, pkgid, &workspace.push("build")); // passing in local_path here sounds fishy
debug!("built_library_in_workspace: checking whether %s exists", library_in_workspace(pkgid.local_path.to_str(), pkgid.short_name, Build,
result.to_str()); workspace, "build")
}
/// Does the actual searching stuff
pub fn installed_library_in_workspace(short_name: &str, workspace: &Path) -> Option<Path> {
library_in_workspace(short_name, short_name, Install, workspace, "lib")
}
/// This doesn't take a PkgId, so we can use it for `extern mod` inference, where we
/// don't know the entire package ID.
/// `full_name` is used to figure out the directory to search.
/// `short_name` is taken as the link name of the library.
fn library_in_workspace(full_name: &str, short_name: &str, where: Target,
workspace: &Path, prefix: &str) -> Option<Path> {
debug!("library_in_workspace: checking whether a library named %s exists",
short_name);
// We don't know what the hash is, so we have to search through the directory // We don't know what the hash is, so we have to search through the directory
// contents // contents
let dir_contents = os::list_dir(&result.pop());
let dir_to_search = match where {
Build => workspace.push(prefix).push(full_name),
Install => workspace.push(prefix)
};
debug!("Listing directory %s", dir_to_search.to_str());
let dir_contents = os::list_dir(&dir_to_search);
debug!("dir has %? entries", dir_contents.len()); debug!("dir has %? entries", dir_contents.len());
let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.short_name); let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, short_name);
let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX); let lib_filetype = os::consts::DLL_SUFFIX;
debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype);
...@@ -116,9 +154,19 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat ...@@ -116,9 +154,19 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
for dir_contents.each |&p| { for dir_contents.each |&p| {
let mut which = 0; let mut which = 0;
let mut hash = None; let mut hash = None;
let p_path = Path(p);
let extension = p_path.filetype();
debug!("p = %s, p's extension is %?", p.to_str(), extension);
match extension {
Some(ref s) if lib_filetype == *s => (),
_ => loop
}
// Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix) // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix)
// and remember what the hash was // and remember what the hash was
for p.each_split_char('-') |piece| { let f_name = match p_path.filename() {
Some(s) => s, None => loop
};
for f_name.each_split_char('-') |piece| {
debug!("a piece = %s", piece); debug!("a piece = %s", piece);
if which == 0 && piece != lib_prefix { if which == 0 && piece != lib_prefix {
break; break;
...@@ -128,13 +176,6 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat ...@@ -128,13 +176,6 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
} }
else if which == 1 { else if which == 1 {
hash = Some(piece.to_owned()); hash = Some(piece.to_owned());
which += 1;
}
else if which == 2 && piece != lib_filetype {
hash = None;
break;
}
else if which == 2 {
break; break;
} }
else { else {
...@@ -144,20 +185,19 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat ...@@ -144,20 +185,19 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
} }
} }
if hash.is_some() { if hash.is_some() {
result_filename = Some(p); result_filename = Some(p_path);
break; break;
} }
} }
// Return the filename that matches, which we now know exists // Return the filename that matches, which we now know exists
// (if result_filename != None) // (if result_filename != None)
debug!("result_filename = %?", result_filename);
match result_filename { match result_filename {
None => None, None => None,
Some(result_filename) => { Some(result_filename) => {
let result_filename = result.with_filename(result_filename); let absolute_path = dir_to_search.push_rel(&result_filename);
debug!("result_filename = %s", result_filename.to_str()); debug!("result_filename = %s", absolute_path.to_str());
Some(result_filename) Some(absolute_path)
} }
} }
} }
...@@ -166,33 +206,36 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat ...@@ -166,33 +206,36 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat
/// in <workspace> /// in <workspace>
/// As a side effect, creates the bin-dir if it doesn't exist /// As a side effect, creates the bin-dir if it doesn't exist
pub fn target_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { pub fn target_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
target_file_in_workspace(pkgid, workspace, Main) target_file_in_workspace(pkgid, workspace, Main, Install)
} }
/// Returns the executable that would be installed for <pkgid> /// Returns the executable that would be installed for <pkgid>
/// in <workspace> /// in <workspace>
/// As a side effect, creates the bin-dir if it doesn't exist /// As a side effect, creates the lib-dir if it doesn't exist
pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
target_file_in_workspace(pkgid, workspace, Lib) target_file_in_workspace(pkgid, workspace, Lib, Install)
} }
/// Returns the test executable that would be installed for <pkgid> /// Returns the test executable that would be installed for <pkgid>
/// in <workspace> /// in <workspace>
/// note that we *don't* install test executables, so this is just for unit testing /// note that we *don't* install test executables, so this is just for unit testing
pub fn target_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { pub fn target_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
target_file_in_workspace(pkgid, workspace, Test) target_file_in_workspace(pkgid, workspace, Test, Install)
} }
/// Returns the bench executable that would be installed for <pkgid> /// Returns the bench executable that would be installed for <pkgid>
/// in <workspace> /// in <workspace>
/// note that we *don't* install bench executables, so this is just for unit testing /// note that we *don't* install bench executables, so this is just for unit testing
pub fn target_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { pub fn target_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
target_file_in_workspace(pkgid, workspace, Bench) target_file_in_workspace(pkgid, workspace, Bench, Install)
} }
/// Returns the path that pkgid `pkgid` would have if placed `where`
/// in `workspace`
fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
what: OutputType) -> Path { what: OutputType, where: Target) -> Path {
use conditions::bad_path::cond; use conditions::bad_path::cond;
let subdir = match what { let subdir = match what {
...@@ -202,7 +245,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, ...@@ -202,7 +245,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) {
cond.raise((copy result, fmt!("I couldn't create the %s dir", subdir))); cond.raise((copy result, fmt!("I couldn't create the %s dir", subdir)));
} }
mk_output_path(what, pkgid, &result) mk_output_path(what, where, pkgid, &result)
} }
/// Return the directory for <pkgid>'s build artifacts in <workspace>. /// Return the directory for <pkgid>'s build artifacts in <workspace>.
...@@ -224,15 +267,21 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { ...@@ -224,15 +267,21 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
/// Return the output file for a given directory name, /// Return the output file for a given directory name,
/// given whether we're building a library and whether we're building tests /// given whether we're building a library and whether we're building tests
pub fn mk_output_path(what: OutputType, pkg_id: &PkgId, workspace: &Path) -> Path { pub fn mk_output_path(what: OutputType, where: Target,
pkg_id: &PkgId, workspace: &Path) -> Path {
let short_name_with_version = pkg_id.short_name_with_version(); let short_name_with_version = pkg_id.short_name_with_version();
// Not local_path.dir_path()! For package foo/bar/blat/, we want // Not local_path.dir_path()! For package foo/bar/blat/, we want
// the executable blat-0.5 to live under blat/ // the executable blat-0.5 to live under blat/
let dir = workspace.push_rel(&*pkg_id.local_path); let dir = match where {
debug!("mk_output_path: short_name = %s, path = %s", // If we're installing, it just goes under <workspace>...
Install => copy *workspace, // bad copy, but I just couldn't make the borrow checker happy
// and if we're just building, it goes in a package-specific subdir
Build => workspace.push_rel(&*pkg_id.local_path)
};
debug!("[%?:%?] mk_output_path: short_name = %s, path = %s", what, where,
if what == Lib { copy short_name_with_version } else { copy pkg_id.short_name }, if what == Lib { copy short_name_with_version } else { copy pkg_id.short_name },
dir.to_str()); dir.to_str());
let output_path = match what { let mut output_path = match what {
// this code is duplicated from elsewhere; fix this // this code is duplicated from elsewhere; fix this
Lib => dir.push(os::dll_filename(short_name_with_version)), Lib => dir.push(os::dll_filename(short_name_with_version)),
// executable names *aren't* versioned // executable names *aren't* versioned
...@@ -244,6 +293,9 @@ pub fn mk_output_path(what: OutputType, pkg_id: &PkgId, workspace: &Path) -> Pat ...@@ -244,6 +293,9 @@ pub fn mk_output_path(what: OutputType, pkg_id: &PkgId, workspace: &Path) -> Pat
} }
os::EXE_SUFFIX)) os::EXE_SUFFIX))
}; };
if !output_path.is_absolute() {
output_path = os::getcwd().push_rel(&output_path).normalize();
}
debug!("mk_output_path: returning %s", output_path.to_str()); debug!("mk_output_path: returning %s", output_path.to_str());
output_path output_path
} }
...@@ -35,15 +35,21 @@ use rustc::metadata::filesearch; ...@@ -35,15 +35,21 @@ use rustc::metadata::filesearch;
use extra::{getopts}; use extra::{getopts};
use syntax::{ast, diagnostic}; use syntax::{ast, diagnostic};
use util::*; use util::*;
use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, u_rwx}; use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, first_pkgid_src_in_workspace};
use path_util::u_rwx;
use path_util::{built_executable_in_workspace, built_library_in_workspace}; use path_util::{built_executable_in_workspace, built_library_in_workspace};
use path_util::{target_executable_in_workspace, target_library_in_workspace}; use path_util::{target_executable_in_workspace, target_library_in_workspace};
use workspace::pkg_parent_workspaces; use workspace::pkg_parent_workspaces;
use context::Ctx; use context::Ctx;
use package_id::PkgId;
mod conditions; mod conditions;
mod context; mod context;
mod package_id;
mod package_path;
mod path_util; mod path_util;
mod search;
mod target;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
mod util; mod util;
...@@ -99,8 +105,7 @@ impl<'self> PkgScript<'self> { ...@@ -99,8 +105,7 @@ impl<'self> PkgScript<'self> {
let input = driver::file_input(script); let input = driver::file_input(script);
let sess = driver::build_session(options, diagnostic::emit); let sess = driver::build_session(options, diagnostic::emit);
let cfg = driver::build_configuration(sess, binary, &input); let cfg = driver::build_configuration(sess, binary, &input);
let (crate, _) = driver::compile_upto(sess, copy cfg, &input, let (crate, _) = driver::compile_upto(sess, copy cfg, &input, driver::cu_parse, None);
driver::cu_parse, None);
let work_dir = build_pkg_id_in_workspace(id, workspace); let work_dir = build_pkg_id_in_workspace(id, workspace);
debug!("Returning package script with id %?", id); debug!("Returning package script with id %?", id);
...@@ -134,11 +139,13 @@ impl<'self> PkgScript<'self> { ...@@ -134,11 +139,13 @@ impl<'self> PkgScript<'self> {
let root = r.pop().pop().pop().pop(); // :-\ let root = r.pop().pop().pop().pop(); // :-\
debug!("Root is %s, calling compile_rest", root.to_str()); debug!("Root is %s, calling compile_rest", root.to_str());
let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
util::compile_crate_from_input(&self.input, self.id, let binary = @copy os::args()[0];
Some(copy self.build_dir), util::compile_crate_from_input(&self.input,
sess, Some(crate), &self.build_dir,
&exe, @copy os::args()[0], sess,
driver::cu_everything); crate,
driver::build_configuration(sess,
binary, &self.input));
debug!("Running program: %s %s %s", exe.to_str(), root.to_str(), what); debug!("Running program: %s %s %s", exe.to_str(), root.to_str(), what);
let status = run::process_status(exe.to_str(), [root.to_str(), what]); let status = run::process_status(exe.to_str(), [root.to_str(), what]);
if status != 0 { if status != 0 {
...@@ -170,9 +177,9 @@ impl<'self> PkgScript<'self> { ...@@ -170,9 +177,9 @@ impl<'self> PkgScript<'self> {
impl Ctx { impl Ctx {
fn run(&self, cmd: ~str, args: ~[~str]) { fn run(&self, cmd: &str, args: ~[~str]) {
match cmd { match cmd {
~"build" => { "build" => {
if args.len() < 1 { if args.len() < 1 {
return usage::build(); return usage::build();
} }
...@@ -183,7 +190,7 @@ impl Ctx { ...@@ -183,7 +190,7 @@ impl Ctx {
self.build(workspace, &pkgid); self.build(workspace, &pkgid);
} }
} }
~"clean" => { "clean" => {
if args.len() < 1 { if args.len() < 1 {
return usage::build(); return usage::build();
} }
...@@ -193,17 +200,17 @@ impl Ctx { ...@@ -193,17 +200,17 @@ impl Ctx {
let cwd = os::getcwd(); let cwd = os::getcwd();
self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd self.clean(&cwd, &pkgid); // tjc: should use workspace, not cwd
} }
~"do" => { "do" => {
if args.len() < 2 { if args.len() < 2 {
return usage::do_cmd(); return usage::do_cmd();
} }
self.do_cmd(copy args[0], copy args[1]); self.do_cmd(copy args[0], copy args[1]);
} }
~"info" => { "info" => {
self.info(); self.info();
} }
~"install" => { "install" => {
if args.len() < 1 { if args.len() < 1 {
return usage::install(); return usage::install();
} }
...@@ -215,24 +222,24 @@ impl Ctx { ...@@ -215,24 +222,24 @@ impl Ctx {
self.install(workspace, &pkgid); self.install(workspace, &pkgid);
} }
} }
~"prefer" => { "prefer" => {
if args.len() < 1 { if args.len() < 1 {
return usage::uninstall(); return usage::uninstall();
} }
self.prefer(args[0], None); self.prefer(args[0], None);
} }
~"test" => { "test" => {
self.test(); self.test();
} }
~"uninstall" => { "uninstall" => {
if args.len() < 1 { if args.len() < 1 {
return usage::uninstall(); return usage::uninstall();
} }
self.uninstall(args[0], None); self.uninstall(args[0], None);
} }
~"unprefer" => { "unprefer" => {
if args.len() < 1 { if args.len() < 1 {
return usage::uninstall(); return usage::uninstall();
} }
...@@ -249,7 +256,7 @@ impl Ctx { ...@@ -249,7 +256,7 @@ impl Ctx {
} }
fn build(&self, workspace: &Path, pkgid: &PkgId) { fn build(&self, workspace: &Path, pkgid: &PkgId) {
let src_dir = pkgid_src_in_workspace(pkgid, workspace); let src_dir = first_pkgid_src_in_workspace(pkgid, workspace);
let build_dir = build_pkg_id_in_workspace(pkgid, workspace); let build_dir = build_pkg_id_in_workspace(pkgid, workspace);
debug!("Destination dir = %s", build_dir.to_str()); debug!("Destination dir = %s", build_dir.to_str());
...@@ -260,8 +267,8 @@ impl Ctx { ...@@ -260,8 +267,8 @@ impl Ctx {
// Is there custom build logic? If so, use it // Is there custom build logic? If so, use it
let pkg_src_dir = src_dir; let pkg_src_dir = src_dir;
let mut custom = false; let mut custom = false;
debug!("Package source directory = %s", pkg_src_dir.to_str()); debug!("Package source directory = %?", pkg_src_dir);
let cfgs = match src.package_script_option(&pkg_src_dir) { let cfgs = match pkg_src_dir.chain_ref(|p| src.package_script_option(p)) {
Some(package_script_path) => { Some(package_script_path) => {
let pscript = PkgScript::parse(package_script_path, let pscript = PkgScript::parse(package_script_path,
workspace, workspace,
...@@ -290,7 +297,7 @@ impl Ctx { ...@@ -290,7 +297,7 @@ impl Ctx {
// Find crates inside the workspace // Find crates inside the workspace
src.find_crates(); src.find_crates();
// Build it! // Build it!
src.build(&build_dir, cfgs, self.sysroot_opt); src.build(self, build_dir, cfgs);
} }
} }
...@@ -352,7 +359,7 @@ impl Ctx { ...@@ -352,7 +359,7 @@ impl Ctx {
} }
fn prefer(&self, _id: &str, _vers: Option<~str>) { fn prefer(&self, _id: &str, _vers: Option<~str>) {
fail!(~"prefer not yet implemented"); fail!("prefer not yet implemented");
} }
fn test(&self) { fn test(&self) {
...@@ -522,21 +529,20 @@ impl PkgSrc { ...@@ -522,21 +529,20 @@ impl PkgSrc {
fn check_dir(&self) -> Path { fn check_dir(&self) -> Path {
use conditions::nonexistent_package::cond; use conditions::nonexistent_package::cond;
debug!("Pushing onto root: %s | %s", self.id.to_str(), debug!("Pushing onto root: %s | %s", self.id.remote_path.to_str(),
self.root.to_str()); self.root.to_str());
let dir;
let mut dir = self.root.push("src"); let dirs = pkgid_src_in_workspace(&self.id, &self.root);
dir = dir.push(self.id.to_str()); // ?? Should this use the version number? debug!("Checking dirs: %?", dirs);
let path = dirs.find(|d| os::path_exists(d));
debug!("Checking dir: %s", dir.to_str()); match path {
Some(d) => dir = d,
if !os::path_exists(&dir) { None => dir = match self.fetch_git() {
if !self.fetch_git() { None => cond.raise((copy self.id, ~"supplied path for package dir does not \
cond.raise((copy self.id, ~"supplied path for package dir does not \ exist, and couldn't interpret it as a URL fragment")),
exist, and couldn't interpret it as a URL fragment")); Some(d) => d
} }
} }
if !os::path_is_dir(&dir) { if !os::path_is_dir(&dir) {
cond.raise((copy self.id, ~"supplied path for package dir is a \ cond.raise((copy self.id, ~"supplied path for package dir is a \
non-directory")); non-directory"));
...@@ -546,10 +552,10 @@ impl PkgSrc { ...@@ -546,10 +552,10 @@ impl PkgSrc {
} }
/// Try interpreting self's package id as a remote package, and try /// Try interpreting self's package id as a remote package, and try
/// fetching it and caching it in a local directory. If that didn't /// fetching it and caching it in a local directory. Return the cached directory
/// work, return false. /// if this was successful, None otherwise
/// (right now we only support git) /// (right now we only support git)
fn fetch_git(&self) -> bool { fn fetch_git(&self) -> Option<Path> {
let mut local = self.root.push("src"); let mut local = self.root.push("src");
local = local.push(self.id.to_str()); local = local.push(self.id.to_str());
...@@ -561,9 +567,11 @@ impl PkgSrc { ...@@ -561,9 +567,11 @@ impl PkgSrc {
if run::process_output("git", [~"clone", copy url, local.to_str()]).status != 0 { if run::process_output("git", [~"clone", copy url, local.to_str()]).status != 0 {
util::note(fmt!("fetching %s failed: can't clone repository", url)); util::note(fmt!("fetching %s failed: can't clone repository", url));
return false; None
}
else {
Some(local)
} }
true
} }
...@@ -655,7 +663,7 @@ impl PkgSrc { ...@@ -655,7 +663,7 @@ impl PkgSrc {
} }
fn build_crates(&self, fn build_crates(&self,
maybe_sysroot: Option<@Path>, ctx: &Ctx,
dst_dir: &Path, dst_dir: &Path,
src_dir: &Path, src_dir: &Path,
crates: &[Crate], crates: &[Crate],
...@@ -666,11 +674,14 @@ impl PkgSrc { ...@@ -666,11 +674,14 @@ impl PkgSrc {
util::note(fmt!("build_crates: compiling %s", path.to_str())); util::note(fmt!("build_crates: compiling %s", path.to_str()));
util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str()));
let result = util::compile_crate(maybe_sysroot, &self.id, path, let result = util::compile_crate(ctx,
dst_dir, &self.id,
crate.flags, path,
crate.cfgs + cfgs, dst_dir,
false, what); crate.flags,
crate.cfgs + cfgs,
false,
what);
if !result { if !result {
build_err::cond.raise(fmt!("build failure on %s", build_err::cond.raise(fmt!("build failure on %s",
path.to_str())); path.to_str()));
...@@ -680,15 +691,15 @@ impl PkgSrc { ...@@ -680,15 +691,15 @@ impl PkgSrc {
} }
} }
fn build(&self, dst_dir: &Path, cfgs: ~[~str], maybe_sysroot: Option<@Path>) { fn build(&self, ctx: &Ctx, dst_dir: Path, cfgs: ~[~str]) {
let dir = self.check_dir(); let dir = self.check_dir();
debug!("Building libs"); debug!("Building libs");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, Lib); self.build_crates(ctx, &dst_dir, &dir, self.libs, cfgs, Lib);
debug!("Building mains"); debug!("Building mains");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, Main); self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main);
debug!("Building tests"); debug!("Building tests");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, Test); self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test);
debug!("Building benches"); debug!("Building benches");
self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, Bench); self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench);
} }
} }
// Copyright 2013 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.
use path_util::installed_library_in_workspace;
use core::prelude::*;
/// If a library with path `p` matching pkg_id's name exists under sroot_opt,
/// return Some(p). Return None if there's no such path or if sroot_opt is None.
pub fn find_library_in_search_path(sroot_opt: Option<@Path>, short_name: &str) -> Option<Path> {
match sroot_opt {
Some(sroot) => {
debug!("Will search for a library with short name %s in \
%s", short_name, (sroot.push("lib")).to_str());
installed_library_in_workspace(short_name, sroot)
}
None => None
}
}
\ No newline at end of file
// Copyright 2013 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.
// Data types that express build artifacts
#[deriving(Eq)]
pub enum OutputType { Main, Lib, Bench, Test }
#[deriving(Eq)]
pub enum Target {
// In-place build
Build,
// Install to bin/ or lib/ dir
Install
}
...@@ -17,10 +17,11 @@ ...@@ -17,10 +17,11 @@
use core::prelude::*; use core::prelude::*;
use core::result; use core::result;
use extra::tempfile::mkdtemp; use extra::tempfile::mkdtemp;
use util::{PkgId, default_version}; use package_path::*;
use package_id::{PkgId, default_version};
use path_util::{target_executable_in_workspace, target_library_in_workspace, use path_util::{target_executable_in_workspace, target_library_in_workspace,
target_test_in_workspace, target_bench_in_workspace, target_test_in_workspace, target_bench_in_workspace,
make_dir_rwx, u_rwx, RemotePath, LocalPath, normalize, make_dir_rwx, u_rwx,
built_bench_in_workspace, built_test_in_workspace}; built_bench_in_workspace, built_test_in_workspace};
fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
...@@ -52,7 +53,7 @@ fn remote_pkg() -> PkgId { ...@@ -52,7 +53,7 @@ fn remote_pkg() -> PkgId {
} }
} }
fn writeFile(file_path: &Path, contents: ~str) { fn writeFile(file_path: &Path, contents: &str) {
let out: @io::Writer = let out: @io::Writer =
result::get(&io::file_writer(file_path, result::get(&io::file_writer(file_path,
[io::Create, io::Truncate])); [io::Create, io::Truncate]));
...@@ -64,15 +65,17 @@ fn mk_temp_workspace(short_name: &LocalPath) -> Path { ...@@ -64,15 +65,17 @@ fn mk_temp_workspace(short_name: &LocalPath) -> Path {
// include version number in directory name // include version number in directory name
let package_dir = workspace.push("src").push(fmt!("%s-0.1", short_name.to_str())); let package_dir = workspace.push("src").push(fmt!("%s-0.1", short_name.to_str()));
assert!(os::mkdir_recursive(&package_dir, u_rwx)); assert!(os::mkdir_recursive(&package_dir, u_rwx));
debug!("Created %s and does it exist? %?", package_dir.to_str(),
os::path_is_dir(&package_dir));
// Create main, lib, test, and bench files // Create main, lib, test, and bench files
writeFile(&package_dir.push("main.rs"), writeFile(&package_dir.push("main.rs"),
~"fn main() { let _x = (); }"); "fn main() { let _x = (); }");
writeFile(&package_dir.push("lib.rs"), writeFile(&package_dir.push("lib.rs"),
~"pub fn f() { let _x = (); }"); "pub fn f() { let _x = (); }");
writeFile(&package_dir.push("test.rs"), writeFile(&package_dir.push("test.rs"),
~"#[test] pub fn f() { (); }"); "#[test] pub fn f() { (); }");
writeFile(&package_dir.push("bench.rs"), writeFile(&package_dir.push("bench.rs"),
~"#[bench] pub fn f() { (); }"); "#[bench] pub fn f() { (); }");
workspace workspace
} }
...@@ -111,6 +114,8 @@ fn test_make_dir_rwx() { ...@@ -111,6 +114,8 @@ fn test_make_dir_rwx() {
#[test] #[test]
fn test_install_valid() { fn test_install_valid() {
use path_util::installed_library_in_workspace;
let sysroot = test_sysroot(); let sysroot = test_sysroot();
debug!("sysroot = %s", sysroot.to_str()); debug!("sysroot = %s", sysroot.to_str());
let ctxt = fake_ctxt(Some(@sysroot)); let ctxt = fake_ctxt(Some(@sysroot));
...@@ -123,10 +128,12 @@ fn test_install_valid() { ...@@ -123,10 +128,12 @@ fn test_install_valid() {
debug!("exec = %s", exec.to_str()); debug!("exec = %s", exec.to_str());
assert!(os::path_exists(&exec)); assert!(os::path_exists(&exec));
assert!(is_rwx(&exec)); assert!(is_rwx(&exec));
let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace);
debug!("lib = %s", lib.to_str()); let lib = installed_library_in_workspace(temp_pkg_id.short_name, &temp_workspace);
assert!(os::path_exists(&lib)); debug!("lib = %?", lib);
assert!(is_rwx(&lib)); assert!(lib.map_default(false, |l| os::path_exists(l)));
assert!(lib.map_default(false, |l| is_rwx(l)));
// And that the test and bench executables aren't installed // And that the test and bench executables aren't installed
assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace))); assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace)));
let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace); let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace);
...@@ -149,6 +156,7 @@ fn test_install_invalid() { ...@@ -149,6 +156,7 @@ fn test_install_invalid() {
}).in { }).in {
do cond.trap(|_| { do cond.trap(|_| {
error_occurred = true; error_occurred = true;
copy temp_workspace
}).in { }).in {
ctxt.install(&temp_workspace, &pkgid); ctxt.install(&temp_workspace, &pkgid);
} }
...@@ -174,10 +182,11 @@ fn test_install_url() { ...@@ -174,10 +182,11 @@ fn test_install_url() {
debug!("lib = %s", lib.to_str()); debug!("lib = %s", lib.to_str());
assert!(os::path_exists(&lib)); assert!(os::path_exists(&lib));
assert!(is_rwx(&lib)); assert!(is_rwx(&lib));
let built_test = built_test_in_workspace(&temp_pkg_id, &workspace).expect("test_install_url"); let built_test = built_test_in_workspace(&temp_pkg_id,
&workspace).expect("test_install_url: built test should exist");
assert!(os::path_exists(&built_test)); assert!(os::path_exists(&built_test));
let built_bench = built_bench_in_workspace(&temp_pkg_id, let built_bench = built_bench_in_workspace(&temp_pkg_id,
&workspace).expect("test_install_url"); &workspace).expect("test_install_url: built bench should exist");
assert!(os::path_exists(&built_bench)); assert!(os::path_exists(&built_bench));
// And that the test and bench executables aren't installed // And that the test and bench executables aren't installed
let test = target_test_in_workspace(&temp_pkg_id, &workspace); let test = target_test_in_workspace(&temp_pkg_id, &workspace);
......
...@@ -13,9 +13,12 @@ ...@@ -13,9 +13,12 @@
with RUST_PATH undefined in the environment with RUST_PATH undefined in the environment
and with `rustpkg install deeply/nested/path/foo` already and with `rustpkg install deeply/nested/path/foo` already
executed: executed:
* ./.rust/external_crate exists and is an executable * ../bin/external_crate exists and is an executable
tjc: Also want a test like this where foo is an external URL,
which requires the `extern mod` changes
*/ */
extern mod foo; // refers to deeply/nested/path/foo extern mod foo;
fn main() {} fn main() {}
// Copyright 2013 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.
fn f() {}
...@@ -9,23 +9,28 @@ ...@@ -9,23 +9,28 @@
// except according to those terms. // except according to those terms.
use core::prelude::*; use core::prelude::*;
use core::*; use core::{io, libc, os, result, str};
use core::cmp::Ord;
use core::hash::Streaming;
use core::rt::io::Writer;
use rustc::driver::{driver, session}; use rustc::driver::{driver, session};
use rustc::metadata::filesearch; use rustc::metadata::filesearch;
use extra::getopts::groups::getopts; use extra::getopts::groups::getopts;
use extra::semver;
use extra::term; use extra::term;
#[cfg(not(test))]
use extra::getopts;
use syntax::ast_util::*; use syntax::ast_util::*;
use syntax::codemap::{dummy_sp, spanned, dummy_spanned}; use syntax::codemap::{dummy_sp, spanned};
use syntax::codemap::dummy_spanned;
use syntax::ext::base::ExtCtxt; use syntax::ext::base::ExtCtxt;
use syntax::{ast, attr, codemap, diagnostic, fold}; use syntax::{ast, attr, codemap, diagnostic, fold};
use syntax::ast::{meta_name_value, meta_list}; use syntax::ast::{meta_name_value, meta_list};
use syntax::attr::{mk_attr}; use syntax::attr::{mk_attr};
use rustc::back::link::output_type_exe; use rustc::back::link::output_type_exe;
use rustc::driver::driver::compile_upto;
use rustc::driver::session::{lib_crate, bin_crate}; use rustc::driver::session::{lib_crate, bin_crate};
use context::Ctx;
use package_id::PkgId;
use path_util::target_library_in_workspace;
use search::find_library_in_search_path;
pub use target::{OutputType, Main, Lib, Bench, Test};
static Commands: &'static [&'static str] = static Commands: &'static [&'static str] =
&["build", "clean", "do", "info", "install", "prefer", "test", "uninstall", &["build", "clean", "do", "info", "install", "prefer", "test", "uninstall",
...@@ -34,119 +39,6 @@ ...@@ -34,119 +39,6 @@
pub type ExitCode = int; // For now pub type ExitCode = int; // For now
/// A version is either an exact revision,
/// or a semantic version
pub enum Version {
ExactRevision(float),
SemVersion(semver::Version)
}
impl Ord for Version {
fn lt(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 < f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 < v2,
_ => false // incomparable, really
}
}
fn le(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 <= f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 <= v2,
_ => false // incomparable, really
}
}
fn ge(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 > f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 > v2,
_ => false // incomparable, really
}
}
fn gt(&self, other: &Version) -> bool {
match (self, other) {
(&ExactRevision(f1), &ExactRevision(f2)) => f1 >= f2,
(&SemVersion(ref v1), &SemVersion(ref v2)) => v1 >= v2,
_ => false // incomparable, really
}
}
}
impl ToStr for Version {
fn to_str(&self) -> ~str {
match *self {
ExactRevision(ref n) => n.to_str(),
SemVersion(ref v) => v.to_str()
}
}
}
#[deriving(Eq)]
pub enum OutputType { Main, Lib, Bench, Test }
/// Placeholder
pub fn default_version() -> Version { ExactRevision(0.1) }
/// Path-fragment identifier of a package such as
/// 'github.com/graydon/test'; path must be a relative
/// path with >=1 component.
pub struct PkgId {
/// Remote path: for example, github.com/mozilla/quux-whatever
remote_path: RemotePath,
/// Local path: for example, /home/quux/github.com/mozilla/quux_whatever
/// Note that '-' normalizes to '_' when mapping a remote path
/// onto a local path
/// Also, this will change when we implement #6407, though we'll still
/// need to keep track of separate local and remote paths
local_path: LocalPath,
/// Short name. This is the local path's filestem, but we store it
/// redundantly so as to not call get() everywhere (filestem() returns an
/// option)
short_name: ~str,
version: Version
}
impl PkgId {
pub fn new(s: &str) -> PkgId {
use conditions::bad_pkg_id::cond;
let p = Path(s);
if p.is_absolute {
return cond.raise((p, ~"absolute pkgid"));
}
if p.components.len() < 1 {
return cond.raise((p, ~"0-length pkgid"));
}
let remote_path = RemotePath(p);
let local_path = normalize(copy remote_path);
let short_name = (copy local_path).filestem().expect(fmt!("Strange path! %s", s));
PkgId {
local_path: local_path,
remote_path: remote_path,
short_name: short_name,
version: default_version()
}
}
pub fn hash(&self) -> ~str {
fmt!("%s-%s-%s", self.remote_path.to_str(),
hash(self.remote_path.to_str() + self.version.to_str()),
self.version.to_str())
}
pub fn short_name_with_version(&self) -> ~str {
fmt!("%s-%s", self.short_name, self.version.to_str())
}
}
impl ToStr for PkgId {
fn to_str(&self) -> ~str {
// should probably use the filestem and not the whole path
fmt!("%s-%s", self.local_path.to_str(), self.version.to_str())
}
}
pub struct Pkg { pub struct Pkg {
id: PkgId, id: PkgId,
bins: ~[~str], bins: ~[~str],
...@@ -264,13 +156,6 @@ pub fn ready_crate(sess: session::Session, ...@@ -264,13 +156,6 @@ pub fn ready_crate(sess: session::Session,
@fold.fold_crate(crate) @fold.fold_crate(crate)
} }
pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
match semver::parse(vers) {
Some(vers) => result::Ok(vers),
None => result::Err(~"could not parse version: invalid")
}
}
pub fn need_dir(s: &Path) { pub fn need_dir(s: &Path) {
if !os::path_is_dir(s) && !os::make_dir(s, 493_i32) { if !os::path_is_dir(s) && !os::make_dir(s, 493_i32) {
fail!("can't create dir: %s", s.to_str()); fail!("can't create dir: %s", s.to_str());
...@@ -316,15 +201,8 @@ pub fn error(msg: ~str) { ...@@ -316,15 +201,8 @@ pub fn error(msg: ~str) {
} }
} }
pub fn hash(data: ~str) -> ~str {
let mut hasher = hash::default_state();
let buffer = str::as_bytes_slice(data);
hasher.write(buffer);
hasher.result_str()
}
// FIXME (#4432): Use workcache to only compile when needed // FIXME (#4432): Use workcache to only compile when needed
pub fn compile_input(sysroot: Option<@Path>, pub fn compile_input(ctxt: &Ctx,
pkg_id: &PkgId, pkg_id: &PkgId,
in_file: &Path, in_file: &Path,
out_dir: &Path, out_dir: &Path,
...@@ -333,6 +211,8 @@ pub fn compile_input(sysroot: Option<@Path>, ...@@ -333,6 +211,8 @@ pub fn compile_input(sysroot: Option<@Path>,
opt: bool, opt: bool,
what: OutputType) -> bool { what: OutputType) -> bool {
let workspace = out_dir.pop().pop();
assert!(in_file.components.len() > 1); assert!(in_file.components.len() > 1);
let input = driver::file_input(copy *in_file); let input = driver::file_input(copy *in_file);
debug!("compile_input: %s / %?", in_file.to_str(), what); debug!("compile_input: %s / %?", in_file.to_str(), what);
...@@ -340,23 +220,10 @@ pub fn compile_input(sysroot: Option<@Path>, ...@@ -340,23 +220,10 @@ pub fn compile_input(sysroot: Option<@Path>,
// not sure if we should support anything else // not sure if we should support anything else
let binary = @(copy os::args()[0]); let binary = @(copy os::args()[0]);
let building_library = what == Lib;
let out_file = if building_library {
out_dir.push(os::dll_filename(pkg_id.short_name))
}
else {
out_dir.push(pkg_id.short_name + match what {
Test => ~"test", Bench => ~"bench", Main | Lib => ~""
} + os::EXE_SUFFIX)
};
debug!("compiling %s into %s",
in_file.to_str(),
out_file.to_str());
debug!("flags: %s", str::connect(flags, " ")); debug!("flags: %s", str::connect(flags, " "));
debug!("cfgs: %s", str::connect(cfgs, " ")); debug!("cfgs: %s", str::connect(cfgs, " "));
debug!("compile_input's sysroot = %?", sysroot); debug!("compile_input's sysroot = %?", ctxt.sysroot_opt);
let crate_type = match what { let crate_type = match what {
Lib => lib_crate, Lib => lib_crate,
...@@ -372,28 +239,62 @@ pub fn compile_input(sysroot: Option<@Path>, ...@@ -372,28 +239,62 @@ pub fn compile_input(sysroot: Option<@Path>,
+ flags + flags
+ cfgs.flat_map(|&c| { ~[~"--cfg", c] }), + cfgs.flat_map(|&c| { ~[~"--cfg", c] }),
driver::optgroups()).get(); driver::optgroups()).get();
let mut options = session::options { let options = @session::options {
crate_type: crate_type, crate_type: crate_type,
optimize: if opt { session::Aggressive } else { session::No }, optimize: if opt { session::Aggressive } else { session::No },
test: what == Test || what == Bench, test: what == Test || what == Bench,
maybe_sysroot: sysroot, maybe_sysroot: ctxt.sysroot_opt,
addl_lib_search_paths: ~[copy *out_dir], addl_lib_search_paths: @mut ~[copy *out_dir],
// output_type should be conditional // output_type should be conditional
output_type: output_type_exe, // Use this to get a library? That's weird output_type: output_type_exe, // Use this to get a library? That's weird
.. copy *driver::build_session_options(binary, &matches, diagnostic::emit) .. copy *driver::build_session_options(binary, &matches, diagnostic::emit)
}; };
for cfgs.each |&cfg| { let addl_lib_search_paths = @mut options.addl_lib_search_paths;
options.cfg.push(attr::mk_word_item(@cfg));
}
let sess = driver::build_session(@options, diagnostic::emit); let sess = driver::build_session(options, diagnostic::emit);
// Infer dependencies that rustpkg needs to build, by scanning for
// `extern mod` directives.
let cfg = driver::build_configuration(sess, binary, &input);
let (crate_opt, _) = driver::compile_upto(sess, copy cfg, &input, driver::cu_expand, None);
let mut crate = match crate_opt {
Some(c) => c,
None => fail!("compile_input expected...")
};
// Not really right. Should search other workspaces too, and the installed
// database (which doesn't exist yet)
find_and_install_dependencies(ctxt, sess, &workspace, crate,
|p| {
debug!("a dependency: %s", p.to_str());
// Pass the directory containing a dependency
// as an additional lib search path
addl_lib_search_paths.push(p);
});
// Inject the link attributes so we get the right package name and version
if attr::find_linkage_metas(crate.node.attrs).is_empty() {
let short_name_to_use = match what {
Test => fmt!("%stest", pkg_id.short_name),
Bench => fmt!("%sbench", pkg_id.short_name),
_ => copy pkg_id.short_name
};
debug!("Injecting link name: %s", short_name_to_use);
crate = @codemap::respan(crate.span, ast::crate_ {
attrs: ~[mk_attr(@dummy_spanned(
meta_list(@~"link",
~[@dummy_spanned(meta_name_value(@~"name",
mk_string_lit(@short_name_to_use))),
@dummy_spanned(meta_name_value(@~"vers",
mk_string_lit(@(copy pkg_id.version.to_str()))))])))],
..copy crate.node});
}
debug!("calling compile_crate_from_input, out_dir = %s, debug!("calling compile_crate_from_input, out_dir = %s,
building_library = %?", out_dir.to_str(), sess.building_library); building_library = %?", out_dir.to_str(), sess.building_library);
let _ = compile_crate_from_input(&input, pkg_id, Some(copy *out_dir), sess, compile_crate_from_input(&input, out_dir, sess, crate, copy cfg);
None, &out_file, binary,
driver::cu_everything);
true true
} }
...@@ -403,52 +304,31 @@ pub fn compile_input(sysroot: Option<@Path>, ...@@ -403,52 +304,31 @@ pub fn compile_input(sysroot: Option<@Path>,
// call compile_upto and return the crate // call compile_upto and return the crate
// also, too many arguments // also, too many arguments
pub fn compile_crate_from_input(input: &driver::input, pub fn compile_crate_from_input(input: &driver::input,
pkg_id: &PkgId, build_dir: &Path,
build_dir_opt: Option<Path>,
sess: session::Session, sess: session::Session,
crate_opt: Option<@ast::crate>, crate: @ast::crate,
out_file: &Path, cfg: ast::crate_cfg) {
binary: @~str, debug!("Calling build_output_filenames with %s, building library? %?",
what: driver::compile_upto) -> @ast::crate { build_dir.to_str(), sess.building_library);
debug!("Calling build_output_filenames with %? and %s", build_dir_opt, out_file.to_str());
let outputs = driver::build_output_filenames(input, &build_dir_opt,
&Some(copy *out_file), sess);
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
let cfg = driver::build_configuration(sess, binary, input);
match crate_opt {
Some(c) => {
debug!("Calling compile_rest, outputs = %?", outputs);
assert_eq!(what, driver::cu_everything);
driver::compile_rest(sess, cfg, driver::cu_everything, Some(outputs), Some(c));
c
}
None => {
debug!("Calling compile_upto, outputs = %?", outputs);
let (crate, _) = driver::compile_upto(sess, copy cfg, input,
driver::cu_parse, Some(outputs));
let mut crate = crate.unwrap();
debug!("About to inject link_meta info...");
// Inject the inferred link_meta info if it's not already there
// (assumes that name and vers are the only linkage metas)
debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len());
if attr::find_linkage_metas(crate.node.attrs).is_empty() {
crate = @codemap::respan(crate.span, ast::crate_ {
attrs: ~[mk_attr(@dummy_spanned(
meta_list(@~"link",
~[@dummy_spanned(meta_name_value(@~"name",
mk_string_lit(@(copy pkg_id.short_name)))),
@dummy_spanned(meta_name_value(@~"vers",
mk_string_lit(@(copy pkg_id.version.to_str()))))])))],
..copy crate.node});
}
driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate)); // bad copy
crate let outputs = driver::build_output_filenames(input, &Some(copy *build_dir), &None,
} crate.node.attrs, sess);
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
debug!("additional libraries:");
for sess.opts.addl_lib_search_paths.each |lib| {
debug!("an additional library: %s", lib.to_str());
} }
driver::compile_rest(sess,
cfg,
compile_upto {
from: driver::cu_expand,
to: driver::cu_everything
},
Some(outputs),
Some(crate));
} }
#[cfg(windows)] #[cfg(windows)]
...@@ -462,7 +342,7 @@ pub fn exe_suffix() -> ~str { ~"" } ...@@ -462,7 +342,7 @@ pub fn exe_suffix() -> ~str { ~"" }
// Called by build_crates // Called by build_crates
// FIXME (#4432): Use workcache to only compile when needed // FIXME (#4432): Use workcache to only compile when needed
pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId, pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId,
crate: &Path, dir: &Path, crate: &Path, dir: &Path,
flags: &[~str], cfgs: &[~str], opt: bool, flags: &[~str], cfgs: &[~str], opt: bool,
what: OutputType) -> bool { what: OutputType) -> bool {
...@@ -471,26 +351,51 @@ pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId, ...@@ -471,26 +351,51 @@ pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId,
for flags.each |&fl| { for flags.each |&fl| {
debug!("+++ %s", fl); debug!("+++ %s", fl);
} }
compile_input(sysroot, pkg_id, crate, dir, flags, cfgs, opt, what) compile_input(ctxt, pkg_id, crate, dir, flags, cfgs, opt, what)
} }
// normalize should be the only way to construct a LocalPath /// Collect all `extern mod` directives in `c`, then
// (though this isn't enforced) /// try to install their targets, failing if any target
/// Replace all occurrences of '-' in the stem part of path with '_' /// can't be found.
/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux fn find_and_install_dependencies(ctxt: &Ctx,
/// as the same name sess: session::Session,
pub fn normalize(p_: RemotePath) -> LocalPath { workspace: &Path,
let RemotePath(p) = p_; c: &ast::crate,
match p.filestem() { save: @fn(Path)
None => LocalPath(p), ) {
Some(st) => { // :-(
let replaced = str::replace(st, "-", "_"); debug!("In find_and_install_dependencies...");
if replaced != st { let my_workspace = copy *workspace;
LocalPath(p.with_filestem(replaced)) let my_ctxt = copy *ctxt;
} for c.each_view_item() |vi: @ast::view_item| {
else { debug!("A view item!");
LocalPath(p) match vi.node {
// ignore metadata, I guess
ast::view_item_extern_mod(lib_ident, _, _) => {
match my_ctxt.sysroot_opt {
Some(ref x) => debug!("sysroot: %s", x.to_str()),
None => ()
};
let lib_name = sess.str_of(lib_ident);
match find_library_in_search_path(my_ctxt.sysroot_opt, *lib_name) {
Some(installed_path) => {
debug!("It exists: %s", installed_path.to_str());
}
None => {
// Try to install it
let pkg_id = PkgId::new(*lib_name);
my_ctxt.install(&my_workspace, &pkg_id);
// Also, add an additional search path
let installed_path = target_library_in_workspace(&pkg_id,
&my_workspace).pop();
debug!("Great, I installed %s, and it's in %s",
*lib_name, installed_path.to_str());
save(installed_path);
}
}
} }
// Ignore `use`s
_ => ()
} }
} }
} }
...@@ -526,10 +431,6 @@ pub fn mk_string_lit(s: @~str) -> ast::lit { ...@@ -526,10 +431,6 @@ pub fn mk_string_lit(s: @~str) -> ast::lit {
} }
} }
/// Wrappers to prevent local and remote paths from getting confused
pub struct RemotePath (Path);
pub struct LocalPath (Path);
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::is_cmd; use super::is_cmd;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
// rustpkg utilities having to do with workspaces // rustpkg utilities having to do with workspaces
use path_util::{rust_path, workspace_contains_package_id}; use path_util::{rust_path, workspace_contains_package_id};
use util::PkgId; use package_id::PkgId;
use core::path::Path; use core::path::Path;
pub fn pkg_parent_workspaces(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool { pub fn pkg_parent_workspaces(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册