@@ -318,40 +318,7 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
318
318
method : ResolveMethod ,
319
319
ctx : & mut Context < ' a , R > )
320
320
-> CargoResult < ( ) > {
321
- let dev_deps = match method {
322
- ResolveEverything => true ,
323
- ResolveRequired ( dev_deps, _, _) => dev_deps,
324
- } ;
325
-
326
- // First, filter by dev-dependencies
327
- let deps = parent. get_dependencies ( ) ;
328
- let deps = deps. iter ( ) . filter ( |d| d. is_transitive ( ) || dev_deps) ;
329
-
330
- // Second, weed out optional dependencies, but not those required
331
- let ( mut feature_deps, used_features) = try!( build_features ( parent, method) ) ;
332
- let deps = deps. filter ( |d| {
333
- !d. is_optional ( ) || feature_deps. remove ( & d. get_name ( ) . to_string ( ) )
334
- } ) . collect :: < Vec < & Dependency > > ( ) ;
335
-
336
- // All features can only point to optional dependencies, in which case they
337
- // should have all been weeded out by the above iteration. Any remaining
338
- // features are bugs in that the package does not actually have those
339
- // features.
340
- if feature_deps. len ( ) > 0 {
341
- let features = feature_deps. iter ( ) . map ( |s| s. as_slice ( ) )
342
- . collect :: < Vec < & str > > ( ) . connect ( ", " ) ;
343
- return Err ( human ( format ! ( "Package `{}` does not have these features: \
344
- `{}`", parent. get_package_id( ) , features) ) )
345
- }
346
-
347
- // Record what list of features is active for this package.
348
- {
349
- let pkgid = parent. get_package_id ( ) . clone ( ) ;
350
- match ctx. resolve . features . entry ( pkgid) {
351
- Occupied ( entry) => entry. into_mut ( ) ,
352
- Vacant ( entry) => entry. set ( HashSet :: new ( ) ) ,
353
- } . extend ( used_features. into_iter ( ) ) ;
354
- }
321
+ let ( deps, features) = try!( resolve_features ( parent, method, ctx) ) ;
355
322
356
323
// Recursively resolve all dependencies
357
324
for & dep in deps. iter ( ) {
@@ -409,8 +376,15 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
409
376
depends on itself",
410
377
summary. get_package_id( ) ) ) )
411
378
}
379
+
380
+ // The list of enabled features for this dependency are both those
381
+ // listed in the dependency itself as well as any of our own features
382
+ // which enabled a feature of this package.
383
+ let features = features. find_equiv ( & dep. get_name ( ) )
384
+ . map ( |v| v. as_slice ( ) )
385
+ . unwrap_or ( & [ ] ) ;
412
386
try!( resolve_deps ( summary,
413
- ResolveRequired ( false , dep . get_features ( ) ,
387
+ ResolveRequired ( false , features ,
414
388
dep. uses_default_features ( ) ) ,
415
389
ctx) ) ;
416
390
if dep. is_transitive ( ) {
@@ -421,10 +395,81 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
421
395
Ok ( ( ) )
422
396
}
423
397
398
+ fn resolve_features < ' a , R > ( parent : & ' a Summary , method : ResolveMethod ,
399
+ ctx : & mut Context < R > )
400
+ -> CargoResult < ( Vec < & ' a Dependency > ,
401
+ HashMap < & ' a str , Vec < String > > ) > {
402
+ let dev_deps = match method {
403
+ ResolveEverything => true ,
404
+ ResolveRequired ( dev_deps, _, _) => dev_deps,
405
+ } ;
406
+
407
+ // First, filter by dev-dependencies
408
+ let deps = parent. get_dependencies ( ) ;
409
+ let deps = deps. iter ( ) . filter ( |d| d. is_transitive ( ) || dev_deps) ;
410
+
411
+ // Second, weed out optional dependencies, but not those required
412
+ let ( mut feature_deps, used_features) = try!( build_features ( parent, method) ) ;
413
+ let mut ret = HashMap :: new ( ) ;
414
+ let deps = deps. filter ( |d| {
415
+ !d. is_optional ( ) || feature_deps. contains_key_equiv ( & d. get_name ( ) )
416
+ } ) . collect :: < Vec < & Dependency > > ( ) ;
417
+
418
+ // Next, sanitize all requested features by whitelisting all the requested
419
+ // features that correspond to optional dependencies
420
+ for dep in deps. iter ( ) {
421
+ let mut base = feature_deps. pop_equiv ( & dep. get_name ( ) )
422
+ . unwrap_or ( Vec :: new ( ) ) ;
423
+ for feature in dep. get_features ( ) . iter ( ) {
424
+ base. push ( feature. clone ( ) ) ;
425
+ if feature. as_slice ( ) . contains ( "/" ) {
426
+ return Err ( human ( format ! ( "features in dependencies \
427
+ cannot enable features in \
428
+ other dependencies: `{}`",
429
+ feature) ) ) ;
430
+ }
431
+ }
432
+ ret. insert ( dep. get_name ( ) , base) ;
433
+ }
434
+
435
+ // All features can only point to optional dependencies, in which case they
436
+ // should have all been weeded out by the above iteration. Any remaining
437
+ // features are bugs in that the package does not actually have those
438
+ // features.
439
+ if feature_deps. len ( ) > 0 {
440
+ let unknown = feature_deps. keys ( ) . map ( |s| s. as_slice ( ) )
441
+ . collect :: < Vec < & str > > ( ) ;
442
+ if unknown. len ( ) > 0 {
443
+ let features = unknown. connect ( ", " ) ;
444
+ return Err ( human ( format ! ( "Package `{}` does not have these features: \
445
+ `{}`", parent. get_package_id( ) , features) ) )
446
+ }
447
+ }
448
+
449
+ // Record what list of features is active for this package.
450
+ {
451
+ let pkgid = parent. get_package_id ( ) . clone ( ) ;
452
+ match ctx. resolve . features . entry ( pkgid) {
453
+ Occupied ( entry) => entry. into_mut ( ) ,
454
+ Vacant ( entry) => entry. set ( HashSet :: new ( ) ) ,
455
+ } . extend ( used_features. into_iter ( ) ) ;
456
+ }
457
+
458
+ Ok ( ( deps, ret) )
459
+ }
460
+
424
461
// Returns a pair of (feature dependencies, all used features)
462
+ //
463
+ // The feature dependencies map is a mapping of package name to list of features
464
+ // enabled. Each package should be enabled, and each package should have the
465
+ // specified set of features enabled.
466
+ //
467
+ // The all used features set is the set of features which this local package had
468
+ // enabled, which is later used when compiling to instruct the code what
469
+ // features were enabled.
425
470
fn build_features ( s : & Summary , method : ResolveMethod )
426
- -> CargoResult < ( HashSet < String > , HashSet < String > ) > {
427
- let mut deps = HashSet :: new ( ) ;
471
+ -> CargoResult < ( HashMap < String , Vec < String > > , HashSet < String > ) > {
472
+ let mut deps = HashMap :: new ( ) ;
428
473
let mut used = HashSet :: new ( ) ;
429
474
let mut visited = HashSet :: new ( ) ;
430
475
match method {
@@ -454,26 +499,51 @@ fn build_features(s: &Summary, method: ResolveMethod)
454
499
return Ok ( ( deps, used) ) ;
455
500
456
501
fn add_feature ( s : & Summary , feat : & str ,
457
- deps : & mut HashSet < String > ,
502
+ deps : & mut HashMap < String , Vec < String > > ,
458
503
used : & mut HashSet < String > ,
459
504
visited : & mut HashSet < String > ) -> CargoResult < ( ) > {
460
- if feat. is_empty ( ) {
461
- return Ok ( ( ) )
462
- }
463
- if !visited. insert ( feat. to_string ( ) ) {
464
- return Err ( human ( format ! ( "Cyclic feature dependency: feature `{}` \
465
- depends on itself", feat) ) )
466
- }
467
- used. insert ( feat. to_string ( ) ) ;
468
- match s. get_features ( ) . find_equiv ( & feat) {
469
- Some ( recursive) => {
470
- for f in recursive. iter ( ) {
471
- try!( add_feature ( s, f. as_slice ( ) , deps, used, visited) ) ;
505
+ if feat. is_empty ( ) { return Ok ( ( ) ) }
506
+
507
+ // If this feature is of the form `foo/bar`, then we just lookup package
508
+ // `foo` and enable its feature `bar`. Otherwise this feature is of the
509
+ // form `foo` and we need to recurse to enable the feature `foo` for our
510
+ // own package, which may end up enabling more features or just enabling
511
+ // a dependency.
512
+ let mut parts = feat. splitn ( 1 , '/' ) ;
513
+ let feat_or_package = parts. next ( ) . unwrap ( ) ;
514
+ match parts. next ( ) {
515
+ Some ( feat) => {
516
+ let package = feat_or_package;
517
+ match deps. entry ( package. to_string ( ) ) {
518
+ Occupied ( e) => e. into_mut ( ) ,
519
+ Vacant ( e) => e. set ( Vec :: new ( ) ) ,
520
+ } . push ( feat. to_string ( ) ) ;
521
+ }
522
+ None => {
523
+ let feat = feat_or_package;
524
+ if !visited. insert ( feat. to_string ( ) ) {
525
+ return Err ( human ( format ! ( "Cyclic feature dependency: \
526
+ feature `{}` depends on itself",
527
+ feat) ) )
528
+ }
529
+ used. insert ( feat. to_string ( ) ) ;
530
+ match s. get_features ( ) . find_equiv ( & feat) {
531
+ Some ( recursive) => {
532
+ for f in recursive. iter ( ) {
533
+ try!( add_feature ( s, f. as_slice ( ) , deps, used,
534
+ visited) ) ;
535
+ }
536
+ }
537
+ None => {
538
+ match deps. entry ( feat. to_string ( ) ) {
539
+ Occupied ( ..) => { } // already activated
540
+ Vacant ( e) => { e. set ( Vec :: new ( ) ) ; }
541
+ }
542
+ }
472
543
}
544
+ visited. remove ( & feat. to_string ( ) ) ;
473
545
}
474
- None => { deps. insert ( feat. to_string ( ) ) ; }
475
546
}
476
- visited. remove ( & feat. to_string ( ) ) ;
477
547
Ok ( ( ) )
478
548
}
479
549
}
0 commit comments