7
7
//! Everything here is basically just a shim around calling either `rustbook` or
8
8
//! `rustdoc`.
9
9
10
+ use std:: ffi:: OsStr ;
10
11
use std:: fs;
11
12
use std:: io;
12
13
use std:: path:: { Path , PathBuf } ;
@@ -431,49 +432,24 @@ impl Step for Std {
431
432
fn run ( self , builder : & Builder < ' _ > ) {
432
433
let stage = self . stage ;
433
434
let target = self . target ;
434
- builder. info ( & format ! ( "Documenting stage{} std ({})" , stage, target) ) ;
435
- if builder. no_std ( target) == Some ( true ) {
436
- panic ! (
437
- "building std documentation for no_std target {target} is not supported\n \
438
- Set `docs = false` in the config to disable documentation."
439
- ) ;
440
- }
441
435
let out = builder. doc_out ( target) ;
442
436
t ! ( fs:: create_dir_all( & out) ) ;
443
- let compiler = builder. compiler ( stage, builder. config . build ) ;
444
-
445
- let out_dir = builder. stage_out ( compiler, Mode :: Std ) . join ( target. triple ) . join ( "doc" ) ;
446
-
447
437
t ! ( fs:: copy( builder. src. join( "src/doc/rust.css" ) , out. join( "rust.css" ) ) ) ;
448
438
449
- let run_cargo_rustdoc_for = |package : & str | {
450
- let mut cargo =
451
- builder. cargo ( compiler, Mode :: Std , SourceType :: InTree , target, "rustdoc" ) ;
452
- compile:: std_cargo ( builder, target, compiler. stage , & mut cargo) ;
453
-
454
- cargo
455
- . arg ( "-p" )
456
- . arg ( package)
457
- . arg ( "-Zskip-rustdoc-fingerprint" )
458
- . arg ( "--" )
459
- . arg ( "--markdown-css" )
460
- . arg ( "rust.css" )
461
- . arg ( "--markdown-no-toc" )
462
- . arg ( "-Z" )
463
- . arg ( "unstable-options" )
464
- . arg ( "--resource-suffix" )
465
- . arg ( & builder. version )
466
- . arg ( "--index-page" )
467
- . arg ( & builder. src . join ( "src/doc/index.md" ) ) ;
468
-
469
- if !builder. config . docs_minification {
470
- cargo. arg ( "--disable-minification" ) ;
471
- }
472
-
473
- builder. run ( & mut cargo. into ( ) ) ;
474
- } ;
439
+ let index_page = builder. src . join ( "src/doc/index.md" ) . into_os_string ( ) ;
440
+ let mut extra_args = vec ! [
441
+ OsStr :: new( "--markdown-css" ) ,
442
+ OsStr :: new( "rust.css" ) ,
443
+ OsStr :: new( "--markdown-no-toc" ) ,
444
+ OsStr :: new( "--index-page" ) ,
445
+ & index_page,
446
+ ] ;
447
+
448
+ if !builder. config . docs_minification {
449
+ extra_args. push ( OsStr :: new ( "--disable-minification" ) ) ;
450
+ }
475
451
476
- let paths = builder
452
+ let requested_crates = builder
477
453
. paths
478
454
. iter ( )
479
455
. map ( components_simplified)
@@ -491,37 +467,155 @@ impl Step for Std {
491
467
} )
492
468
. collect :: < Vec < _ > > ( ) ;
493
469
494
- // Only build the following crates. While we could just iterate over the
495
- // folder structure, that would also build internal crates that we do
496
- // not want to show in documentation. These crates will later be visited
497
- // by the rustc step, so internal documentation will show them.
498
- //
499
- // Note that the order here is important! The crates need to be
500
- // processed starting from the leaves, otherwise rustdoc will not
501
- // create correct links between crates because rustdoc depends on the
502
- // existence of the output directories to know if it should be a local
503
- // or remote link.
504
- let krates = [ "core" , "alloc" , "std" , "proc_macro" , "test" ] ;
505
- for krate in & krates {
506
- run_cargo_rustdoc_for ( krate) ;
507
- if paths. iter ( ) . any ( |p| p == krate) {
508
- // No need to document more of the libraries if we have the one we want.
509
- break ;
510
- }
511
- }
512
- builder. cp_r ( & out_dir, & out) ;
470
+ doc_std (
471
+ builder,
472
+ DocumentationFormat :: HTML ,
473
+ stage,
474
+ target,
475
+ & out,
476
+ & extra_args,
477
+ & requested_crates,
478
+ ) ;
513
479
514
480
// Look for library/std, library/core etc in the `x.py doc` arguments and
515
481
// open the corresponding rendered docs.
516
- for requested_crate in paths {
517
- if krates . iter ( ) . any ( |k| * k == requested_crate. as_str ( ) ) {
482
+ for requested_crate in requested_crates {
483
+ if STD_PUBLIC_CRATES . iter ( ) . any ( |k| * k == requested_crate. as_str ( ) ) {
518
484
let index = out. join ( requested_crate) . join ( "index.html" ) ;
519
485
open ( builder, & index) ;
520
486
}
521
487
}
522
488
}
523
489
}
524
490
491
+ #[ derive( Debug , Copy , Clone , Hash , PartialEq , Eq ) ]
492
+ pub struct JsonStd {
493
+ pub stage : u32 ,
494
+ pub target : TargetSelection ,
495
+ }
496
+
497
+ impl Step for JsonStd {
498
+ type Output = ( ) ;
499
+ const DEFAULT : bool = false ;
500
+
501
+ fn should_run ( run : ShouldRun < ' _ > ) -> ShouldRun < ' _ > {
502
+ let default = run. builder . config . docs && run. builder . config . cmd . json ( ) ;
503
+ run. all_krates ( "test" ) . path ( "library" ) . default_condition ( default)
504
+ }
505
+
506
+ fn make_run ( run : RunConfig < ' _ > ) {
507
+ run. builder . ensure ( Std { stage : run. builder . top_stage , target : run. target } ) ;
508
+ }
509
+
510
+ /// Build JSON documentation for the standard library crates.
511
+ ///
512
+ /// This is largely just a wrapper around `cargo doc`.
513
+ fn run ( self , builder : & Builder < ' _ > ) {
514
+ let stage = self . stage ;
515
+ let target = self . target ;
516
+ let out = builder. json_doc_out ( target) ;
517
+ t ! ( fs:: create_dir_all( & out) ) ;
518
+ let extra_args = [ OsStr :: new ( "--output-format" ) , OsStr :: new ( "json" ) ] ;
519
+ doc_std ( builder, DocumentationFormat :: JSON , stage, target, & out, & extra_args, & [ ] )
520
+ }
521
+ }
522
+
523
+ /// Name of the crates that are visible to consumers of the standard library.
524
+ /// Documentation for internal crates is handled by the rustc step, so internal crates will show
525
+ /// up there.
526
+ ///
527
+ /// Order here is important!
528
+ /// Crates need to be processed starting from the leaves, otherwise rustdoc will not
529
+ /// create correct links between crates because rustdoc depends on the
530
+ /// existence of the output directories to know if it should be a local
531
+ /// or remote link.
532
+ const STD_PUBLIC_CRATES : [ & str ; 5 ] = [ "core" , "alloc" , "std" , "proc_macro" , "test" ] ;
533
+
534
+ #[ derive( Debug , Copy , Clone , Hash , PartialEq , Eq ) ]
535
+ enum DocumentationFormat {
536
+ HTML ,
537
+ JSON ,
538
+ }
539
+
540
+ impl DocumentationFormat {
541
+ fn as_str ( & self ) -> & str {
542
+ match self {
543
+ DocumentationFormat :: HTML => "HTML" ,
544
+ DocumentationFormat :: JSON => "JSON" ,
545
+ }
546
+ }
547
+ }
548
+
549
+ /// Build the documentation for public standard library crates.
550
+ ///
551
+ /// `requested_crates` can be used to build only a subset of the crates. If empty, all crates will
552
+ /// be built.
553
+ fn doc_std (
554
+ builder : & Builder < ' _ > ,
555
+ format : DocumentationFormat ,
556
+ stage : u32 ,
557
+ target : TargetSelection ,
558
+ out : & Path ,
559
+ extra_args : & [ & OsStr ] ,
560
+ requested_crates : & [ String ] ,
561
+ ) {
562
+ builder. info ( & format ! (
563
+ "Documenting stage{} std ({}) in {} format" ,
564
+ stage,
565
+ target,
566
+ format. as_str( )
567
+ ) ) ;
568
+ if builder. no_std ( target) == Some ( true ) {
569
+ panic ! (
570
+ "building std documentation for no_std target {target} is not supported\n \
571
+ Set `docs = false` in the config to disable documentation."
572
+ ) ;
573
+ }
574
+ let compiler = builder. compiler ( stage, builder. config . build ) ;
575
+ // This is directory where the compiler will place the output of the command.
576
+ // We will then copy the files from this directory into the final `out` directory, the specified
577
+ // as a function parameter.
578
+ let out_dir = builder. stage_out ( compiler, Mode :: Std ) . join ( target. triple ) . join ( "doc" ) ;
579
+ // `cargo` uses the same directory for both JSON docs and HTML docs.
580
+ // This could lead to cross-contamination when copying files into the specified `out` directory.
581
+ // For example:
582
+ // ```bash
583
+ // x doc std
584
+ // x doc std --json
585
+ // ```
586
+ // could lead to HTML docs being copied into the JSON docs output directory.
587
+ // To avoid this issue, we clean the doc folder before invoking `cargo`.
588
+ if out_dir. exists ( ) {
589
+ builder. remove_dir ( & out_dir) ;
590
+ }
591
+
592
+ let run_cargo_rustdoc_for = |package : & str | {
593
+ let mut cargo = builder. cargo ( compiler, Mode :: Std , SourceType :: InTree , target, "rustdoc" ) ;
594
+ compile:: std_cargo ( builder, target, compiler. stage , & mut cargo) ;
595
+ cargo
596
+ . arg ( "-p" )
597
+ . arg ( package)
598
+ . arg ( "-Zskip-rustdoc-fingerprint" )
599
+ . arg ( "--" )
600
+ . arg ( "-Z" )
601
+ . arg ( "unstable-options" )
602
+ . arg ( "--resource-suffix" )
603
+ . arg ( & builder. version )
604
+ . args ( extra_args) ;
605
+ builder. run ( & mut cargo. into ( ) ) ;
606
+ } ;
607
+
608
+ for krate in STD_PUBLIC_CRATES {
609
+ run_cargo_rustdoc_for ( krate) ;
610
+ if requested_crates. iter ( ) . any ( |p| p == krate) {
611
+ // No need to document more of the libraries if we have the one we want.
612
+ break ;
613
+ }
614
+ }
615
+
616
+ builder. cp_r ( & out_dir, & out) ;
617
+ }
618
+
525
619
#[ derive( Debug , Copy , Clone , Hash , PartialEq , Eq ) ]
526
620
pub struct Rustc {
527
621
pub stage : u32 ,
0 commit comments