/// For a package, return all targets which are registered as dependencies
/// for that package.
- pub fn dep_targets(&self, unit: &Unit<'a>) -> Vec<Unit<'a>> {
+ pub fn dep_targets(&self, unit: &Unit<'a>) -> CargoResult<Vec<Unit<'a>>> {
if unit.profile.run_custom_build {
return self.dep_run_custom_build(unit)
} else if unit.profile.doc {
let id = unit.pkg.package_id();
let deps = self.resolve.deps(id).into_iter().flat_map(|a| a);
- let mut ret = deps.filter(|dep| {
+ let mut ret = try!(deps.filter(|dep| {
unit.pkg.dependencies().iter().filter(|d| {
d.name() == dep.name()
}).any(|d| {
true
})
}).filter_map(|id| {
- let pkg = self.get_package(id);
- pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
- Unit {
- pkg: pkg,
- target: t,
- profile: self.lib_profile(id),
- kind: unit.kind.for_target(t),
+ match self.get_package(id) {
+ Ok(pkg) => {
+ pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
+ Ok(Unit {
+ pkg: pkg,
+ target: t,
+ profile: self.lib_profile(id),
+ kind: unit.kind.for_target(t),
+ })
+ })
}
- })
- }).collect::<Vec<_>>();
+ Err(e) => Some(Err(e))
+ }
+ }).collect::<CargoResult<Vec<_>>>());
// If this target is a build script, then what we've collected so far is
// all we need. If this isn't a build script, then it depends on the
// build script if there is one.
if unit.target.is_custom_build() {
- return ret
+ return Ok(ret)
}
ret.extend(self.dep_build_script(unit));
// didn't include `pkg` in the return values, so we need to special case
// it here and see if we need to push `(pkg, pkg_lib_target)`.
if unit.target.is_lib() {
- return ret
+ return Ok(ret)
}
ret.extend(self.maybe_lib(unit));
}
}));
}
- ret
+ Ok(ret)
}
/// Returns the dependencies needed to run a build script.
///
/// The `unit` provided must represent an execution of a build script, and
/// the returned set of units must all be run before `unit` is run.
- pub fn dep_run_custom_build(&self, unit: &Unit<'a>) -> Vec<Unit<'a>> {
+ pub fn dep_run_custom_build(&self, unit: &Unit<'a>)
+ -> CargoResult<Vec<Unit<'a>>> {
// If this build script's execution has been overridden then we don't
// actually depend on anything, we've reached the end of the dependency
// chain as we've got all the info we're gonna get.
let key = (unit.pkg.package_id().clone(), unit.kind);
if self.build_state.outputs.lock().unwrap().contains_key(&key) {
- return Vec::new()
+ return Ok(Vec::new())
}
// When not overridden, then the dependencies to run a build script are:
profile: &self.profiles.dev,
..*unit
};
- self.dep_targets(&tmp).iter().filter_map(|unit| {
+ let deps = try!(self.dep_targets(&tmp));
+ Ok(deps.iter().filter_map(|unit| {
if !unit.target.linkable() || unit.pkg.manifest().links().is_none() {
return None
}
profile: self.build_script_profile(unit.pkg.package_id()),
kind: Kind::Host, // build scripts always compiled for the host
..*unit
- })).collect()
+ })).collect())
}
/// Returns the dependencies necessary to document a package
- fn doc_deps(&self, unit: &Unit<'a>) -> Vec<Unit<'a>> {
+ fn doc_deps(&self, unit: &Unit<'a>) -> CargoResult<Vec<Unit<'a>>> {
let deps = self.resolve.deps(unit.pkg.package_id()).into_iter();
let deps = deps.flat_map(|a| a).filter(|dep| {
unit.pkg.dependencies().iter().filter(|d| {
_ => false,
}
})
- }).filter_map(|dep| {
- let dep = self.get_package(dep);
- dep.targets().iter().find(|t| t.is_lib()).map(|t| (dep, t))
+ }).map(|dep| {
+ self.get_package(dep)
});
// To document a library, we depend on dependencies actually being
// built. If we're documenting *all* libraries, then we also depend on
// the documentation of the library being built.
let mut ret = Vec::new();
- for (dep, lib) in deps {
+ for dep in deps {
+ let dep = try!(dep);
+ let lib = match dep.targets().iter().find(|t| t.is_lib()) {
+ Some(lib) => lib,
+ None => continue,
+ };
ret.push(Unit {
pkg: dep,
target: lib,
if unit.target.is_bin() {
ret.extend(self.maybe_lib(unit));
}
- ret
+ Ok(ret)
}
/// If a build script is scheduled to be run for the package specified by
}
/// Gets a package for the given package id.
- pub fn get_package(&self, id: &PackageId) -> &'a Package {
- // TODO: remove this unwrap() -- happens in a later commit
- self.packages.get(id).unwrap()
+ pub fn get_package(&self, id: &PackageId) -> CargoResult<&'a Package> {
+ self.packages.get(id)
}
/// Get the user-specified linker for a particular host or target
// This information will be used at build-time later on to figure out which
// sorts of variables need to be discovered at that time.
let lib_deps = {
- cx.dep_run_custom_build(unit).iter().filter_map(|unit| {
+ try!(cx.dep_run_custom_build(unit)).iter().filter_map(|unit| {
if unit.profile.run_custom_build {
Some((unit.pkg.manifest().links().unwrap().to_string(),
unit.pkg.package_id().clone()))
/// The given set of targets to this function is the initial set of
/// targets/profiles which are being built.
pub fn build_map<'b, 'cfg>(cx: &mut Context<'b, 'cfg>,
- units: &[Unit<'b>]) {
+ units: &[Unit<'b>])
+ -> CargoResult<()> {
let mut ret = HashMap::new();
for unit in units {
- build(&mut ret, cx, unit);
+ try!(build(&mut ret, cx, unit));
}
cx.build_scripts.extend(ret.into_iter().map(|(k, v)| {
(k, Arc::new(v))
}));
+ return Ok(());
// Recursive function to build up the map we're constructing. This function
// memoizes all of its return values as it goes along.
fn build<'a, 'b, 'cfg>(out: &'a mut HashMap<Unit<'b>, BuildScripts>,
cx: &Context<'b, 'cfg>,
unit: &Unit<'b>)
- -> &'a BuildScripts {
+ -> CargoResult<&'a BuildScripts> {
// Do a quick pre-flight check to see if we've already calculated the
// set of dependencies.
if out.contains_key(unit) {
- return &out[unit]
+ return Ok(&out[unit])
}
let mut ret = BuildScripts::default();
if !unit.target.is_custom_build() && unit.pkg.has_custom_build() {
add_to_link(&mut ret, unit.pkg.package_id(), unit.kind);
}
- for unit in cx.dep_targets(unit).iter() {
- let dep_scripts = build(out, cx, unit);
+ for unit in try!(cx.dep_targets(unit)).iter() {
+ let dep_scripts = try!(build(out, cx, unit));
if unit.target.for_host() {
ret.plugins.extend(dep_scripts.to_link.iter()
add_to_link(prev, &pkg, kind);
}
prev.plugins.extend(ret.plugins);
- prev
+ Ok(prev)
}
// When adding an entry to 'to_link' we only actually push it on if the
// elsewhere. Also skip fingerprints of binaries because they don't actually
// induce a recompile, they're just dependencies in the sense that they need
// to be built.
- let deps = try!(cx.dep_targets(unit).iter().filter(|u| {
+ let deps = try!(cx.dep_targets(unit));
+ let deps = try!(deps.iter().filter(|u| {
!u.target.is_custom_build() && !u.target.is_bin()
}).map(|unit| {
calculate(cx, unit).map(|fingerprint| {
}
}
- pub fn enqueue<'cfg>(&mut self, cx: &Context<'a, 'cfg>,
- unit: &Unit<'a>, job: Job, fresh: Freshness) {
+ pub fn enqueue<'cfg>(&mut self,
+ cx: &Context<'a, 'cfg>,
+ unit: &Unit<'a>,
+ job: Job,
+ fresh: Freshness) -> CargoResult<()> {
let key = Key::new(unit);
- self.queue.queue(Fresh,
- key,
- Vec::new(),
- &key.dependencies(cx)).push((job, fresh));
+ let deps = try!(key.dependencies(cx));
+ self.queue.queue(Fresh, key, Vec::new(), &deps).push((job, fresh));
*self.counts.entry(key.pkg).or_insert(0) += 1;
+ Ok(())
}
/// Execute all jobs necessary to build the dependency graph.
}
}
- fn dependencies<'cfg>(&self, cx: &Context<'a, 'cfg>) -> Vec<Key<'a>> {
+ fn dependencies<'cfg>(&self, cx: &Context<'a, 'cfg>)
+ -> CargoResult<Vec<Key<'a>>> {
let unit = Unit {
- pkg: cx.get_package(self.pkg),
+ pkg: try!(cx.get_package(self.pkg)),
target: self.target,
profile: self.profile,
kind: self.kind,
};
- cx.dep_targets(&unit).iter().filter_map(|unit| {
+ let targets = try!(cx.dep_targets(&unit));
+ Ok(targets.iter().filter_map(|unit| {
// Binaries aren't actually needed to *compile* tests, just to run
// them, so we don't include this dependency edge in the job graph.
if self.target.is_test() && unit.target.is_bin() {
} else {
Some(Key::new(unit))
}
- }).collect()
+ }).collect())
}
}
let mut queue = JobQueue::new(&cx);
try!(cx.prepare(root));
- custom_build::build_map(&mut cx, &units);
+ try!(custom_build::build_map(&mut cx, &units));
for unit in units.iter() {
// Build up a list of pending jobs, each of which represent
if !unit.target.is_lib() { continue }
// Include immediate lib deps as well
- for unit in cx.dep_targets(unit).iter() {
+ for unit in try!(cx.dep_targets(unit)).iter() {
let pkgid = unit.pkg.package_id();
if !unit.target.is_lib() { continue }
if unit.profile.doc { continue }
let dirty = work.then(dirty);
(dirty, fresh, freshness)
};
- jobs.enqueue(cx, unit, Job::new(dirty, fresh), freshness);
+ try!(jobs.enqueue(cx, unit, Job::new(dirty, fresh), freshness));
drop(p);
// Be sure to compile all dependencies of this target as well.
- for unit in cx.dep_targets(unit).iter() {
+ for unit in try!(cx.dep_targets(unit)).iter() {
try!(compile(cx, jobs, unit));
}
Ok(())
cmd.env("OUT_DIR", &layout.build_out(unit.pkg));
}
- for unit in cx.dep_targets(unit).iter() {
+ for unit in try!(cx.dep_targets(unit)).iter() {
if unit.target.linkable() {
try!(link_to(cmd, cx, unit));
}