auto merge of #9263 : catamorphism/rust/rustpkg-issue-7879, r=brson
r? @brson Treating a package as the thing that can have other packages depend on it, and depends on other packages, was wrong if a package has more than one crate. Now, rustpkg knows about dependencies between crates in the same package. This solves the problem reported in #7879 where rustpkg wrongly discovered a circular dependency between thhe package and itself, and recursed infinitely. Closes #7879
This commit is contained in:
commit
36cc41481c
|
@ -12,6 +12,7 @@ use context::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use package_id::*;
|
use package_id::*;
|
||||||
use package_source::*;
|
use package_source::*;
|
||||||
|
use target::*;
|
||||||
use version::Version;
|
use version::Version;
|
||||||
use workcache_support::*;
|
use workcache_support::*;
|
||||||
|
|
||||||
|
@ -63,56 +64,40 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
|
||||||
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
lib: Path) {
|
lib: Path) {
|
||||||
let cx = default_context(sysroot);
|
let cx = default_context(sysroot);
|
||||||
let subroot = root.clone();
|
let pkg_src = PkgSrc {
|
||||||
let subversion = version.clone();
|
workspace: root.clone(),
|
||||||
let sublib = lib.clone();
|
start_dir: root.push("src").push(name),
|
||||||
do cx.workcache_context.with_prep(name) |prep| {
|
id: PkgId{ version: version, ..PkgId::new(name)},
|
||||||
let pkg_src = PkgSrc {
|
// n.b. This assumes the package only has one crate
|
||||||
workspace: subroot.clone(),
|
libs: ~[mk_crate(lib)],
|
||||||
start_dir: subroot.push("src").push(name),
|
|
||||||
id: PkgId{ version: subversion.clone(), ..PkgId::new(name)},
|
|
||||||
libs: ~[mk_crate(sublib.clone())],
|
|
||||||
mains: ~[],
|
mains: ~[],
|
||||||
tests: ~[],
|
tests: ~[],
|
||||||
benchs: ~[]
|
benchs: ~[]
|
||||||
};
|
};
|
||||||
pkg_src.declare_inputs(prep);
|
pkg_src.build(&cx, ~[]);
|
||||||
let subcx = cx.clone();
|
|
||||||
let subsrc = pkg_src.clone();
|
|
||||||
do prep.exec |exec| {
|
|
||||||
subsrc.build(exec, &subcx.clone(), ~[]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
main: Path) {
|
main: Path) {
|
||||||
let cx = default_context(sysroot);
|
let cx = default_context(sysroot);
|
||||||
let subroot = root.clone();
|
let pkg_src = PkgSrc {
|
||||||
let submain = main.clone();
|
workspace: root.clone(),
|
||||||
do cx.workcache_context.with_prep(name) |prep| {
|
start_dir: root.push("src").push(name),
|
||||||
let pkg_src = PkgSrc {
|
id: PkgId{ version: version, ..PkgId::new(name)},
|
||||||
workspace: subroot.clone(),
|
libs: ~[],
|
||||||
start_dir: subroot.push("src").push(name),
|
// n.b. This assumes the package only has one crate
|
||||||
id: PkgId{ version: version.clone(), ..PkgId::new(name)},
|
mains: ~[mk_crate(main)],
|
||||||
libs: ~[],
|
tests: ~[],
|
||||||
mains: ~[mk_crate(submain.clone())],
|
benchs: ~[]
|
||||||
tests: ~[],
|
};
|
||||||
benchs: ~[]
|
|
||||||
};
|
pkg_src.build(&cx, ~[]);
|
||||||
pkg_src.declare_inputs(prep);
|
|
||||||
let subsrc = pkg_src.clone();
|
|
||||||
let subcx = cx.clone();
|
|
||||||
do prep.exec |exec| {
|
|
||||||
subsrc.clone().build(exec, &subcx.clone(), ~[]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
|
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
|
||||||
let cx = default_context(sysroot);
|
let cx = default_context(sysroot);
|
||||||
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
|
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 {
|
fn mk_crate(p: Path) -> Crate {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
// 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;
|
|
@ -108,6 +108,12 @@ impl PkgId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
struct Prefixes {
|
||||||
|
|
|
@ -22,6 +22,7 @@ use path_util::{find_dir_using_rust_path_hack, default_workspace, make_dir_rwx_r
|
||||||
use util::compile_crate;
|
use util::compile_crate;
|
||||||
use workspace::is_workspace;
|
use workspace::is_workspace;
|
||||||
use workcache_support;
|
use workcache_support;
|
||||||
|
use workcache_support::crate_tag;
|
||||||
use extra::workcache;
|
use extra::workcache;
|
||||||
|
|
||||||
// An enumeration of the unpacked source of a package workspace.
|
// An enumeration of the unpacked source of a package workspace.
|
||||||
|
@ -231,7 +232,7 @@ impl PkgSrc {
|
||||||
p.filestem().map_default(false, |p| { p == &self.id.short_name.as_slice() })
|
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);
|
assert!(p.components.len() > prefix);
|
||||||
let mut sub = Path("");
|
let mut sub = Path("");
|
||||||
for c in p.components.slice(prefix, p.components.len()).iter() {
|
for c in p.components.slice(prefix, p.components.len()).iter() {
|
||||||
|
@ -286,7 +287,6 @@ impl PkgSrc {
|
||||||
|
|
||||||
fn build_crates(&self,
|
fn build_crates(&self,
|
||||||
ctx: &BuildContext,
|
ctx: &BuildContext,
|
||||||
exec: &mut workcache::Exec,
|
|
||||||
destination_dir: &Path,
|
destination_dir: &Path,
|
||||||
crates: &[Crate],
|
crates: &[Crate],
|
||||||
cfgs: &[~str],
|
cfgs: &[~str],
|
||||||
|
@ -297,25 +297,40 @@ impl PkgSrc {
|
||||||
let path_str = path.to_str();
|
let path_str = path.to_str();
|
||||||
let cfgs = crate.cfgs + cfgs;
|
let cfgs = crate.cfgs + cfgs;
|
||||||
|
|
||||||
let result =
|
do ctx.workcache_context.with_prep(crate_tag(&path)) |prep| {
|
||||||
// compile_crate should return the path of the output artifact
|
debug!("Building crate %s, declaring it as an input", path.to_str());
|
||||||
compile_crate(ctx,
|
prep.declare_input("file", path.to_str(),
|
||||||
exec,
|
workcache_support::digest_file_with_date(&path));
|
||||||
&self.id,
|
let subpath = path.clone();
|
||||||
&path,
|
let subcfgs = cfgs.clone();
|
||||||
destination_dir,
|
let subpath_str = path_str.clone();
|
||||||
crate.flags,
|
let subcx = ctx.clone();
|
||||||
cfgs,
|
let id = self.id.clone();
|
||||||
false,
|
let sub_dir = destination_dir.clone();
|
||||||
what).to_str();
|
let sub_flags = crate.flags.clone();
|
||||||
debug!("Result of compiling %s was %s", path_str, result);
|
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
|
/// Declare all the crate files in the package source as inputs
|
||||||
|
/// (to the package)
|
||||||
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
|
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
|
||||||
let to_do = ~[self.libs.clone(), self.mains.clone(),
|
let to_do = ~[self.libs.clone(), self.mains.clone(),
|
||||||
self.tests.clone(), self.benchs.clone()];
|
self.tests.clone(), self.benchs.clone()];
|
||||||
|
debug!("In declare inputs, self = %s", self.to_str());
|
||||||
for cs in to_do.iter() {
|
for cs in to_do.iter() {
|
||||||
for c in cs.iter() {
|
for c in cs.iter() {
|
||||||
let path = self.start_dir.push_rel(&c.file).normalize();
|
let path = self.start_dir.push_rel(&c.file).normalize();
|
||||||
|
@ -330,7 +345,6 @@ impl PkgSrc {
|
||||||
// It would be better if build returned a Path, but then Path would have to derive
|
// It would be better if build returned a Path, but then Path would have to derive
|
||||||
// Encodable.
|
// Encodable.
|
||||||
pub fn build(&self,
|
pub fn build(&self,
|
||||||
exec: &mut workcache::Exec,
|
|
||||||
build_context: &BuildContext,
|
build_context: &BuildContext,
|
||||||
cfgs: ~[~str]) -> ~str {
|
cfgs: ~[~str]) -> ~str {
|
||||||
use conditions::not_a_workspace::cond;
|
use conditions::not_a_workspace::cond;
|
||||||
|
@ -360,13 +374,23 @@ impl PkgSrc {
|
||||||
let benchs = self.benchs.clone();
|
let benchs = self.benchs.clone();
|
||||||
debug!("Building libs in %s, destination = %s",
|
debug!("Building libs in %s, destination = %s",
|
||||||
destination_workspace.to_str(), destination_workspace.to_str());
|
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");
|
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");
|
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");
|
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()
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,10 @@ extern mod extra;
|
||||||
extern mod rustc;
|
extern mod rustc;
|
||||||
extern mod syntax;
|
extern mod syntax;
|
||||||
|
|
||||||
use std::{io, os, result, run, str};
|
use std::{io, os, result, run, str, task};
|
||||||
pub use std::path::Path;
|
pub use std::path::Path;
|
||||||
|
|
||||||
use extra::workcache;
|
use extra::workcache;
|
||||||
use extra::arc::RWArc;
|
|
||||||
use rustc::driver::{driver, session};
|
use rustc::driver::{driver, session};
|
||||||
use rustc::metadata::filesearch;
|
use rustc::metadata::filesearch;
|
||||||
use rustc::metadata::filesearch::rust_path;
|
use rustc::metadata::filesearch::rust_path;
|
||||||
|
@ -45,12 +44,16 @@ use context::{Context, BuildContext,
|
||||||
LLVMAssemble, LLVMCompileBitcode};
|
LLVMAssemble, LLVMCompileBitcode};
|
||||||
use package_id::PkgId;
|
use package_id::PkgId;
|
||||||
use package_source::PkgSrc;
|
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;
|
pub mod api;
|
||||||
mod conditions;
|
mod conditions;
|
||||||
mod context;
|
mod context;
|
||||||
mod crate;
|
mod crate;
|
||||||
|
mod exit_codes;
|
||||||
mod installed_packages;
|
mod installed_packages;
|
||||||
mod messages;
|
mod messages;
|
||||||
mod package_id;
|
mod package_id;
|
||||||
|
@ -172,19 +175,18 @@ impl<'self> PkgScript<'self> {
|
||||||
pub trait CtxMethods {
|
pub trait CtxMethods {
|
||||||
fn run(&self, cmd: &str, args: ~[~str]);
|
fn run(&self, cmd: &str, args: ~[~str]);
|
||||||
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
|
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
|
||||||
fn build_from_src(&self, pkg_src: PkgSrc);
|
|
||||||
/// Returns the destination workspace
|
/// 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 clean(&self, workspace: &Path, id: &PkgId);
|
||||||
fn info(&self);
|
fn info(&self);
|
||||||
/// Returns a pair. First component is a list of installed paths,
|
/// Returns a pair. First component is a list of installed paths,
|
||||||
/// second is a list of declared and discovered inputs
|
/// 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
|
/// Returns a list of installed files
|
||||||
fn install_no_build(&self,
|
fn install_no_build(&self,
|
||||||
source_workspace: &Path,
|
source_workspace: &Path,
|
||||||
target_workspace: &Path,
|
target_workspace: &Path,
|
||||||
id: &PkgId) -> ~[Path];
|
id: &PkgId) -> ~[~str];
|
||||||
fn prefer(&self, _id: &str, _vers: Option<~str>);
|
fn prefer(&self, _id: &str, _vers: Option<~str>);
|
||||||
fn test(&self);
|
fn test(&self);
|
||||||
fn uninstall(&self, _id: &str, _vers: Option<~str>);
|
fn uninstall(&self, _id: &str, _vers: Option<~str>);
|
||||||
|
@ -193,20 +195,6 @@ pub trait CtxMethods {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtxMethods for BuildContext {
|
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]) {
|
fn run(&self, cmd: &str, args: ~[~str]) {
|
||||||
match cmd {
|
match cmd {
|
||||||
"build" => {
|
"build" => {
|
||||||
|
@ -215,11 +203,13 @@ impl CtxMethods for BuildContext {
|
||||||
None if self.context.use_rust_path_hack => {
|
None if self.context.use_rust_path_hack => {
|
||||||
let cwd = os::getcwd();
|
let cwd = os::getcwd();
|
||||||
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
|
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; }
|
None => { usage::build(); return; }
|
||||||
Some((ws, pkgid)) => {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,8 +220,8 @@ impl CtxMethods for BuildContext {
|
||||||
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
|
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
|
||||||
debug!("found pkg %s in workspace %s, trying to build",
|
debug!("found pkg %s in workspace %s, trying to build",
|
||||||
pkgid.to_str(), workspace.to_str());
|
pkgid.to_str(), workspace.to_str());
|
||||||
let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
|
let mut pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
|
||||||
self.build_from_src(pkg_src);
|
self.build(&mut pkg_src, &Everything);
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -271,12 +261,12 @@ impl CtxMethods for BuildContext {
|
||||||
let cwd = os::getcwd();
|
let cwd = os::getcwd();
|
||||||
let inferred_pkgid =
|
let inferred_pkgid =
|
||||||
PkgId::new(cwd.components[cwd.components.len() - 1]);
|
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; }
|
None => { usage::install(); return; }
|
||||||
Some((ws, pkgid)) => {
|
Some((ws, pkgid)) => {
|
||||||
let pkg_src = PkgSrc::new(ws, false, pkgid);
|
let pkg_src = PkgSrc::new(ws, false, pkgid);
|
||||||
self.install(pkg_src);
|
self.install(pkg_src, &Everything);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -291,14 +281,14 @@ impl CtxMethods for BuildContext {
|
||||||
let rp = rust_path();
|
let rp = rust_path();
|
||||||
assert!(!rp.is_empty());
|
assert!(!rp.is_empty());
|
||||||
let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
|
let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
|
||||||
self.install(src);
|
self.install(src, &Everything);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for workspace in workspaces.iter() {
|
for workspace in workspaces.iter() {
|
||||||
let src = PkgSrc::new(workspace.clone(),
|
let src = PkgSrc::new(workspace.clone(),
|
||||||
self.context.use_rust_path_hack,
|
self.context.use_rust_path_hack,
|
||||||
pkgid.clone());
|
pkgid.clone());
|
||||||
self.install(src);
|
self.install(src, &Everything);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -366,7 +356,9 @@ impl CtxMethods for BuildContext {
|
||||||
|
|
||||||
/// Returns the destination workspace
|
/// Returns the destination workspace
|
||||||
/// In the case of a custom build, we don't know, so we just return the source 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 workspace = pkg_src.workspace.clone();
|
||||||
let pkgid = pkg_src.id.clone();
|
let pkgid = pkg_src.id.clone();
|
||||||
|
|
||||||
|
@ -384,7 +376,7 @@ impl CtxMethods for BuildContext {
|
||||||
let default_ws = default_workspace();
|
let default_ws = default_workspace();
|
||||||
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
|
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
|
||||||
pkgid.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
|
// Is there custom build logic? If so, use it
|
||||||
|
@ -395,12 +387,21 @@ impl CtxMethods for BuildContext {
|
||||||
let cfgs = match pkg_src.package_script_option() {
|
let cfgs = match pkg_src.package_script_option() {
|
||||||
Some(package_script_path) => {
|
Some(package_script_path) => {
|
||||||
let sysroot = self.sysroot_to_use();
|
let sysroot = self.sysroot_to_use();
|
||||||
let (cfgs, hook_result) = {
|
let (cfgs, hook_result) =
|
||||||
let pscript = PkgScript::parse(@sysroot.clone(),
|
do self.workcache_context.with_prep(package_script_path.to_str()) |prep| {
|
||||||
package_script_path.clone(),
|
let sub_sysroot = sysroot.clone();
|
||||||
&workspace.clone(),
|
let package_script_path_clone = package_script_path.clone();
|
||||||
&pkgid);
|
let sub_ws = workspace.clone();
|
||||||
pscript.run_custom(exec, &sysroot)
|
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);
|
debug!("Command return code = %?", hook_result);
|
||||||
if hook_result != 0 {
|
if hook_result != 0 {
|
||||||
|
@ -419,10 +420,31 @@ impl CtxMethods for BuildContext {
|
||||||
// If there was a package script, it should have finished
|
// If there was a package script, it should have finished
|
||||||
// the build already. Otherwise...
|
// the build already. Otherwise...
|
||||||
if !custom {
|
if !custom {
|
||||||
// Find crates inside the workspace
|
match what_to_build {
|
||||||
pkg_src.find_crates();
|
// 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!
|
// Build it!
|
||||||
let rs_path = pkg_src.build(exec, self, cfgs);
|
let rs_path = pkg_src.build(self, cfgs);
|
||||||
Path(rs_path)
|
Path(rs_path)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -452,56 +474,54 @@ impl CtxMethods for BuildContext {
|
||||||
fail!("info not yet implemented");
|
fail!("info not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
|
fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
|
||||||
|
|
||||||
let id = &pkg_src.id;
|
let id = pkg_src.id.clone();
|
||||||
|
|
||||||
let installed_files = RWArc::new(~[]);
|
let mut installed_files = ~[];
|
||||||
let inputs = RWArc::new(~[]);
|
let inputs = ~[];
|
||||||
// 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());
|
// workcache only knows about *crates*. Building a package
|
||||||
sub_files.write(|r| { *r = result.clone(); });
|
// just means inferring all the crates in it, then building each one.
|
||||||
sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
|
let destination_workspace = self.build(&mut pkg_src, what).to_str();
|
||||||
note(fmt!("Installed package %s to %s", id_str, actual_workspace.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,
|
fn install_no_build(&self,
|
||||||
source_workspace: &Path,
|
source_workspace: &Path,
|
||||||
target_workspace: &Path,
|
target_workspace: &Path,
|
||||||
id: &PkgId) -> ~[Path] {
|
id: &PkgId) -> ~[~str] {
|
||||||
use conditions::copy_failed::cond;
|
use conditions::copy_failed::cond;
|
||||||
|
|
||||||
// Now copy stuff into the install dirs
|
// Now copy stuff into the install dirs
|
||||||
|
@ -511,32 +531,59 @@ impl CtxMethods for BuildContext {
|
||||||
let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
|
let target_lib = maybe_library.map(|_p| target_library_in_workspace(id, target_workspace));
|
||||||
|
|
||||||
debug!("target_exec = %s target_lib = %? \
|
debug!("target_exec = %s target_lib = %? \
|
||||||
maybe_executable = %? maybe_library = %?",
|
maybe_executable = %? maybe_library = %?",
|
||||||
target_exec.to_str(), target_lib,
|
target_exec.to_str(), target_lib,
|
||||||
maybe_executable, maybe_library);
|
maybe_executable, maybe_library);
|
||||||
|
|
||||||
let mut outputs = ~[];
|
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));
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
|
||||||
for exec in maybe_executable.iter() {
|
do prep.exec |exe_thing| {
|
||||||
debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
|
let mut outputs = ~[];
|
||||||
if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
|
|
||||||
os::copy_file(exec, &target_exec)) {
|
for exec in subex.iter() {
|
||||||
cond.raise(((*exec).clone(), target_exec.clone()));
|
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_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()));
|
|
||||||
}
|
|
||||||
outputs.push(target_lib.clone());
|
|
||||||
}
|
|
||||||
outputs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefer(&self, _id: &str, _vers: Option<~str>) {
|
fn prefer(&self, _id: &str, _vers: Option<~str>) {
|
||||||
|
@ -726,15 +773,27 @@ pub fn main_args(args: &[~str]) {
|
||||||
|
|
||||||
debug!("Using sysroot: %s", sroot.to_str());
|
debug!("Using sysroot: %s", sroot.to_str());
|
||||||
debug!("Will store workcache in %s", default_workspace().to_str());
|
debug!("Will store workcache in %s", default_workspace().to_str());
|
||||||
BuildContext {
|
|
||||||
context: Context {
|
let rm_args = remaining_args.clone();
|
||||||
cfgs: cfgs,
|
let sub_cmd = cmd.clone();
|
||||||
rustc_flags: rustc_flags,
|
// Wrap the rest in task::try in case of a condition failure in a task
|
||||||
use_rust_path_hack: use_rust_path_hack,
|
let result = do task::try {
|
||||||
sysroot: sroot, // Currently, only tests override this
|
BuildContext {
|
||||||
},
|
context: Context {
|
||||||
workcache_context: api::default_context(default_workspace()).workcache_context
|
cfgs: cfgs.clone(),
|
||||||
}.run(*cmd, remaining_args)
|
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); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,8 +16,45 @@ pub enum OutputType { Main, Lib, Bench, Test }
|
||||||
|
|
||||||
#[deriving(Eq)]
|
#[deriving(Eq)]
|
||||||
pub enum Target {
|
pub enum Target {
|
||||||
// In-place build
|
/// In-place build
|
||||||
Build,
|
Build,
|
||||||
// Install to bin/ or lib/ dir
|
/// Install to bin/ or lib/ dir
|
||||||
Install
|
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";
|
||||||
|
|
|
@ -34,11 +34,7 @@ use rustc::driver::driver::{build_session, build_session_options, host_triple, o
|
||||||
use syntax::diagnostic;
|
use syntax::diagnostic;
|
||||||
use target::*;
|
use target::*;
|
||||||
use package_source::PkgSrc;
|
use package_source::PkgSrc;
|
||||||
|
use util::datestamp;
|
||||||
/// Returns the last-modified date as an Option
|
|
||||||
fn datestamp(p: &Path) -> Option<libc::time_t> {
|
|
||||||
p.stat().map(|stat| stat.st_mtime)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
|
fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
|
||||||
let context = workcache::Context::new(
|
let context = workcache::Context::new(
|
||||||
|
@ -224,18 +220,26 @@ fn rustpkg_exec() -> Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command_line_test(args: &[~str], cwd: &Path) -> ProcessOutput {
|
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)
|
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
|
/// Runs `rustpkg` (based on the directory that this executable was
|
||||||
/// invoked from) with the given arguments, in the given working directory.
|
/// invoked from) with the given arguments, in the given working directory.
|
||||||
/// Returns the process's output.
|
/// Returns the process's output.
|
||||||
fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
|
fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~str)]>)
|
||||||
-> Option<ProcessOutput> {
|
-> ProcessResult {
|
||||||
let cmd = rustpkg_exec().to_str();
|
let cmd = rustpkg_exec().to_str();
|
||||||
let env_str = match env {
|
let env_str = match env {
|
||||||
Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
|
Some(ref pairs) => pairs.map(|&(ref k, ref v)| { fmt!("%s=%s", *k, *v) }).connect(","),
|
||||||
|
@ -266,10 +270,10 @@ to make sure the command succeeded
|
||||||
debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
|
debug!("Command %s %? failed with exit code %?; its output was {{{ %s }}}",
|
||||||
cmd, args, output.status,
|
cmd, args, output.status,
|
||||||
str::from_utf8(output.output) + str::from_utf8(output.error));
|
str::from_utf8(output.output) + str::from_utf8(output.error));
|
||||||
None
|
Fail(output.status)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Some(output)
|
Success(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,8 +414,11 @@ fn command_line_test_output(args: &[~str]) -> ~[~str] {
|
||||||
|
|
||||||
fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
|
fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~str] {
|
||||||
let mut result = ~[];
|
let mut result = ~[];
|
||||||
let p_output = command_line_test_with_env(args,
|
let p_output = match command_line_test_with_env(args,
|
||||||
&os::getcwd(), Some(env)).expect("Command-line test failed");
|
&os::getcwd(), Some(env)) {
|
||||||
|
Fail(_) => fail!("Command-line test failed"),
|
||||||
|
Success(r) => r
|
||||||
|
};
|
||||||
let test_output = str::from_utf8(p_output.output);
|
let test_output = str::from_utf8(p_output.output);
|
||||||
for s in test_output.split_iter('\n') {
|
for s in test_output.split_iter('\n') {
|
||||||
result.push(s.to_owned());
|
result.push(s.to_owned());
|
||||||
|
@ -420,9 +427,9 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~
|
||||||
}
|
}
|
||||||
|
|
||||||
// assumes short_name and path are one and the same -- I should fix
|
// 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 {
|
fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
|
||||||
debug!("lib_output_file_name: given %s and parent %s and short name %s",
|
debug!("lib_output_file_name: given %s and short name %s",
|
||||||
workspace.to_str(), parent, short_name);
|
workspace.to_str(), short_name);
|
||||||
library_in_workspace(&Path(short_name),
|
library_in_workspace(&Path(short_name),
|
||||||
short_name,
|
short_name,
|
||||||
Build,
|
Build,
|
||||||
|
@ -450,19 +457,18 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a comment at the end
|
/// 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;
|
use conditions::bad_path::cond;
|
||||||
let pkg_src_dir = workspace.push_many([~"src", pkgid.to_str()]);
|
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;
|
let mut maybe_p = None;
|
||||||
for p in contents.iter() {
|
let maybe_file = pkg_src_dir.push(filename);
|
||||||
if p.filetype() == Some(".rs") {
|
debug!("Trying to frob %s -- %s", pkg_src_dir.to_str(), filename);
|
||||||
maybe_p = Some(p);
|
if os::path_exists(&maybe_file) {
|
||||||
break;
|
maybe_p = Some(maybe_file);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
debug!("Frobbed? %?", maybe_p);
|
||||||
match maybe_p {
|
match maybe_p {
|
||||||
Some(p) => {
|
Some(ref p) => {
|
||||||
let w = io::file_writer(p, &[io::Append]);
|
let w = io::file_writer(p, &[io::Append]);
|
||||||
match w {
|
match w {
|
||||||
Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
|
Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
|
||||||
|
@ -499,7 +505,7 @@ fn test_install_valid() {
|
||||||
debug!("temp_workspace = %s", temp_workspace.to_str());
|
debug!("temp_workspace = %s", temp_workspace.to_str());
|
||||||
// should have test, bench, lib, and main
|
// should have test, bench, lib, and main
|
||||||
let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
|
let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
|
||||||
ctxt.install(src);
|
ctxt.install(src, &Everything);
|
||||||
// Check that all files exist
|
// Check that all files exist
|
||||||
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
|
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
|
||||||
debug!("exec = %s", exec.to_str());
|
debug!("exec = %s", exec.to_str());
|
||||||
|
@ -528,7 +534,7 @@ fn test_install_invalid() {
|
||||||
// Uses task::try because of #9001
|
// Uses task::try because of #9001
|
||||||
let result = do task::try {
|
let result = do task::try {
|
||||||
let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
|
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.
|
// Not the best test -- doesn't test that we failed in the right way.
|
||||||
// Best we can do for now.
|
// Best we can do for now.
|
||||||
|
@ -939,26 +945,28 @@ fn no_rebuilding() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn no_rebuilding_dep() {
|
fn no_rebuilding_dep() {
|
||||||
let p_id = PkgId::new("foo");
|
let p_id = PkgId::new("foo");
|
||||||
let dep_id = PkgId::new("bar");
|
let dep_id = PkgId::new("bar");
|
||||||
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
||||||
command_line_test([~"build", ~"foo"], &workspace);
|
command_line_test([~"build", ~"foo"], &workspace);
|
||||||
let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
|
let bar_lib = lib_output_file_name(&workspace, "bar");
|
||||||
".rust",
|
let bar_date_1 = datestamp(&bar_lib);
|
||||||
"bar"));
|
|
||||||
let foo_date_1 = datestamp(&output_file_name(&workspace, ~"foo"));
|
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,
|
let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
|
||||||
".rust",
|
"bar"));
|
||||||
"bar"));
|
|
||||||
let foo_date_2 = datestamp(&output_file_name(&workspace, ~"foo"));
|
|
||||||
assert_eq!(bar_date_1, bar_date_2);
|
assert_eq!(bar_date_1, bar_date_2);
|
||||||
assert!(foo_date_1 < foo_date_2);
|
|
||||||
assert!(foo_date_1 > bar_date_1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -967,7 +975,7 @@ fn do_rebuild_dep_dates_change() {
|
||||||
let dep_id = PkgId::new("bar");
|
let dep_id = PkgId::new("bar");
|
||||||
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
||||||
command_line_test([~"build", ~"foo"], &workspace);
|
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);
|
let bar_date = datestamp(&bar_lib_name);
|
||||||
debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
|
debug!("Datestamp on %s is %?", bar_lib_name.to_str(), bar_date);
|
||||||
touch_source_file(&workspace, &dep_id);
|
touch_source_file(&workspace, &dep_id);
|
||||||
|
@ -983,11 +991,11 @@ fn do_rebuild_dep_only_contents_change() {
|
||||||
let dep_id = PkgId::new("bar");
|
let dep_id = PkgId::new("bar");
|
||||||
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
||||||
command_line_test([~"build", ~"foo"], &workspace);
|
command_line_test([~"build", ~"foo"], &workspace);
|
||||||
let bar_date = datestamp(&lib_output_file_name(&workspace, "build", "bar"));
|
let bar_date = datestamp(&lib_output_file_name(&workspace, "bar"));
|
||||||
frob_source_file(&workspace, &dep_id);
|
frob_source_file(&workspace, &dep_id, "lib.rs");
|
||||||
// should adjust the datestamp
|
// should adjust the datestamp
|
||||||
command_line_test([~"build", ~"foo"], &workspace);
|
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);
|
assert!(new_bar_date > bar_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,7 +1317,6 @@ fn rust_path_hack_build_no_arg() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore (reason = "#7402 not yet implemented")]
|
|
||||||
fn rust_path_install_target() {
|
fn rust_path_install_target() {
|
||||||
let dir_for_path = mkdtemp(&os::tmpdir(),
|
let dir_for_path = mkdtemp(&os::tmpdir(),
|
||||||
"source_workspace").expect("rust_path_install_target failed");
|
"source_workspace").expect("rust_path_install_target failed");
|
||||||
|
@ -1464,10 +1471,13 @@ fn test_cfg_fail() {
|
||||||
let workspace = create_local_package(&p_id);
|
let workspace = create_local_package(&p_id);
|
||||||
writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
|
writeFile(&workspace.push_many(["src", "foo-0.1", "main.rs"]),
|
||||||
"#[cfg(quux)] fn main() {}");
|
"#[cfg(quux)] fn main() {}");
|
||||||
assert!(command_line_test_partial([test_sysroot().to_str(),
|
match command_line_test_partial([test_sysroot().to_str(),
|
||||||
~"build",
|
~"build",
|
||||||
~"foo"],
|
~"foo"],
|
||||||
&workspace).is_none());
|
&workspace) {
|
||||||
|
Success(*) => fail!("test_cfg_fail failed"),
|
||||||
|
_ => ()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1680,6 +1690,21 @@ fn test_target_specific_install_dir() {
|
||||||
assert_executable_exists(&workspace, "foo");
|
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
|
/// Returns true if p exists and is executable
|
||||||
fn is_executable(p: &Path) -> bool {
|
fn is_executable(p: &Path) -> bool {
|
||||||
use std::libc::consts::os::posix88::{S_IXUSR};
|
use std::libc::consts::os::posix88::{S_IXUSR};
|
||||||
|
@ -1689,3 +1714,25 @@ fn is_executable(p: &Path) -> bool {
|
||||||
Some(mode) => mode & S_IXUSR as uint == S_IXUSR as uint
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::libc;
|
||||||
use std::os;
|
use std::os;
|
||||||
use extra::workcache;
|
use extra::workcache;
|
||||||
use rustc::driver::{driver, session};
|
use rustc::driver::{driver, session};
|
||||||
|
@ -26,7 +27,7 @@ use workspace::pkg_parent_workspaces;
|
||||||
use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
|
use path_util::{installed_library_in_workspace, U_RWX, rust_path, system_library, target_build_dir};
|
||||||
use messages::error;
|
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};
|
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,
|
// It would be nice to have the list of commands in just one place -- for example,
|
||||||
|
@ -171,6 +172,8 @@ pub fn compile_input(context: &BuildContext,
|
||||||
// not sure if we should support anything else
|
// not sure if we should support anything else
|
||||||
|
|
||||||
let out_dir = target_build_dir(workspace).push_rel(&pkg_id.path);
|
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();
|
let binary = os::args()[0].to_managed();
|
||||||
|
|
||||||
|
@ -220,7 +223,7 @@ pub fn compile_input(context: &BuildContext,
|
||||||
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: Some(sysroot_to_use),
|
maybe_sysroot: Some(sysroot_to_use),
|
||||||
addl_lib_search_paths: @mut (~[out_dir.clone()]),
|
addl_lib_search_paths: @mut (~[]),
|
||||||
output_type: output_type,
|
output_type: output_type,
|
||||||
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
|
.. (*driver::build_session_options(binary, &matches, diagnostic::emit)).clone()
|
||||||
};
|
};
|
||||||
|
@ -329,6 +332,9 @@ pub fn compile_crate_from_input(input: &Path,
|
||||||
// Register dependency on the source file
|
// Register dependency on the source file
|
||||||
exec.discover_input("file", input.to_str(), digest_file_with_date(input));
|
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)
|
Some(outputs.out_filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -409,7 +415,8 @@ pub fn find_and_install_dependencies(context: &BuildContext,
|
||||||
workspaces[0]
|
workspaces[0]
|
||||||
};
|
};
|
||||||
let (outputs_disc, inputs_disc) =
|
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 \
|
debug!("Installed %s, returned %? dependencies and \
|
||||||
%? transitive dependencies",
|
%? transitive dependencies",
|
||||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||||
|
@ -435,10 +442,11 @@ pub fn find_and_install_dependencies(context: &BuildContext,
|
||||||
debug!("Adding additional search path: %s", lib_name);
|
debug!("Adding additional search path: %s", lib_name);
|
||||||
let installed_library =
|
let installed_library =
|
||||||
installed_library_in_workspace(&Path(lib_name), &dep_workspace)
|
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));
|
lib_name));
|
||||||
let install_dir = installed_library.pop();
|
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);
|
save(install_dir);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -449,37 +457,6 @@ pub fn find_and_install_dependencies(context: &BuildContext,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 {
|
pub fn mk_string_lit(s: @str) -> ast::lit {
|
||||||
Spanned {
|
Spanned {
|
||||||
node: ast::lit_str(s),
|
node: ast::lit_str(s),
|
||||||
|
@ -516,3 +493,12 @@ pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
|
||||||
// tjc: cheesy
|
// tjc: cheesy
|
||||||
fn debug_flags() -> ~[~str] { ~[] }
|
fn debug_flags() -> ~[~str] { ~[] }
|
||||||
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
|
// 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 })
|
||||||
|
}
|
||||||
|
|
|
@ -56,3 +56,8 @@ pub fn discover_outputs(e: &mut workcache::Exec, outputs: ~[Path]) {
|
||||||
e.discover_output("binary", p.to_str(), digest_only_date(p));
|
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)"...
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue