use crate::*;
use package_id::*;
use package_source::*;
+use target::*;
use version::Version;
use workcache_support::*;
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
lib: Path) {
let cx = default_context(sysroot);
- let subroot = root.clone();
- let subversion = version.clone();
- let sublib = lib.clone();
- do cx.workcache_context.with_prep(name) |prep| {
- let pkg_src = PkgSrc {
- workspace: subroot.clone(),
- start_dir: subroot.push("src").push(name),
- id: PkgId{ version: subversion.clone(), ..PkgId::new(name)},
- libs: ~[mk_crate(sublib.clone())],
+ let pkg_src = PkgSrc {
+ workspace: root.clone(),
+ start_dir: root.push("src").push(name),
+ id: PkgId{ version: version, ..PkgId::new(name)},
+ // n.b. This assumes the package only has one crate
+ libs: ~[mk_crate(lib)],
mains: ~[],
tests: ~[],
benchs: ~[]
};
- pkg_src.declare_inputs(prep);
- let subcx = cx.clone();
- let subsrc = pkg_src.clone();
- do prep.exec |exec| {
- subsrc.build(exec, &subcx.clone(), ~[]);
- }
- };
+ pkg_src.build(&cx, ~[]);
}
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
main: Path) {
let cx = default_context(sysroot);
- let subroot = root.clone();
- let submain = main.clone();
- do cx.workcache_context.with_prep(name) |prep| {
- let pkg_src = PkgSrc {
- workspace: subroot.clone(),
- start_dir: subroot.push("src").push(name),
- id: PkgId{ version: version.clone(), ..PkgId::new(name)},
- libs: ~[],
- mains: ~[mk_crate(submain.clone())],
- tests: ~[],
- benchs: ~[]
- };
- pkg_src.declare_inputs(prep);
- let subsrc = pkg_src.clone();
- let subcx = cx.clone();
- do prep.exec |exec| {
- subsrc.clone().build(exec, &subcx.clone(), ~[]);
- }
- }
+ let pkg_src = PkgSrc {
+ workspace: root.clone(),
+ start_dir: root.push("src").push(name),
+ id: PkgId{ version: version, ..PkgId::new(name)},
+ libs: ~[],
+ // n.b. This assumes the package only has one crate
+ mains: ~[mk_crate(main)],
+ tests: ~[],
+ benchs: ~[]
+ };
+
+ pkg_src.build(&cx, ~[]);
}
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
let cx = default_context(sysroot);
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
- cx.install(PkgSrc::new(workspace, false, pkgid));
+ cx.install(PkgSrc::new(workspace, false, pkgid), &Everything);
}
fn mk_crate(p: Path) -> Crate {
--- /dev/null
+// 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 static copy_failed_code: int = 65;
}
}
+ // This is the workcache function name for the *installed*
+ // binaries for this package (as opposed to the built ones,
+ // which are per-crate).
+ pub fn install_tag(&self) -> ~str {
+ fmt!("install(%s)", self.to_str())
+ }
}
struct Prefixes {
use util::compile_crate;
use workspace::is_workspace;
use workcache_support;
+use workcache_support::crate_tag;
use extra::workcache;
// An enumeration of the unpacked source of a package workspace.
p.filestem().map_default(false, |p| { p == &self.id.short_name.as_slice() })
}
- fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
+ pub fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
assert!(p.components.len() > prefix);
let mut sub = Path("");
for c in p.components.slice(prefix, p.components.len()).iter() {
fn build_crates(&self,
ctx: &BuildContext,
- exec: &mut workcache::Exec,
destination_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
let path_str = path.to_str();
let cfgs = crate.cfgs + cfgs;
- let result =
- // compile_crate should return the path of the output artifact
- compile_crate(ctx,
- exec,
- &self.id,
- &path,
- destination_dir,
- crate.flags,
- cfgs,
- false,
- what).to_str();
- debug!("Result of compiling %s was %s", path_str, result);
+ do ctx.workcache_context.with_prep(crate_tag(&path)) |prep| {
+ debug!("Building crate %s, declaring it as an input", path.to_str());
+ prep.declare_input("file", path.to_str(),
+ workcache_support::digest_file_with_date(&path));
+ let subpath = path.clone();
+ let subcfgs = cfgs.clone();
+ let subpath_str = path_str.clone();
+ let subcx = ctx.clone();
+ let id = self.id.clone();
+ let sub_dir = destination_dir.clone();
+ let sub_flags = crate.flags.clone();
+ do prep.exec |exec| {
+ let result = compile_crate(&subcx,
+ exec,
+ &id,
+ &subpath,
+ &sub_dir,
+ sub_flags,
+ subcfgs,
+ false,
+ what).to_str();
+ debug!("Result of compiling %s was %s", subpath_str, result);
+ result
+ }
+ };
}
}
/// Declare all the crate files in the package source as inputs
+ /// (to the package)
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
let to_do = ~[self.libs.clone(), self.mains.clone(),
self.tests.clone(), self.benchs.clone()];
+ debug!("In declare inputs, self = %s", self.to_str());
for cs in to_do.iter() {
for c in cs.iter() {
let path = self.start_dir.push_rel(&c.file).normalize();
// It would be better if build returned a Path, but then Path would have to derive
// Encodable.
pub fn build(&self,
- exec: &mut workcache::Exec,
build_context: &BuildContext,
cfgs: ~[~str]) -> ~str {
use conditions::not_a_workspace::cond;
let benchs = self.benchs.clone();
debug!("Building libs in %s, destination = %s",
destination_workspace.to_str(), destination_workspace.to_str());
- self.build_crates(build_context, exec, &destination_workspace, libs, cfgs, Lib);
+ self.build_crates(build_context, &destination_workspace, libs, cfgs, Lib);
debug!("Building mains");
- self.build_crates(build_context, exec, &destination_workspace, mains, cfgs, Main);
+ self.build_crates(build_context, &destination_workspace, mains, cfgs, Main);
debug!("Building tests");
- self.build_crates(build_context, exec, &destination_workspace, tests, cfgs, Test);
+ self.build_crates(build_context, &destination_workspace, tests, cfgs, Test);
debug!("Building benches");
- self.build_crates(build_context, exec, &destination_workspace, benchs, cfgs, Bench);
+ self.build_crates(build_context, &destination_workspace, benchs, cfgs, Bench);
destination_workspace.to_str()
}
+
+ /// Debugging
+ pub fn dump_crates(&self) {
+ let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
+ for crate_set in crate_sets.iter() {
+ for c in crate_set.iter() {
+ debug!("Built crate: %s", c.file.to_str())
+ }
+ }
+ }
}
extern mod rustc;
extern mod syntax;
-use std::{io, os, result, run, str};
+use std::{io, os, result, run, str, task};
pub use std::path::Path;
use extra::workcache;
-use extra::arc::RWArc;
use rustc::driver::{driver, session};
use rustc::metadata::filesearch;
use rustc::metadata::filesearch::rust_path;
LLVMAssemble, LLVMCompileBitcode};
use package_id::PkgId;
use package_source::PkgSrc;
-use workcache_support::{discover_outputs, digest_only_date};
+use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
+// use workcache_support::{discover_outputs, digest_only_date};
+use workcache_support::digest_only_date;
+use exit_codes::copy_failed_code;
pub mod api;
mod conditions;
mod context;
mod crate;
+mod exit_codes;
mod installed_packages;
mod messages;
mod package_id;
pub trait CtxMethods {
fn run(&self, cmd: &str, args: ~[~str]);
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
- fn build_from_src(&self, pkg_src: PkgSrc);
/// Returns the destination workspace
- fn build(&self, exec: &mut workcache::Exec, pkg_src: PkgSrc) -> Path;
+ fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild) -> Path;
fn clean(&self, workspace: &Path, id: &PkgId);
fn info(&self);
/// Returns a pair. First component is a list of installed paths,
/// second is a list of declared and discovered inputs
- fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
+ fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
/// Returns a list of installed files
fn install_no_build(&self,
source_workspace: &Path,
target_workspace: &Path,
- id: &PkgId) -> ~[Path];
+ id: &PkgId) -> ~[~str];
fn prefer(&self, _id: &str, _vers: Option<~str>);
fn test(&self);
fn uninstall(&self, _id: &str, _vers: Option<~str>);
}
impl CtxMethods for BuildContext {
- fn build_from_src(&self, pkg_src: PkgSrc) {
- let tag = pkg_src.id.to_str();
- debug!("package source = %s", pkg_src.to_str());
- do self.workcache_context.with_prep(tag) |prep| {
- let subsrc = pkg_src.clone();
- let subself = self.clone();
- declare_package_script_dependency(prep, &subsrc);
- pkg_src.declare_inputs(prep);
- do prep.exec |exec| {
- subself.build(exec, subsrc.clone());
- }
- }
- }
-
fn run(&self, cmd: &str, args: ~[~str]) {
match cmd {
"build" => {
None if self.context.use_rust_path_hack => {
let cwd = os::getcwd();
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
- self.build_from_src(PkgSrc::new(cwd, true, pkgid));
+ let mut pkg_src = PkgSrc::new(cwd, true, pkgid);
+ self.build(&mut pkg_src, &Everything);
}
None => { usage::build(); return; }
Some((ws, pkgid)) => {
- self.build_from_src(PkgSrc::new(ws, false, pkgid));
+ let mut pkg_src = PkgSrc::new(ws, false, pkgid);
+ self.build(&mut pkg_src, &Everything);
}
}
}
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
debug!("found pkg %s in workspace %s, trying to build",
pkgid.to_str(), workspace.to_str());
- let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
- self.build_from_src(pkg_src);
+ let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
+ self.build(&mut pkg_src, &Everything);
true
};
}
let cwd = os::getcwd();
let inferred_pkgid =
PkgId::new(cwd.components[cwd.components.len() - 1]);
- self.install(PkgSrc::new(cwd, true, inferred_pkgid));
+ self.install(PkgSrc::new(cwd, true, inferred_pkgid), &Everything);
}
None => { usage::install(); return; }
Some((ws, pkgid)) => {
let pkg_src = PkgSrc::new(ws, false, pkgid);
- self.install(pkg_src);
+ self.install(pkg_src, &Everything);
}
}
}
let rp = rust_path();
assert!(!rp.is_empty());
let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
- self.install(src);
+ self.install(src, &Everything);
}
else {
for workspace in workspaces.iter() {
let src = PkgSrc::new(workspace.clone(),
self.context.use_rust_path_hack,
pkgid.clone());
- self.install(src);
+ self.install(src, &Everything);
};
}
}
/// Returns the destination workspace
/// In the case of a custom build, we don't know, so we just return the source workspace
- fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
+ /// what_to_build says: "Just build the lib.rs file in one subdirectory,
+ /// don't walk anything recursively." Or else, everything.
+ fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) -> Path {
let workspace = pkg_src.workspace.clone();
let pkgid = pkg_src.id.clone();
let default_ws = default_workspace();
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
pkgid.to_str());
- return self.build(exec, PkgSrc::new(default_ws, false, pkgid.clone()));
+ return self.build(&mut PkgSrc::new(default_ws, false, pkgid.clone()), what_to_build);
}
// Is there custom build logic? If so, use it
let cfgs = match pkg_src.package_script_option() {
Some(package_script_path) => {
let sysroot = self.sysroot_to_use();
- let (cfgs, hook_result) = {
- let pscript = PkgScript::parse(@sysroot.clone(),
- package_script_path.clone(),
- &workspace.clone(),
- &pkgid);
- pscript.run_custom(exec, &sysroot)
+ let (cfgs, hook_result) =
+ do self.workcache_context.with_prep(package_script_path.to_str()) |prep| {
+ let sub_sysroot = sysroot.clone();
+ let package_script_path_clone = package_script_path.clone();
+ let sub_ws = workspace.clone();
+ let sub_id = pkgid.clone();
+ declare_package_script_dependency(prep, &*pkg_src);
+ do prep.exec |exec| {
+ let pscript = PkgScript::parse(@sub_sysroot.clone(),
+ package_script_path_clone.clone(),
+ &sub_ws,
+ &sub_id);
+
+ pscript.run_custom(exec, &sub_sysroot)
+ }
};
debug!("Command return code = %?", hook_result);
if hook_result != 0 {
// If there was a package script, it should have finished
// the build already. Otherwise...
if !custom {
- // Find crates inside the workspace
- pkg_src.find_crates();
+ match what_to_build {
+ // Find crates inside the workspace
+ &Everything => pkg_src.find_crates(),
+ // Don't infer any crates -- just build the one that was requested
+ &JustOne(ref p) => {
+ // We expect that p is relative to the package source's start directory,
+ // so check that assumption
+ debug!("JustOne: p = %s", p.to_str());
+ assert!(os::path_exists(&pkg_src.start_dir.push_rel(p)));
+ if is_lib(p) {
+ PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
+ } else if is_main(p) {
+ PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
+ } else if is_test(p) {
+ PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
+ } else if is_bench(p) {
+ PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
+ } else {
+ warn(fmt!("Not building any crates for dependency %s", p.to_str()));
+ return workspace.clone();
+ }
+ }
+ }
// Build it!
- let rs_path = pkg_src.build(exec, self, cfgs);
+ let rs_path = pkg_src.build(self, cfgs);
Path(rs_path)
}
else {
fail!("info not yet implemented");
}
- fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
-
- let id = &pkg_src.id;
-
- let installed_files = RWArc::new(~[]);
- let inputs = RWArc::new(~[]);
- // FIXME #7402: Use RUST_PATH to determine target dir
- self.workcache_context.with_prep(id.to_str(), |p| pkg_src.declare_inputs(p));
- do self.workcache_context.with_prep(id.to_str()) |prep| {
- let sub_inputs = inputs.clone();
- let sub_files = installed_files.clone();
- let subsrc = pkg_src.clone();
- let subself = self.clone();
- let id_str = id.to_str();
- let sub_id = id.clone();
- sub_inputs.write(|r| *r = prep.lookup_declared_inputs().map(|v|
- { (~"file", (*v).clone()) }));
- do prep.exec |exec| {
- let destination_workspace = subself.build(exec, subsrc.clone()).to_str();
- // See #7402: This still isn't quite right yet; we want to
- // install to the first workspace in the RUST_PATH if there's
- // a non-default RUST_PATH. This code installs to the same
- // workspace the package was built in.
- let actual_workspace = if path_util::user_set_rust_path() {
- default_workspace()
- }
- else {
- Path(destination_workspace)
- };
- debug!("install: destination workspace = %s, id = %s, installing to %s",
- destination_workspace, id_str, actual_workspace.to_str());
- let result = subself.install_no_build(&Path(destination_workspace),
- &actual_workspace,
- &sub_id);
- debug!("install: id = %s, about to call discover_outputs, %?",
- id_str, result.to_str());
-
- discover_outputs(exec, result.clone());
- sub_files.write(|r| { *r = result.clone(); });
- sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
- note(fmt!("Installed package %s to %s", id_str, actual_workspace.to_str()));
+ fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
+
+ let id = pkg_src.id.clone();
+
+ let mut installed_files = ~[];
+ let inputs = ~[];
+
+ // workcache only knows about *crates*. Building a package
+ // just means inferring all the crates in it, then building each one.
+ let destination_workspace = self.build(&mut pkg_src, what).to_str();
+
+ let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
+ pkg_src.tests.clone(), pkg_src.benchs.clone()];
+ debug!("In declare inputs for %s", id.to_str());
+ for cs in to_do.iter() {
+ for c in cs.iter() {
+ let path = pkg_src.start_dir.push_rel(&c.file).normalize();
+ debug!("Recording input: %s", path.to_str());
+ installed_files.push(path);
}
+ }
+ // See #7402: This still isn't quite right yet; we want to
+ // install to the first workspace in the RUST_PATH if there's
+ // a non-default RUST_PATH. This code installs to the same
+ // workspace the package was built in.
+ let actual_workspace = if path_util::user_set_rust_path() {
+ default_workspace()
+ }
+ else {
+ Path(destination_workspace)
};
- (installed_files.unwrap(), inputs.unwrap())
+ debug!("install: destination workspace = %s, id = %s, installing to %s",
+ destination_workspace, id.to_str(), actual_workspace.to_str());
+ let result = self.install_no_build(&Path(destination_workspace),
+ &actual_workspace,
+ &id).map(|s| Path(*s));
+ debug!("install: id = %s, about to call discover_outputs, %?",
+ id.to_str(), result.to_str());
+ installed_files = installed_files + result;
+ note(fmt!("Installed package %s to %s", id.to_str(), actual_workspace.to_str()));
+ (installed_files, inputs)
}
+ // again, working around lack of Encodable for Path
fn install_no_build(&self,
source_workspace: &Path,
target_workspace: &Path,
- id: &PkgId) -> ~[Path] {
+ id: &PkgId) -> ~[~str] {
use conditions::copy_failed::cond;
// Now copy stuff into the install dirs
let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
debug!("target_exec = %s target_lib = %? \
- maybe_executable = %? maybe_library = %?",
+ maybe_executable = %? maybe_library = %?",
target_exec.to_str(), target_lib,
maybe_executable, maybe_library);
- let mut outputs = ~[];
-
- for exec in maybe_executable.iter() {
- debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
- if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
- os::copy_file(exec, &target_exec)) {
- cond.raise(((*exec).clone(), target_exec.clone()));
+ do self.workcache_context.with_prep(id.install_tag()) |prep| {
+ for ee in maybe_executable.iter() {
+ prep.declare_input("binary",
+ ee.to_str(),
+ workcache_support::digest_only_date(ee));
}
- outputs.push(target_exec.clone());
- }
- for lib in maybe_library.iter() {
- let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
- didn't install it!", lib.to_str()));
- let target_lib = target_lib.pop().push(lib.filename().expect("weird target lib"));
- debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str());
- if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
- os::copy_file(lib, &target_lib)) {
- cond.raise(((*lib).clone(), target_lib.clone()));
+ for ll in maybe_library.iter() {
+ prep.declare_input("binary",
+ ll.to_str(),
+ workcache_support::digest_only_date(ll));
+ }
+ let subex = maybe_executable.clone();
+ let sublib = maybe_library.clone();
+ let sub_target_ex = target_exec.clone();
+ let sub_target_lib = target_lib.clone();
+
+ do prep.exec |exe_thing| {
+ let mut outputs = ~[];
+
+ for exec in subex.iter() {
+ debug!("Copying: %s -> %s", exec.to_str(), sub_target_ex.to_str());
+ if !(os::mkdir_recursive(&sub_target_ex.dir_path(), U_RWX) &&
+ os::copy_file(exec, &sub_target_ex)) {
+ cond.raise(((*exec).clone(), sub_target_ex.clone()));
+ }
+ exe_thing.discover_output("binary",
+ sub_target_ex.to_str(),
+ workcache_support::digest_only_date(&sub_target_ex));
+ outputs.push(sub_target_ex.to_str());
+ }
+ for lib in sublib.iter() {
+ let target_lib = sub_target_lib
+ .clone().expect(fmt!("I built %s but apparently \
+ didn't install it!", lib.to_str()));
+ let target_lib = target_lib
+ .pop().push(lib.filename().expect("weird target lib"));
+ debug!("Copying: %s -> %s", lib.to_str(), sub_target_lib.to_str());
+ if !(os::mkdir_recursive(&target_lib.dir_path(), U_RWX) &&
+ os::copy_file(lib, &target_lib)) {
+ cond.raise(((*lib).clone(), target_lib.clone()));
+ }
+ exe_thing.discover_output("binary",
+ target_lib.to_str(),
+ workcache_support::digest_only_date(&target_lib));
+ outputs.push(target_lib.to_str());
+ }
+ outputs
}
- outputs.push(target_lib.clone());
}
- outputs
}
fn prefer(&self, _id: &str, _vers: Option<~str>) {
debug!("Using sysroot: %s", sroot.to_str());
debug!("Will store workcache in %s", default_workspace().to_str());
- BuildContext {
- context: Context {
- cfgs: cfgs,
- rustc_flags: rustc_flags,
- use_rust_path_hack: use_rust_path_hack,
- sysroot: sroot, // Currently, only tests override this
- },
- workcache_context: api::default_context(default_workspace()).workcache_context
- }.run(*cmd, remaining_args)
+
+ let rm_args = remaining_args.clone();
+ let sub_cmd = cmd.clone();
+ // Wrap the rest in task::try in case of a condition failure in a task
+ let result = do task::try {
+ BuildContext {
+ context: Context {
+ cfgs: cfgs.clone(),
+ rustc_flags: rustc_flags.clone(),
+ use_rust_path_hack: use_rust_path_hack,
+ sysroot: sroot.clone(), // Currently, only tests override this
+ },
+ workcache_context: api::default_context(default_workspace()).workcache_context
+ }.run(sub_cmd, rm_args.clone())
+ };
+ // FIXME #9262: This is using the same error code for all errors,
+ // and at least one test case succeeds if rustpkg returns copy_failed_code,
+ // when actually, it might set the exit code for that even if a different
+ // unhandled condition got raised.
+ if result.is_err() { os::set_exit_status(copy_failed_code); }
+
}
/**
#[deriving(Eq)]
pub enum Target {
- // In-place build
+ /// In-place build
Build,
- // Install to bin/ or lib/ dir
+ /// Install to bin/ or lib/ dir
Install
}
+
+#[deriving(Eq, Clone)]
+pub enum WhatToBuild {
+ /// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
+ JustOne(Path),
+ /// Build everything
+ Everything
+}
+
+pub fn is_lib(p: &Path) -> bool {
+ file_is(p, "lib")
+}
+
+pub fn is_main(p: &Path) -> bool {
+ file_is(p, "main")
+}
+
+pub fn is_test(p: &Path) -> bool {
+ file_is(p, "test")
+}
+
+pub fn is_bench(p: &Path) -> bool {
+ file_is(p, "bench")
+}
+
+fn file_is(p: &Path, stem: &str) -> bool {
+ match p.filestem() {
+ Some(s) if s == stem => true,
+ _ => false
+ }
+}
+
+pub fn lib_name_of(p: &Path) -> Path {
+ p.push("lib.rs")
+}
+
+pub static lib_crate_filename: &'static str = "lib.rs";
use syntax::diagnostic;
use target::*;
use package_source::PkgSrc;
-
-/// Returns the last-modified date as an Option
-fn datestamp(p: &Path) -> Option<libc::time_t> {
- p.stat().map(|stat| stat.st_mtime)
-}
+use util::datestamp;
fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
let context = workcache::Context::new(
}
fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
- command_line_test_with_env(args, cwd, None).expect("Command line test failed")
+ match command_line_test_with_env(args, cwd, None) {
+ Success(r) => r,
+ _ => fail!("Command line test failed")
+ }
}
-fn command_line_test_partial(args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
+fn command_line_test_partial(args: &[~str], cwd: &Path) -> ProcessResult {
command_line_test_with_env(args, cwd, None)
}
+enum ProcessResult {
+ Success(ProcessOutput),
+ Fail(int) // exit code
+}
+
/// Runs `rustpkg` (based on the directory that this executable was
/// invoked from) with the given arguments, in the given working directory.
/// Returns the process's output.
fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
- -> Option<ProcessOutput> {
+ -> ProcessResult {
let cmd = rustpkg_exec().to_str();
let env_str = match env {
Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
cmd, args, output.status,
str::from_utf8(output.output) + str::from_utf8(output.error));
- None
+ Fail(output.status)
}
else {
- Some(output)
+ Success(output)
}
}
fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
let mut result = ~[];
- let p_output = command_line_test_with_env(args,
- &os::getcwd(), Some(env)).expect("Command-line test failed");
+ let p_output = match command_line_test_with_env(args,
+ &os::getcwd(), Some(env)) {
+ Fail(_) => fail!("Command-line test failed"),
+ Success(r) => r
+ };
let test_output = str::from_utf8(p_output.output);
for s in test_output.split_iter('\n') {
result.push(s.to_owned());
}
// assumes short_name and path are one and the same -- I should fix
-fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Path {
- debug!("lib_output_file_name: given %s and parent %s and short name %s",
- workspace.to_str(), parent, short_name);
+fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
+ debug!("lib_output_file_name: given %s and short name %s",
+ workspace.to_str(), short_name);
library_in_workspace(&Path(short_name),
short_name,
Build,
}
/// Add a comment at the end
-fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
+fn frob_source_file(workspace: &Path, pkgid: &PkgId, filename: &str) {
use conditions::bad_path::cond;
let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
- let contents = os::list_dir_path(&pkg_src_dir);
let mut maybe_p = None;
- for p in contents.iter() {
- if p.filetype() == Some(".rs") {
- maybe_p = Some(p);
- break;
- }
+ let maybe_file = pkg_src_dir.push(filename);
+ debug!("Trying to frob %s -- %s", pkg_src_dir.to_str(), filename);
+ if os::path_exists(&maybe_file) {
+ maybe_p = Some(maybe_file);
}
+ debug!("Frobbed? %?", maybe_p);
match maybe_p {
- Some(p) => {
+ Some(ref p) => {
let w = io::file_writer(p, &[io::Append]);
match w {
Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
debug!("temp_workspace = %s", temp_workspace.to_str());
// should have test, bench, lib, and main
let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
- ctxt.install(src);
+ ctxt.install(src, &Everything);
// Check that all files exist
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
debug!("exec = %s", exec.to_str());
// Uses task::try because of #9001
let result = do task::try {
let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
- ctxt.install(pkg_src);
+ ctxt.install(pkg_src, &Everything);
};
// Not the best test -- doesn't test that we failed in the right way.
// Best we can do for now.
}
#[test]
-#[ignore]
fn no_rebuilding_dep() {
let p_id = PkgId::new("foo");
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
- ".rust",
- "bar"));
- let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
+ let bar_lib = lib_output_file_name(&workspace, "bar");
+ let bar_date_1 = datestamp(&bar_lib);
+
+ frob_source_file(&workspace, &p_id, "main.rs");
+
+ // Now make `bar` read-only so that subsequent rebuilds of it will fail
+ assert!(chmod_read_only(&bar_lib));
+
+ match command_line_test_partial([~"build", ~"foo"], &workspace) {
+ Success(*) => (), // ok
+ Fail(status) if status == 65 => fail!("no_rebuilding_dep failed: it tried to rebuild bar"),
+ Fail(_) => fail!("no_rebuilding_dep failed for some other reason")
+ }
- frob_source_file(&workspace, &p_id);
- command_line_test([~"build", ~"foo"], &workspace);
let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
- ".rust",
- "bar"));
- let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
+ "bar"));
assert_eq!(bar_date_1, bar_date_2);
- assert!(foo_date_1 < foo_date_2);
- assert!(foo_date_1 > bar_date_1);
}
#[test]
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_lib_name = lib_output_file_name(&workspace, "build", "bar");
+ let bar_lib_name = lib_output_file_name(&workspace, "bar");
let bar_date = datestamp(&bar_lib_name);
debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
touch_source_file(&workspace, &dep_id);
let dep_id = PkgId::new("bar");
let workspace = create_local_package_with_dep(&p_id, &dep_id);
command_line_test([~"build", ~"foo"], &workspace);
- let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
- frob_source_file(&workspace, &dep_id);
+ let bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
+ frob_source_file(&workspace, &dep_id, "lib.rs");
// should adjust the datestamp
command_line_test([~"build", ~"foo"], &workspace);
- let new_bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
+ let new_bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
assert!(new_bar_date > bar_date);
}
}
#[test]
-#[ignore (reason = "#7402 not yet implemented")]
fn rust_path_install_target() {
let dir_for_path = mkdtemp(&os::tmpdir(),
"source_workspace").expect("rust_path_install_target failed");
let workspace = create_local_package(&p_id);
writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
"#[cfg(quux)] fn main() {}");
- assert!(command_line_test_partial([test_sysroot().to_str(),
+ match command_line_test_partial([test_sysroot().to_str(),
~"build",
~"foo"],
- &workspace).is_none());
+ &workspace) {
+ Success(*) => fail!("test_cfg_fail failed"),
+ _ => ()
+ }
}
assert_executable_exists(&workspace, "foo");
}
+#[test]
+fn test_dependencies_terminate() {
+ // let a_id = PkgId::new("a");
+ let b_id = PkgId::new("b");
+// let workspace = create_local_package_with_dep(&b_id, &a_id);
+ let workspace = create_local_package(&b_id);
+ let b_dir = workspace.push_many([~"src", ~"b-0.1"]);
+ // writeFile(&b_dir.push("lib.rs"), "extern mod a; pub fn f() {}");
+ let b_subdir = b_dir.push("test");
+ assert!(os::mkdir_recursive(&b_subdir, U_RWX));
+ writeFile(&b_subdir.push("test.rs"),
+ "extern mod b; use b::f; #[test] fn g() { f() }");
+ command_line_test([~"install", ~"b"], &workspace);
+}
+
/// Returns true if p exists and is executable
fn is_executable(p: &Path) -> bool {
use std::libc::consts::os::posix88::{S_IXUSR};
Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
}
}
+
+#[cfg(target_os = "win32")]
+fn chmod_read_only(p: &Path) -> bool {
+ #[fixed_stack_segment];
+ unsafe {
+ do p.to_str().with_c_str |src_buf| {
+ libc::chmod(src_buf, libc::consts::os::posix88::S_IRUSR as c_int) == 0 as libc::c_int
+ }
+ }
+}
+
+#[cfg(not(target_os = "win32"))]
+fn chmod_read_only(p: &Path) -> bool {
+ #[fixed_stack_segment];
+ unsafe {
+ do p.to_str().with_c_str |src_buf| {
+ libc::chmod(src_buf,
+ libc::consts::os::posix88::S_IRUSR as libc::mode_t) == 0
+ as libc::c_int
+ }
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::libc;
use std::os;
use extra::workcache;
use rustc::driver::{driver, session};
use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
use messages::error;
-pub use target::{OutputType, Main, Lib, Bench, Test};
+pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
use workcache_support::{digest_file_with_date, digest_only_date};
// It would be nice to have the list of commands in just one place -- for example,
// not sure if we should support anything else
let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
+ // Make the output directory if it doesn't exist already
+ assert!(os::mkdir_recursive(&out_dir, U_RWX));
let binary = os::args()[0].to_managed();
optimize: if opt { session::Aggressive } else { session::No },
test: what == Test || what == Bench,
maybe_sysroot: Some(sysroot_to_use),
- addl_lib_search_paths: @mut (~[out_dir.clone()]),
+ addl_lib_search_paths: @mut (~[]),
output_type: output_type,
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
};
// Register dependency on the source file
exec.discover_input("file", input.to_str(), digest_file_with_date(input));
+ debug!("Built %s, date = %?", outputs.out_filename.to_str(),
+ datestamp(&outputs.out_filename));
+
Some(outputs.out_filename)
}
workspaces[0]
};
let (outputs_disc, inputs_disc) =
- context.install(PkgSrc::new(dep_workspace.clone(), false, pkg_id));
+ context.install(PkgSrc::new(dep_workspace.clone(),
+ false, pkg_id), &JustOne(Path(lib_crate_filename)));
debug!("Installed %s, returned %? dependencies and \
%? transitive dependencies",
lib_name, outputs_disc.len(), inputs_disc.len());
debug!("Adding additional search path: %s", lib_name);
let installed_library =
installed_library_in_workspace(&Path(lib_name), &dep_workspace)
- .expect( fmt!("rustpkg failed to install dependency %s",
+ .expect(fmt!("rustpkg failed to install dependency %s",
lib_name));
let install_dir = installed_library.pop();
- debug!("Installed %s into %s", lib_name, install_dir.to_str());
+ debug!("Installed %s into %s [%?]", lib_name, install_dir.to_str(),
+ datestamp(&installed_library));
save(install_dir);
}
}}
};
}
-#[cfg(windows)]
-pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- /* FIXME (#1768): Investigate how to do this on win32
- Node wraps symlinks by having a .bat,
- but that won't work with minGW. */
-
- false
-}
-
-#[cfg(target_os = "linux")]
-#[cfg(target_os = "android")]
-#[cfg(target_os = "freebsd")]
-#[cfg(target_os = "macos")]
-pub fn link_exe(src: &Path, dest: &Path) -> bool {
- #[fixed_stack_segment]; #[inline(never)];
-
- use std::c_str::ToCStr;
- use std::libc;
-
- unsafe {
- do src.with_c_str |src_buf| {
- do dest.with_c_str |dest_buf| {
- libc::link(src_buf, dest_buf) == 0 as libc::c_int &&
- libc::chmod(dest_buf, 755) == 0 as libc::c_int
- }
- }
- }
-}
-
pub fn mk_string_lit(s: @str) -> ast::lit {
Spanned {
node: ast::lit_str(s),
// tjc: cheesy
fn debug_flags() -> ~[~str] { ~[] }
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
+
+
+/// Returns the last-modified date as an Option
+pub fn datestamp(p: &Path) -> Option<libc::time_t> {
+ debug!("Scrutinizing datestamp for %s - does it exist? %?", p.to_str(), os::path_exists(p));
+ let out = p.stat().map(|stat| stat.st_mtime);
+ debug!("Date = %?", out);
+ out.map(|t| { *t as libc::time_t })
+}
e.discover_output("binary", p.to_str(), digest_only_date(p));
}
}
+
+/// Returns the function name for building a crate
+pub fn crate_tag(p: &Path) -> ~str {
+ p.to_str() // implicitly, it's "build(p)"...
+}