77//! Everything here is basically just a shim around calling either `rustbook` or
88//! `rustdoc`.
99
10+ use std:: ffi:: OsStr ;
1011use std:: fs;
1112use std:: io;
1213use std:: path:: { Path , PathBuf } ;
@@ -425,49 +426,24 @@ impl Step for Std {
425426 fn run ( self , builder : & Builder < ' _ > ) {
426427 let stage = self . stage ;
427428 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- }
435429 let out = builder. doc_out ( target) ;
436430 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-
441431 t ! ( fs:: copy( builder. src. join( "src/doc/rust.css" ) , out. join( "rust.css" ) ) ) ;
442432
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+ }
469445
470- let paths = builder
446+ let requested_crates = builder
471447 . paths
472448 . iter ( )
473449 . map ( components_simplified)
@@ -485,37 +461,155 @@ impl Step for Std {
485461 } )
486462 . collect :: < Vec < _ > > ( ) ;
487463
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+ ) ;
507473
508474 // Look for library/std, library/core etc in the `x.py doc` arguments and
509475 // 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 ( ) ) {
512478 let index = out. join ( requested_crate) . join ( "index.html" ) ;
513479 open ( builder, & index) ;
514480 }
515481 }
516482 }
517483}
518484
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+
519613#[ derive( Debug , Copy , Clone , Hash , PartialEq , Eq ) ]
520614pub struct Rustc {
521615 pub stage : u32 ,
0 commit comments