@@ -5,6 +5,7 @@ use std::fmt;
5
5
use std:: fs;
6
6
use std:: io:: ErrorKind ;
7
7
use std:: io:: Write ;
8
+ use std:: iter;
8
9
use std:: path:: Path ;
9
10
10
11
use toml_edit:: InlineTable ;
@@ -389,33 +390,76 @@ see that for related crates.", self.data.krate)?;
389
390
}
390
391
391
392
let mut emitted_features = self . emitted_features ( config) ;
392
- let _ = emitted_features. insert (
393
- "all" . to_string ( ) ,
394
- emitted_features. keys ( ) . cloned ( ) . collect :: < BTreeSet < _ > > ( ) ,
393
+
394
+ // All features are enabled by default, except for frameworks that
395
+ // would bump the minimum version of the library.
396
+ //
397
+ // The reasoning is that default features are meant for ease of use,
398
+ // especially so in end-user binaries and hobby projects. But we also
399
+ // don't want to make the user's binary incompatible with older OSes
400
+ // if they didn't explicitly opt-in to that.
401
+ //
402
+ // End result: The "only" cost is compilation time (vs. wasted
403
+ // developer time in finding each feature gate, or an unintentionally
404
+ // raised minimum OS version).
405
+ //
406
+ // And yes, libraries that use these crates _will_ want to disable
407
+ // default features, but that's the name of the game.
408
+ //
409
+ // We _could_ technically try to do something fancy to avoid e.g.
410
+ // `objc2-app-kit` pulling in `objc2-core-data`, since that is rarely
411
+ // needed, but where do we draw the line? And besides, that just masks
412
+ // the problem, library developers _should_ also disable the file
413
+ // features that they don't use if they really care about compilation
414
+ // time.
415
+ //
416
+ // See also https://github.com/madsmtm/objc2/issues/627.
417
+ let is_default_feature = |feature| {
418
+ if let Some ( lib) = config. try_library_from_crate ( feature) {
419
+ // Dependency feature
420
+ self . data . can_safely_depend_on ( lib) || !lib. link
421
+ } else {
422
+ // File feature
423
+ true
424
+ }
425
+ } ;
426
+ cargo_toml[ "features" ] [ "default" ] = array_with_newlines (
427
+ iter:: once ( "std" . to_string ( ) ) . chain (
428
+ emitted_features
429
+ . keys ( )
430
+ . filter ( |feature| is_default_feature ( feature) )
431
+ . cloned ( ) ,
432
+ ) ,
395
433
) ;
396
434
397
- // Emit crates first.
435
+ // Enable non-default features when building docs.
436
+ let non_default_features: Vec < _ > = emitted_features
437
+ . keys ( )
438
+ . filter ( |feature| !is_default_feature ( feature) )
439
+ . cloned ( )
440
+ . collect ( ) ;
441
+ if !non_default_features. is_empty ( ) {
442
+ cargo_toml[ "package" ] [ "metadata" ] [ "docs" ] [ "rs" ] [ "features" ] =
443
+ array_with_newlines ( non_default_features) ;
444
+ }
445
+
446
+ // Emit crate features first (the "default" feature overrides in
447
+ // `default_cargo.toml`).
398
448
for ( feature, _) in emitted_features. clone ( ) . iter ( ) {
399
449
if config. try_library_from_crate ( feature) . is_none ( ) {
400
450
continue ;
401
451
}
402
452
let enabled_features = emitted_features. remove ( feature) . unwrap ( ) ;
403
- let array: Array = enabled_features. iter ( ) . collect ( ) ;
404
- cargo_toml[ "features" ] [ feature] = value ( array) ;
453
+ cargo_toml[ "features" ] [ feature] = array_with_newlines ( enabled_features) ;
405
454
}
406
- add_newline_at_end ( & mut cargo_toml [ "features" ] ) ;
455
+
407
456
// And then the rest of the features.
457
+ if !emitted_features. is_empty ( ) {
458
+ add_newline_at_end ( & mut cargo_toml[ "features" ] ) ;
459
+ }
408
460
for ( feature, enabled_features) in emitted_features {
409
- let mut array: Array = enabled_features. into_iter ( ) . collect ( ) ;
410
- if 1 < array. len ( ) {
411
- for item in array. iter_mut ( ) {
412
- item. decor_mut ( ) . set_prefix ( "\n " ) ;
413
- }
414
- array. set_trailing ( "\n " ) ;
415
- array. set_trailing_comma ( true ) ;
416
- }
417
461
if cargo_toml[ "features" ] . get ( & feature) . is_none ( ) {
418
- cargo_toml[ "features" ] [ feature] = value ( array ) ;
462
+ cargo_toml[ "features" ] [ feature] = array_with_newlines ( enabled_features ) ;
419
463
}
420
464
}
421
465
@@ -546,6 +590,18 @@ fn add_newline_at_end(item: &mut Item) {
546
590
. set_suffix ( "\n " ) ;
547
591
}
548
592
593
+ fn array_with_newlines ( features : impl IntoIterator < Item = String > ) -> Item {
594
+ let mut array: Array = features. into_iter ( ) . collect ( ) ;
595
+ if 1 < array. len ( ) {
596
+ for item in array. iter_mut ( ) {
597
+ item. decor_mut ( ) . set_prefix ( "\n " ) ;
598
+ }
599
+ array. set_trailing ( "\n " ) ;
600
+ array. set_trailing_comma ( true ) ;
601
+ }
602
+ value ( array)
603
+ }
604
+
549
605
pub trait EntryExt < ' a > {
550
606
fn implicit_table ( self ) -> & ' a mut Table ;
551
607
}
0 commit comments