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