Skip to content

Commit

Permalink
Auto merge of #1242 - alexcrichton:issue-1236, r=wycats
Browse files Browse the repository at this point in the history
Set out to solve #1236, but ended up solving #834 as well!
  • Loading branch information
bors committed Jan 29, 2015
2 parents 453ae9f + 06f37a0 commit 1e56839
Show file tree
Hide file tree
Showing 15 changed files with 364 additions and 149 deletions.
11 changes: 6 additions & 5 deletions src/cargo/core/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl Encodable for Manifest {
}
}

#[derive(Debug, Clone, PartialEq, Hash, RustcEncodable, Copy)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, RustcEncodable, Copy)]
pub enum LibKind {
Lib,
Rlib,
Expand Down Expand Up @@ -103,14 +103,14 @@ impl LibKind {
}
}

#[derive(Debug, Clone, Hash, PartialEq, RustcEncodable)]
#[derive(Debug, Clone, Hash, PartialEq, RustcEncodable, Eq)]
pub enum TargetKind {
Lib(Vec<LibKind>),
Bin,
Example,
}

#[derive(RustcEncodable, RustcDecodable, Clone, PartialEq, Debug)]
#[derive(RustcEncodable, RustcDecodable, Clone, PartialEq, Eq, Debug)]
pub struct Profile {
env: String, // compile, test, dev, bench, etc.
opt_level: u32,
Expand Down Expand Up @@ -345,7 +345,7 @@ impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for Profile {
}

/// Informations about a binary, a library, an example, etc. that is part of the package.
#[derive(Clone, Hash, PartialEq, Debug)]
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct Target {
kind: TargetKind,
name: String,
Expand Down Expand Up @@ -467,7 +467,8 @@ impl Manifest {
impl Target {
pub fn file_stem(&self) -> String {
match self.metadata {
Some(ref metadata) => format!("{}{}", self.name, metadata.extra_filename),
Some(ref metadata) => format!("{}{}", self.name,
metadata.extra_filename),
None => self.name.clone()
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/core/package_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl FromError<PackageIdError> for Box<CargoError> {
fn from_error(t: PackageIdError) -> Box<CargoError> { Box::new(t) }
}

#[derive(PartialEq, Hash, Clone, RustcEncodable, Debug)]
#[derive(PartialEq, Eq, Hash, Clone, RustcEncodable, Debug)]
pub struct Metadata {
pub metadata: String,
pub extra_filename: String
Expand Down
6 changes: 1 addition & 5 deletions src/cargo/core/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ pub trait Registry {

impl Registry for Vec<Summary> {
fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
debug!("querying for {:?}, summaries={:?}", dep,
self.iter().map(|s| s.get_package_id()).collect::<Vec<_>>());

Ok(self.iter().filter(|summary| dep.matches(*summary))
.map(|summary| summary.clone()).collect())
}
Expand Down Expand Up @@ -83,8 +80,7 @@ impl<'a, 'b> PackageRegistry<'a, 'b> {
}

pub fn get(&mut self, package_ids: &[PackageId]) -> CargoResult<Vec<Package>> {
log!(5, "getting packags; sources={}; ids={:?}", self.sources.len(),
package_ids);
log!(5, "getting packages; sources={}", self.sources.len());

// TODO: Only call source with package ID if the package came from the
// source
Expand Down
123 changes: 71 additions & 52 deletions src/cargo/core/resolver/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,28 +131,44 @@ struct Context {
/// Builds the list of all packages required to build the first argument.
pub fn resolve(summary: &Summary, method: Method,
registry: &mut Registry) -> CargoResult<Resolve> {
log!(5, "resolve; summary={:?}", summary);
log!(5, "resolve; summary={}", summary.get_package_id());
let summary = Rc::new(summary.clone());

let mut cx = Box::new(Context {
let cx = Box::new(Context {
resolve: Resolve::new(summary.get_package_id().clone()),
activations: HashMap::new(),
visited: Rc::new(RefCell::new(HashSet::new())),
});
let _p = profile::start(format!("resolving: {:?}", summary));
cx.activations.insert((summary.get_name().to_string(),
summary.get_source_id().clone()),
vec![Rc::new(summary.clone())]);
match try!(activate(cx, registry, summary, method)) {
Ok(cx) => Ok(cx.resolve),
match try!(activate(cx, registry, &summary, method)) {
Ok(cx) => {
debug!("resolved: {:?}", cx.resolve);
Ok(cx.resolve)
}
Err(e) => Err(e),
}
}

fn activate(mut cx: Box<Context>,
registry: &mut Registry,
parent: &Summary,
parent: &Rc<Summary>,
method: Method)
-> CargoResult<CargoResult<Box<Context>>> {
// Dependency graphs are required to be a DAG, so we keep a set of
// packages we're visiting and bail if we hit a dupe.
let id = parent.get_package_id();
if !cx.visited.borrow_mut().insert(id.clone()) {
return Err(human(format!("cyclic package dependency: package `{}` \
depends on itself", id)))
}

// If we're already activated, then that was easy!
if flag_activated(&mut *cx, parent, &method) {
cx.visited.borrow_mut().remove(id);
return Ok(Ok(cx))
}
debug!("activating {}", parent.get_package_id());

// Extracting the platform request.
let platform = match method {
Method::Required(_, _, _, platform) => platform,
Expand All @@ -162,7 +178,7 @@ fn activate(mut cx: Box<Context>,
// First, figure out our set of dependencies based on the requsted set of
// features. This also calculates what features we're going to enable for
// our own dependencies.
let deps = try!(resolve_features(&mut *cx, parent, method));
let deps = try!(resolve_features(&mut *cx, &**parent, method));

// Next, transform all dependencies into a list of possible candidates which
// can satisfy that dependency.
Expand All @@ -185,7 +201,40 @@ fn activate(mut cx: Box<Context>,
a.len().cmp(&b.len())
});

activate_deps(cx, registry, parent, platform, deps.as_slice(), 0)
Ok(match try!(activate_deps(cx, registry, &**parent, platform, &*deps, 0)) {
Ok(cx) => {
cx.visited.borrow_mut().remove(parent.get_package_id());
Ok(cx)
}
Err(e) => Err(e),
})
}

// Activate this summary by inserting it into our list of known activations.
//
// Returns if this summary with the given method is already activated.
fn flag_activated(cx: &mut Context,
summary: &Rc<Summary>,
method: &Method) -> bool {
let id = summary.get_package_id();
let key = (id.get_name().to_string(), id.get_source_id().clone());
let prev = cx.activations.entry(key).get().unwrap_or_else(|e| {
e.insert(Vec::new())
});
if !prev.iter().any(|c| c == summary) {
cx.resolve.graph.add(id.clone(), &[]);
prev.push(summary.clone());
return false
}
debug!("checking if {} is already activated", summary.get_package_id());
let features = match *method {
Method::Required(_, features, _, _) => features,
Method::Everything => return false,
};
match cx.resolve.features(id) {
Some(prev) => features.iter().all(|f| prev.contains(f)),
None => features.len() == 0,
}
}

fn activate_deps<'a>(cx: Box<Context>,
Expand Down Expand Up @@ -237,50 +286,20 @@ fn activate_deps<'a>(cx: Box<Context>,
log!(5, "{}[{}]>{} trying {}", parent.get_name(), cur, dep.get_name(),
candidate.get_version());
let mut my_cx = cx.clone();
let early_return = {
let my_cx = &mut *my_cx;
my_cx.resolve.graph.link(parent.get_package_id().clone(),
candidate.get_package_id().clone());
let prev = match my_cx.activations.entry(key.clone()) {
Occupied(e) => e.into_mut(),
Vacant(e) => e.insert(Vec::new()),
};
if prev.iter().any(|c| c == candidate) {
match cx.resolve.features(candidate.get_package_id()) {
Some(prev_features) => {
features.iter().all(|f| prev_features.contains(f))
}
None => features.len() == 0,
}
} else {
my_cx.resolve.graph.add(candidate.get_package_id().clone(), &[]);
prev.push(candidate.clone());
false
}
};
my_cx.resolve.graph.link(parent.get_package_id().clone(),
candidate.get_package_id().clone());

let my_cx = if early_return {
my_cx
} else {
// Dependency graphs are required to be a DAG. Non-transitive
// dependencies (dev-deps), however, can never introduce a cycle, so
// we skip them.
if dep.is_transitive() &&
!cx.visited.borrow_mut().insert(candidate.get_package_id().clone()) {
return Err(human(format!("cyclic package dependency: package `{}` \
depends on itself",
candidate.get_package_id())))
}
let my_cx = try!(activate(my_cx, registry, &**candidate, method));
if dep.is_transitive() {
cx.visited.borrow_mut().remove(candidate.get_package_id());
}
match my_cx {
Ok(cx) => cx,
Err(e) => { last_err = Some(e); continue }
}
// If we hit an intransitive dependency then clear out the visitation
// list as we can't induce a cycle through transitive dependencies.
if !dep.is_transitive() {
my_cx.visited.borrow_mut().clear();
}
let my_cx = match try!(activate(my_cx, registry, candidate, method)) {
Ok(cx) => cx,
Err(e) => { last_err = Some(e); continue }
};
match try!(activate_deps(my_cx, registry, parent, platform, deps, cur + 1)) {
match try!(activate_deps(my_cx, registry, parent, platform, deps,
cur + 1)) {
Ok(cx) => return Ok(Ok(cx)),
Err(e) => { last_err = Some(e); }
}
Expand Down
2 changes: 0 additions & 2 deletions src/cargo/ops/cargo_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,6 @@ pub fn compile_pkg(package: &Package, options: &CompileOptions)
(packages, resolved_with_overrides, registry.move_sources())
};

debug!("packages={:?}", packages);

let to_build = match spec {
Some(spec) => {
let pkgid = try!(resolve_with_overrides.query(spec));
Expand Down
1 change: 0 additions & 1 deletion src/cargo/ops/cargo_read_manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ pub fn read_packages(path: &Path, source_id: &SourceId, config: &Config)
if all_packages.is_empty() {
Err(human(format!("Could not find Cargo.toml in `{}`", path.display())))
} else {
log!(5, "all packages: {:?}", all_packages);
Ok(all_packages.into_iter().collect())
}
}
Expand Down
26 changes: 23 additions & 3 deletions src/cargo/ops/cargo_rustc/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ use std::sync::Arc;

use regex::Regex;

use core::{SourceMap, Package, PackageId, PackageSet, Resolve, Target};
use core::{SourceMap, Package, PackageId, PackageSet, Resolve, Target, Profile};
use util::{self, CargoResult, ChainError, internal, Config, profile};
use util::human;

use super::{Kind, Compilation, BuildConfig};
use super::TargetConfig;
use super::layout::{Layout, LayoutProxy};
use super::custom_build::BuildState;
use super::fingerprint::Fingerprint;
use super::layout::{Layout, LayoutProxy};
use super::{Kind, Compilation, BuildConfig};
use super::{ProcessEngine, ExecEngine};

#[derive(Debug, Copy)]
Expand All @@ -29,6 +30,7 @@ pub struct Context<'a, 'b: 'a> {
pub compilation: Compilation,
pub build_state: Arc<BuildState>,
pub exec_engine: Arc<Box<ExecEngine>>,
pub fingerprints: HashMap<(&'a PackageId, &'a Target, Kind), Fingerprint>,

env: &'a str,
host: Layout,
Expand Down Expand Up @@ -80,6 +82,7 @@ impl<'a, 'b: 'a> Context<'a, 'b> {
build_state: Arc::new(BuildState::new(build_config.clone(), deps)),
build_config: build_config,
exec_engine: Arc::new(Box::new(ProcessEngine) as Box<ExecEngine>),
fingerprints: HashMap::new(),
})
}

Expand Down Expand Up @@ -357,6 +360,23 @@ impl<'a, 'b: 'a> Context<'a, 'b> {
pub fn requested_target(&self) -> Option<&str> {
self.build_config.requested_target.as_ref().map(|s| &s[])
}

/// Calculate the actual profile to use for a target's compliation.
///
/// This may involve overriding some options such as debug information,
/// rpath, opt level, etc.
pub fn profile(&self, target: &Target) -> Profile {
let mut profile = target.get_profile().clone();
let root_package = self.get_package(self.resolve.root());
for target in root_package.get_manifest().get_targets().iter() {
let root_profile = target.get_profile();
if root_profile.get_env() != profile.get_env() { continue }
profile = profile.opt_level(root_profile.get_opt_level())
.debug(root_profile.get_debug())
.rpath(root_profile.get_rpath())
}
profile
}
}

impl Platform {
Expand Down
Loading

0 comments on commit 1e56839

Please sign in to comment.