Skip to content

Commit ddccbca

Browse files
committed
Add an explanation of links related conflicts to error messages
1 parent 50cd36a commit ddccbca

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

src/cargo/core/resolver/mod.rs

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,12 @@ impl Ord for DepsFrame {
532532
}
533533
}
534534

535+
#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
536+
enum ConflictReason {
537+
Semver,
538+
Links(String),
539+
}
540+
535541
struct BacktrackFrame<'a> {
536542
cur: usize,
537543
context_backup: Context<'a>,
@@ -540,18 +546,18 @@ struct BacktrackFrame<'a> {
540546
parent: Summary,
541547
dep: Dependency,
542548
features: Rc<Vec<String>>,
543-
conflicting_activations: HashSet<PackageId>,
549+
conflicting_activations: HashMap<PackageId, ConflictReason>,
544550
}
545551

546552
#[derive(Clone)]
547553
struct RemainingCandidates {
548554
remaining: RcVecIter<Candidate>,
549555
// note: change to RcList or something if clone is to expensive
550-
conflicting_prev_active: HashSet<PackageId>,
556+
conflicting_prev_active: HashMap<PackageId, ConflictReason>,
551557
}
552558

553559
impl RemainingCandidates {
554-
fn next(&mut self, prev_active: &[Summary], links: &HashMap<String, PackageId>) -> Result<Candidate, HashSet<PackageId>> {
560+
fn next(&mut self, prev_active: &[Summary], links: &HashMap<String, PackageId>) -> Result<Candidate, HashMap<PackageId, ConflictReason>> {
555561
// Filter the set of candidates based on the previously activated
556562
// versions for this dependency. We can actually use a version if it
557563
// precisely matches an activated version or if it is otherwise
@@ -565,15 +571,17 @@ impl RemainingCandidates {
565571
// that conflicted with the ones we tried. If any of these change
566572
// then we would have considered different candidates.
567573
for (_, b) in self.remaining.by_ref() {
568-
if let Some(a) = b.summary.links().and_then(|l| links.get(l)) {
569-
if a != b.summary.package_id() {
570-
self.conflicting_prev_active.insert(a.clone());
571-
continue
574+
if let Some(link) = b.summary.links() {
575+
if let Some(a) = links.get(link) {
576+
if a != b.summary.package_id() {
577+
self.conflicting_prev_active.insert(a.clone(), ConflictReason::Links(link.to_owned()));
578+
continue
579+
}
572580
}
573581
}
574582
if let Some(a) = prev_active.iter().find(|a| compatible(a.version(), b.summary.version())) {
575583
if *a != b.summary {
576-
self.conflicting_prev_active.insert(a.package_id().clone());
584+
self.conflicting_prev_active.insert(a.package_id().clone(), ConflictReason::Semver);
577585
continue
578586
}
579587
}
@@ -673,9 +681,9 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
673681
dep.name(), prev_active.len());
674682
let mut candidates = RemainingCandidates {
675683
remaining: RcVecIter::new(Rc::clone(&candidates)),
676-
conflicting_prev_active: HashSet::new(),
684+
conflicting_prev_active: HashMap::new(),
677685
};
678-
conflicting_activations = HashSet::new();
686+
conflicting_activations = HashMap::new();
679687
(candidates.next(prev_active, &cx.links),
680688
candidates.clone().next(prev_active, &cx.links).is_ok(),
681689
candidates)
@@ -772,7 +780,7 @@ fn find_candidate<'a>(
772780
cur: &mut usize,
773781
dep: &mut Dependency,
774782
features: &mut Rc<Vec<String>>,
775-
conflicting_activations: &mut HashSet<PackageId>,
783+
conflicting_activations: &mut HashMap<PackageId, ConflictReason>,
776784
) -> Option<Candidate> {
777785
while let Some(mut frame) = backtrack_stack.pop() {
778786
let (next, has_another) = {
@@ -786,7 +794,7 @@ fn find_candidate<'a>(
786794
&& conflicting_activations
787795
.iter()
788796
// note: a lot of redundant work in is_active for similar debs
789-
.all(|con| frame.context_backup.is_active(con))
797+
.all(|(con, _)| frame.context_backup.is_active(con))
790798
{
791799
continue;
792800
}
@@ -818,7 +826,7 @@ fn activation_error(cx: &Context,
818826
registry: &mut Registry,
819827
parent: &Summary,
820828
dep: &Dependency,
821-
conflicting_activations: HashSet<PackageId>,
829+
conflicting_activations: HashMap<PackageId, ConflictReason>,
822830
candidates: &[Candidate],
823831
config: Option<&Config>) -> CargoError {
824832
let graph = cx.graph();
@@ -842,9 +850,17 @@ fn activation_error(cx: &Context,
842850
msg.push_str(&describe_path(parent.package_id()));
843851
let mut conflicting_activations: Vec<_> = conflicting_activations.iter().collect();
844852
conflicting_activations.sort_unstable();
845-
for v in conflicting_activations.iter().rev() {
853+
for &(p, r) in conflicting_activations.iter().rev() {
854+
match r {
855+
&ConflictReason::Links(ref link) => {
856+
msg.push_str("\n multiple packages link to native library `");
857+
msg.push_str(link);
858+
msg.push_str("`, but a native library can be linked only once.")
859+
},
860+
_ => (),
861+
}
846862
msg.push_str("\n previously selected ");
847-
msg.push_str(&describe_path(v));
863+
msg.push_str(&describe_path(p));
848864
}
849865

850866
msg.push_str("\n possible versions to select: ");

tests/build-script.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,11 @@ fn links_duplicates() {
257257
assert_that(p.cargo("build"),
258258
execs().with_status(101)
259259
.with_stderr("\
260-
error: failed to select a version for `a-sys` (required by `foo`):
261-
all possible versions conflict with previously selected versions of `a-sys`
260+
error: failed to select a version for `a-sys`.
261+
all possible versions conflict with previously selected packages.
262+
required by package `foo v0.5.0 ([..])`
263+
multiple packages link to native library `a`, but a native library can be linked only once.
264+
previously selected package `foo v0.5.0 ([..])`
262265
possible versions to select: 0.5.0
263266
"));
264267
}
@@ -307,8 +310,12 @@ fn links_duplicates_deep_dependency() {
307310
assert_that(p.cargo("build"),
308311
execs().with_status(101)
309312
.with_stderr("\
310-
error: failed to select a version for `a-sys` (required by `a`):
311-
all possible versions conflict with previously selected versions of `a-sys`
313+
error: failed to select a version for `a-sys`.
314+
all possible versions conflict with previously selected packages.
315+
required by package `a v0.5.0 ([..])`
316+
... which is depended on by `foo v0.5.0 ([..])`
317+
multiple packages link to native library `a`, but a native library can be linked only once.
318+
previously selected package `foo v0.5.0 ([..])`
312319
possible versions to select: 0.5.0
313320
"));
314321
}
@@ -2773,8 +2780,11 @@ fn links_duplicates_with_cycle() {
27732780
assert_that(p.cargo("build"),
27742781
execs().with_status(101)
27752782
.with_stderr("\
2776-
error: failed to select a version for `a` (required by `foo`):
2777-
all possible versions conflict with previously selected versions of `a`
2783+
error: failed to select a version for `a`.
2784+
all possible versions conflict with previously selected packages.
2785+
required by package `foo v0.5.0 ([..])`
2786+
multiple packages link to native library `a`, but a native library can be linked only once.
2787+
previously selected package `foo v0.5.0 ([..])`
27782788
possible versions to select: 0.5.0
27792789
"));
27802790
}

0 commit comments

Comments
 (0)