@@ -318,40 +318,7 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
318318 method : ResolveMethod ,
319319 ctx : & mut Context < ' a , R > )
320320 -> 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) ) ;
355322
356323 // Recursively resolve all dependencies
357324 for & dep in deps. iter ( ) {
@@ -409,8 +376,15 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
409376 depends on itself",
410377 summary. get_package_id( ) ) ) )
411378 }
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 ( & [ ] ) ;
412386 try!( resolve_deps ( summary,
413- ResolveRequired ( false , dep . get_features ( ) ,
387+ ResolveRequired ( false , features ,
414388 dep. uses_default_features ( ) ) ,
415389 ctx) ) ;
416390 if dep. is_transitive ( ) {
@@ -421,10 +395,81 @@ fn resolve_deps<'a, R: Registry>(parent: &Summary,
421395 Ok ( ( ) )
422396}
423397
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+
424461// 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.
425470fn 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 ( ) ;
428473 let mut used = HashSet :: new ( ) ;
429474 let mut visited = HashSet :: new ( ) ;
430475 match method {
@@ -454,26 +499,51 @@ fn build_features(s: &Summary, method: ResolveMethod)
454499 return Ok ( ( deps, used) ) ;
455500
456501 fn add_feature ( s : & Summary , feat : & str ,
457- deps : & mut HashSet < String > ,
502+ deps : & mut HashMap < String , Vec < String > > ,
458503 used : & mut HashSet < String > ,
459504 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+ }
472543 }
544+ visited. remove ( & feat. to_string ( ) ) ;
473545 }
474- None => { deps. insert ( feat. to_string ( ) ) ; }
475546 }
476- visited. remove ( & feat. to_string ( ) ) ;
477547 Ok ( ( ) )
478548 }
479549}
0 commit comments