@@ -41,6 +41,7 @@ use crate::core::compiler::{standard_lib, CrateType, TargetInfo};
41
41
use crate :: core:: compiler:: { BuildConfig , BuildContext , Compilation , Context } ;
42
42
use crate :: core:: compiler:: { CompileKind , CompileMode , CompileTarget , RustcTargetData , Unit } ;
43
43
use crate :: core:: compiler:: { DefaultExecutor , Executor , UnitInterner } ;
44
+ use crate :: core:: dependency:: DepKind ;
44
45
use crate :: core:: profiles:: { Profiles , UnitFor } ;
45
46
use crate :: core:: resolver:: features:: { self , CliFeatures , FeaturesFor } ;
46
47
use crate :: core:: resolver:: { HasDevUnits , Resolve } ;
@@ -361,6 +362,7 @@ pub fn create_bcx<'a, 'cfg>(
361
362
& pkg_set,
362
363
& profiles,
363
364
interner,
365
+ has_dev_units,
364
366
) ?;
365
367
366
368
if let Some ( args) = target_rustc_crate_types {
@@ -369,11 +371,10 @@ pub fn create_bcx<'a, 'cfg>(
369
371
370
372
let should_scrape = build_config. mode . is_doc ( ) && config. cli_unstable ( ) . rustdoc_scrape_examples ;
371
373
let mut scrape_units = if should_scrape {
372
- let scrape_filter = filter. refine_for_docscrape ( & to_builds, has_dev_units) ;
373
374
let all_units = generate_targets (
374
375
ws,
375
376
& to_builds,
376
- & scrape_filter ,
377
+ & filter ,
377
378
& build_config. requested_kinds ,
378
379
explicit_host_kind,
379
380
CompileMode :: Docscrape ,
@@ -383,6 +384,7 @@ pub fn create_bcx<'a, 'cfg>(
383
384
& pkg_set,
384
385
& profiles,
385
386
interner,
387
+ has_dev_units,
386
388
) ?;
387
389
388
390
// The set of scraped targets should be a strict subset of the set of documented targets,
@@ -397,10 +399,11 @@ pub fn create_bcx<'a, 'cfg>(
397
399
let valid_units = all_units
398
400
. into_iter ( )
399
401
. filter ( |unit| {
400
- !matches ! (
401
- unit. target. doc_scrape_examples( ) ,
402
- RustdocScrapeExamples :: Disabled
403
- )
402
+ ws. unit_needs_doc_scrape ( unit)
403
+ && !matches ! (
404
+ unit. target. doc_scrape_examples( ) ,
405
+ RustdocScrapeExamples :: Disabled
406
+ )
404
407
} )
405
408
. collect :: < Vec < _ > > ( ) ;
406
409
valid_units
@@ -597,6 +600,7 @@ fn generate_targets(
597
600
package_set : & PackageSet < ' _ > ,
598
601
profiles : & Profiles ,
599
602
interner : & UnitInterner ,
603
+ has_dev_units : HasDevUnits ,
600
604
) -> CargoResult < Vec < Unit > > {
601
605
let config = ws. config ( ) ;
602
606
// Helper for creating a list of `Unit` structures
@@ -828,6 +832,52 @@ fn generate_targets(
828
832
}
829
833
}
830
834
835
+ if mode. is_doc_scrape ( ) {
836
+ // In general, the goal is to scrape examples from (a) whatever targets
837
+ // the user is documenting, and (b) Example targets. However, if the user
838
+ // is documenting a library with dev-dependencies, those dev-deps are not
839
+ // needed for the library, while dev-deps are needed for the examples.
840
+ //
841
+ // If scrape-examples caused `cargo doc` to start requiring dev-deps, this
842
+ // would be a breaking change to crates whose dev-deps don't compile.
843
+ // Therefore we ONLY want to scrape Example targets if either:
844
+ // (1) No package has dev-dependencies, so this is a moot issue, OR
845
+ // (2) The provided CompileFilter requires dev-dependencies anyway.
846
+ //
847
+ // The next two variables represent these two conditions.
848
+ let no_pkg_has_dev_deps = packages. iter ( ) . all ( |pkg| {
849
+ pkg. summary ( )
850
+ . dependencies ( )
851
+ . iter ( )
852
+ . all ( |dep| !matches ! ( dep. kind( ) , DepKind :: Development ) )
853
+ } ) ;
854
+ let reqs_dev_deps = matches ! ( has_dev_units, HasDevUnits :: Yes ) ;
855
+ let safe_to_scrape_example_targets = no_pkg_has_dev_deps || reqs_dev_deps;
856
+
857
+ let proposed_targets: HashSet < & Target > = proposals. iter ( ) . map ( |p| p. target ) . collect ( ) ;
858
+ let can_scrape = |target : & Target | {
859
+ let not_redundant = !proposed_targets. contains ( target) ;
860
+ not_redundant
861
+ && match ( target. doc_scrape_examples ( ) , target. is_example ( ) ) {
862
+ // Targets configured by the user to not be scraped should never be scraped
863
+ ( RustdocScrapeExamples :: Disabled , _) => false ,
864
+ // Targets configured by the user to be scraped should always be scraped
865
+ ( RustdocScrapeExamples :: Enabled , _) => true ,
866
+ // Example targets with no configuration should be conditionally scraped if
867
+ // it's guaranteed not to break the build
868
+ ( RustdocScrapeExamples :: Unset , true ) => safe_to_scrape_example_targets,
869
+ // All other targets are ignored for now. This may change in the future!
870
+ ( RustdocScrapeExamples :: Unset , false ) => false ,
871
+ }
872
+ } ;
873
+ proposals. extend ( filter_targets (
874
+ packages,
875
+ can_scrape,
876
+ false ,
877
+ CompileMode :: Docscrape ,
878
+ ) ) ;
879
+ }
880
+
831
881
// Only include targets that are libraries or have all required
832
882
// features available.
833
883
//
@@ -1074,7 +1124,7 @@ fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target>
1074
1124
. iter ( )
1075
1125
. filter ( |t| t. is_bin ( ) || t. is_lib ( ) )
1076
1126
. collect ( ) ,
1077
- CompileMode :: Doc { .. } => {
1127
+ CompileMode :: Doc { .. } | CompileMode :: Docscrape => {
1078
1128
// `doc` does lib and bins (bin with same name as lib is skipped).
1079
1129
targets
1080
1130
. iter ( )
@@ -1085,7 +1135,7 @@ fn filter_default_targets(targets: &[Target], mode: CompileMode) -> Vec<&Target>
1085
1135
} )
1086
1136
. collect ( )
1087
1137
}
1088
- CompileMode :: Doctest | CompileMode :: Docscrape | CompileMode :: RunCustomBuild => {
1138
+ CompileMode :: Doctest | CompileMode :: RunCustomBuild => {
1089
1139
panic ! ( "Invalid mode {:?}" , mode)
1090
1140
}
1091
1141
}
0 commit comments