@@ -177,6 +177,10 @@ impl FeatureOpts {
177
177
if let ForceAllTargets :: Yes = force_all_targets {
178
178
opts. ignore_inactive_targets = false ;
179
179
}
180
+ if unstable_flags. weak_dep_features {
181
+ // Force this ON because it only works with the new resolver.
182
+ opts. new_resolver = true ;
183
+ }
180
184
Ok ( opts)
181
185
}
182
186
}
@@ -311,6 +315,15 @@ pub struct FeatureResolver<'a, 'cfg> {
311
315
/// This has to be separate from `FeatureOpts.decouple_host_deps` because
312
316
/// `for_host` tracking is also needed for `itarget` to work properly.
313
317
track_for_host : bool ,
318
+ /// `dep_name?/feat_name` features that will be activated if `dep_name` is
319
+ /// ever activated.
320
+ ///
321
+ /// The key is the `(package, for_host, dep_name)` of the package whose
322
+ /// dependency will trigger the addition of new features. The value is the
323
+ /// set of `(feature, dep_prefix)` features to activate (`dep_prefix` is a
324
+ /// bool that indicates if `dep:` prefix was used).
325
+ deferred_weak_dependencies :
326
+ HashMap < ( PackageId , bool , InternedString ) , HashSet < ( InternedString , bool ) > > ,
314
327
}
315
328
316
329
impl < ' a , ' cfg > FeatureResolver < ' a , ' cfg > {
@@ -353,6 +366,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
353
366
activated_dependencies : HashMap :: new ( ) ,
354
367
processed_deps : HashSet :: new ( ) ,
355
368
track_for_host,
369
+ deferred_weak_dependencies : HashMap :: new ( ) ,
356
370
} ;
357
371
r. do_resolve ( specs, requested_features) ?;
358
372
log:: debug!( "features={:#?}" , r. activated_features) ;
@@ -378,7 +392,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
378
392
for ( member, requested_features) in & member_features {
379
393
let fvs = self . fvs_from_requested ( member. package_id ( ) , requested_features) ;
380
394
let for_host = self . track_for_host && self . is_proc_macro ( member. package_id ( ) ) ;
381
- self . activate_pkg ( member. package_id ( ) , & fvs , for_host ) ?;
395
+ self . activate_pkg ( member. package_id ( ) , for_host , & fvs ) ?;
382
396
if for_host {
383
397
// Also activate without for_host. This is needed if the
384
398
// proc-macro includes other targets (like binaries or tests),
@@ -387,7 +401,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
387
401
// `--workspace`), this forces feature unification with normal
388
402
// dependencies. This is part of the bigger problem where
389
403
// features depend on which packages are built.
390
- self . activate_pkg ( member. package_id ( ) , & fvs , false ) ?;
404
+ self . activate_pkg ( member. package_id ( ) , false , & fvs ) ?;
391
405
}
392
406
}
393
407
Ok ( ( ) )
@@ -396,17 +410,18 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
396
410
fn activate_pkg (
397
411
& mut self ,
398
412
pkg_id : PackageId ,
399
- fvs : & [ FeatureValue ] ,
400
413
for_host : bool ,
414
+ fvs : & [ FeatureValue ] ,
401
415
) -> CargoResult < ( ) > {
416
+ log:: trace!( "activate_pkg {} {}" , pkg_id. name( ) , for_host) ;
402
417
// Add an empty entry to ensure everything is covered. This is intended for
403
418
// finding bugs where the resolver missed something it should have visited.
404
419
// Remove this in the future if `activated_features` uses an empty default.
405
420
self . activated_features
406
421
. entry ( ( pkg_id, self . opts . decouple_host_deps && for_host) )
407
422
. or_insert_with ( BTreeSet :: new) ;
408
423
for fv in fvs {
409
- self . activate_fv ( pkg_id, fv , for_host ) ?;
424
+ self . activate_fv ( pkg_id, for_host , fv ) ?;
410
425
}
411
426
if !self . processed_deps . insert ( ( pkg_id, for_host) ) {
412
427
// Already processed dependencies. There's no need to process them
@@ -433,7 +448,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
433
448
}
434
449
// Recurse into the dependency.
435
450
let fvs = self . fvs_from_dependency ( dep_pkg_id, dep) ;
436
- self . activate_pkg ( dep_pkg_id, & fvs , dep_for_host ) ?;
451
+ self . activate_pkg ( dep_pkg_id, dep_for_host , & fvs ) ?;
437
452
}
438
453
}
439
454
Ok ( ( ) )
@@ -443,59 +458,31 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
443
458
fn activate_fv (
444
459
& mut self ,
445
460
pkg_id : PackageId ,
446
- fv : & FeatureValue ,
447
461
for_host : bool ,
462
+ fv : & FeatureValue ,
448
463
) -> CargoResult < ( ) > {
464
+ log:: trace!( "activate_fv {} {} {}" , pkg_id. name( ) , for_host, fv) ;
449
465
match fv {
450
466
FeatureValue :: Feature ( f) => {
451
- self . activate_rec ( pkg_id, * f , for_host ) ?;
467
+ self . activate_rec ( pkg_id, for_host , * f ) ?;
452
468
}
453
469
FeatureValue :: Dep { dep_name } => {
454
- // Mark this dependency as activated.
455
- self . activated_dependencies
456
- . entry ( ( pkg_id, self . opts . decouple_host_deps && for_host) )
457
- . or_default ( )
458
- . insert ( * dep_name) ;
459
- // Activate the optional dep.
460
- for ( dep_pkg_id, deps) in self . deps ( pkg_id, for_host) {
461
- for ( dep, dep_for_host) in deps {
462
- if dep. name_in_toml ( ) != * dep_name {
463
- continue ;
464
- }
465
- let fvs = self . fvs_from_dependency ( dep_pkg_id, dep) ;
466
- self . activate_pkg ( dep_pkg_id, & fvs, dep_for_host) ?;
467
- }
468
- }
470
+ self . activate_dependency ( pkg_id, for_host, * dep_name) ?;
469
471
}
470
472
FeatureValue :: DepFeature {
471
473
dep_name,
472
474
dep_feature,
473
475
dep_prefix,
476
+ weak,
474
477
} => {
475
- // Activate a feature within a dependency.
476
- for ( dep_pkg_id, deps) in self . deps ( pkg_id, for_host) {
477
- for ( dep, dep_for_host) in deps {
478
- if dep. name_in_toml ( ) != * dep_name {
479
- continue ;
480
- }
481
- if dep. is_optional ( ) {
482
- // Activate the dependency on self.
483
- let fv = FeatureValue :: Dep {
484
- dep_name : * dep_name,
485
- } ;
486
- self . activate_fv ( pkg_id, & fv, for_host) ?;
487
- if !dep_prefix {
488
- // To retain compatibility with old behavior,
489
- // this also enables a feature of the same
490
- // name.
491
- self . activate_rec ( pkg_id, * dep_name, for_host) ?;
492
- }
493
- }
494
- // Activate the feature on the dependency.
495
- let fv = FeatureValue :: new ( * dep_feature) ;
496
- self . activate_fv ( dep_pkg_id, & fv, dep_for_host) ?;
497
- }
498
- }
478
+ self . activate_dep_feature (
479
+ pkg_id,
480
+ for_host,
481
+ * dep_name,
482
+ * dep_feature,
483
+ * dep_prefix,
484
+ * weak,
485
+ ) ?;
499
486
}
500
487
}
501
488
Ok ( ( ) )
@@ -506,9 +493,15 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
506
493
fn activate_rec (
507
494
& mut self ,
508
495
pkg_id : PackageId ,
509
- feature_to_enable : InternedString ,
510
496
for_host : bool ,
497
+ feature_to_enable : InternedString ,
511
498
) -> CargoResult < ( ) > {
499
+ log:: trace!(
500
+ "activate_rec {} {} feat={}" ,
501
+ pkg_id. name( ) ,
502
+ for_host,
503
+ feature_to_enable
504
+ ) ;
512
505
let enabled = self
513
506
. activated_features
514
507
. entry ( ( pkg_id, self . opts . decouple_host_deps && for_host) )
@@ -534,7 +527,111 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
534
527
}
535
528
} ;
536
529
for fv in fvs {
537
- self . activate_fv ( pkg_id, fv, for_host) ?;
530
+ self . activate_fv ( pkg_id, for_host, fv) ?;
531
+ }
532
+ Ok ( ( ) )
533
+ }
534
+
535
+ /// Activate a dependency (`dep:dep_name` syntax).
536
+ fn activate_dependency (
537
+ & mut self ,
538
+ pkg_id : PackageId ,
539
+ for_host : bool ,
540
+ dep_name : InternedString ,
541
+ ) -> CargoResult < ( ) > {
542
+ // Mark this dependency as activated.
543
+ let save_for_host = self . opts . decouple_host_deps && for_host;
544
+ self . activated_dependencies
545
+ . entry ( ( pkg_id, save_for_host) )
546
+ . or_default ( )
547
+ . insert ( dep_name) ;
548
+ // Check for any deferred features.
549
+ let to_enable = self
550
+ . deferred_weak_dependencies
551
+ . remove ( & ( pkg_id, for_host, dep_name) ) ;
552
+ // Activate the optional dep.
553
+ for ( dep_pkg_id, deps) in self . deps ( pkg_id, for_host) {
554
+ for ( dep, dep_for_host) in deps {
555
+ if dep. name_in_toml ( ) != dep_name {
556
+ continue ;
557
+ }
558
+ if let Some ( to_enable) = & to_enable {
559
+ for ( dep_feature, dep_prefix) in to_enable {
560
+ log:: trace!(
561
+ "activate deferred {} {} -> {}/{}" ,
562
+ pkg_id. name( ) ,
563
+ for_host,
564
+ dep_name,
565
+ dep_feature
566
+ ) ;
567
+ if !dep_prefix {
568
+ self . activate_rec ( pkg_id, for_host, dep_name) ?;
569
+ }
570
+ let fv = FeatureValue :: new ( * dep_feature) ;
571
+ self . activate_fv ( dep_pkg_id, dep_for_host, & fv) ?;
572
+ }
573
+ }
574
+ let fvs = self . fvs_from_dependency ( dep_pkg_id, dep) ;
575
+ self . activate_pkg ( dep_pkg_id, dep_for_host, & fvs) ?;
576
+ }
577
+ }
578
+ Ok ( ( ) )
579
+ }
580
+
581
+ /// Activate a feature within a dependency (`dep_name/feat_name` syntax).
582
+ fn activate_dep_feature (
583
+ & mut self ,
584
+ pkg_id : PackageId ,
585
+ for_host : bool ,
586
+ dep_name : InternedString ,
587
+ dep_feature : InternedString ,
588
+ dep_prefix : bool ,
589
+ weak : bool ,
590
+ ) -> CargoResult < ( ) > {
591
+ for ( dep_pkg_id, deps) in self . deps ( pkg_id, for_host) {
592
+ for ( dep, dep_for_host) in deps {
593
+ if dep. name_in_toml ( ) != dep_name {
594
+ continue ;
595
+ }
596
+ if dep. is_optional ( ) {
597
+ let save_for_host = self . opts . decouple_host_deps && for_host;
598
+ if weak
599
+ && !self
600
+ . activated_dependencies
601
+ . get ( & ( pkg_id, save_for_host) )
602
+ . map ( |deps| deps. contains ( & dep_name) )
603
+ . unwrap_or ( false )
604
+ {
605
+ // This is weak, but not yet activated. Defer in case
606
+ // something comes along later and enables it.
607
+ log:: trace!(
608
+ "deferring feature {} {} -> {}/{}" ,
609
+ pkg_id. name( ) ,
610
+ for_host,
611
+ dep_name,
612
+ dep_feature
613
+ ) ;
614
+ self . deferred_weak_dependencies
615
+ . entry ( ( pkg_id, for_host, dep_name) )
616
+ . or_default ( )
617
+ . insert ( ( dep_feature, dep_prefix) ) ;
618
+ continue ;
619
+ }
620
+
621
+ // Activate the dependency on self.
622
+ let fv = FeatureValue :: Dep { dep_name } ;
623
+ self . activate_fv ( pkg_id, for_host, & fv) ?;
624
+ if !dep_prefix {
625
+ // To retain compatibility with old behavior,
626
+ // this also enables a feature of the same
627
+ // name.
628
+ self . activate_rec ( pkg_id, for_host, dep_name) ?;
629
+ }
630
+ }
631
+ // Activate the feature on the dependency.
632
+ let fv = FeatureValue :: new ( dep_feature) ;
633
+ self . activate_fv ( dep_pkg_id, dep_for_host, & fv) ?;
634
+ }
538
635
}
539
636
Ok ( ( ) )
540
637
}
0 commit comments