| 1 | #![doc ( |
| 2 | html_root_url = "https://doc.rust-lang.org/nightly/" , |
| 3 | html_playground_url = "https://play.rust-lang.org/" |
| 4 | )] |
| 5 | #![feature (rustc_private)] |
| 6 | #![feature (assert_matches)] |
| 7 | #![feature (box_patterns)] |
| 8 | #![feature (debug_closure_helpers)] |
| 9 | #![feature (file_buffered)] |
| 10 | #![feature (format_args_nl)] |
| 11 | #![feature (if_let_guard)] |
| 12 | #![feature (impl_trait_in_assoc_type)] |
| 13 | #![feature (iter_intersperse)] |
| 14 | #![feature (let_chains)] |
| 15 | #![feature (never_type)] |
| 16 | #![feature (round_char_boundary)] |
| 17 | #![feature (test)] |
| 18 | #![feature (type_alias_impl_trait)] |
| 19 | #![feature (type_ascription)] |
| 20 | #![recursion_limit = "256" ] |
| 21 | #![warn (rustc::internal)] |
| 22 | #![allow (clippy::collapsible_if, clippy::collapsible_else_if)] |
| 23 | #![allow (rustc::diagnostic_outside_of_impl)] |
| 24 | #![allow (rustc::untranslatable_diagnostic)] |
| 25 | |
| 26 | extern crate thin_vec; |
| 27 | |
| 28 | // N.B. these need `extern crate` even in 2018 edition |
| 29 | // because they're loaded implicitly from the sysroot. |
| 30 | // The reason they're loaded from the sysroot is because |
| 31 | // the rustdoc artifacts aren't stored in rustc's cargo target directory. |
| 32 | // So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. |
| 33 | // |
| 34 | // Dependencies listed in Cargo.toml do not need `extern crate`. |
| 35 | |
| 36 | extern crate pulldown_cmark; |
| 37 | extern crate rustc_abi; |
| 38 | extern crate rustc_ast; |
| 39 | extern crate rustc_ast_pretty; |
| 40 | extern crate rustc_attr_parsing; |
| 41 | extern crate rustc_data_structures; |
| 42 | extern crate rustc_driver; |
| 43 | extern crate rustc_errors; |
| 44 | extern crate rustc_expand; |
| 45 | extern crate rustc_feature; |
| 46 | extern crate rustc_hir; |
| 47 | extern crate rustc_hir_analysis; |
| 48 | extern crate rustc_hir_pretty; |
| 49 | extern crate rustc_index; |
| 50 | extern crate rustc_infer; |
| 51 | extern crate rustc_interface; |
| 52 | extern crate rustc_lexer; |
| 53 | extern crate rustc_lint; |
| 54 | extern crate rustc_lint_defs; |
| 55 | extern crate rustc_log; |
| 56 | extern crate rustc_macros; |
| 57 | extern crate rustc_metadata; |
| 58 | extern crate rustc_middle; |
| 59 | extern crate rustc_parse; |
| 60 | extern crate rustc_passes; |
| 61 | extern crate rustc_resolve; |
| 62 | extern crate rustc_serialize; |
| 63 | extern crate rustc_session; |
| 64 | extern crate rustc_span; |
| 65 | extern crate rustc_target; |
| 66 | extern crate rustc_trait_selection; |
| 67 | extern crate test; |
| 68 | |
| 69 | // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs |
| 70 | // about jemalloc. |
| 71 | #[cfg (feature = "jemalloc" )] |
| 72 | extern crate tikv_jemalloc_sys as jemalloc_sys; |
| 73 | |
| 74 | use std::env::{self, VarError}; |
| 75 | use std::io::{self, IsTerminal}; |
| 76 | use std::process; |
| 77 | |
| 78 | use rustc_errors::DiagCtxtHandle; |
| 79 | use rustc_interface::interface; |
| 80 | use rustc_middle::ty::TyCtxt; |
| 81 | use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; |
| 82 | use rustc_session::{EarlyDiagCtxt, getopts}; |
| 83 | use tracing::info; |
| 84 | |
| 85 | use crate::clean::utils::DOC_RUST_LANG_ORG_VERSION; |
| 86 | |
| 87 | /// A macro to create a FxHashMap. |
| 88 | /// |
| 89 | /// Example: |
| 90 | /// |
| 91 | /// ```ignore(cannot-test-this-because-non-exported-macro) |
| 92 | /// let letters = map!{"a" => "b", "c" => "d"}; |
| 93 | /// ``` |
| 94 | /// |
| 95 | /// Trailing commas are allowed. |
| 96 | /// Commas between elements are required (even if the expression is a block). |
| 97 | macro_rules! map { |
| 98 | ($( $key: expr => $val: expr ),* $(,)*) => {{ |
| 99 | let mut map = ::rustc_data_structures::fx::FxIndexMap::default(); |
| 100 | $( map.insert($key, $val); )* |
| 101 | map |
| 102 | }} |
| 103 | } |
| 104 | |
| 105 | mod clean; |
| 106 | mod config; |
| 107 | mod core; |
| 108 | mod display; |
| 109 | mod docfs; |
| 110 | mod doctest; |
| 111 | mod error; |
| 112 | mod externalfiles; |
| 113 | mod fold; |
| 114 | mod formats; |
| 115 | // used by the error-index generator, so it needs to be public |
| 116 | pub mod html; |
| 117 | mod json; |
| 118 | pub(crate) mod lint; |
| 119 | mod markdown; |
| 120 | mod passes; |
| 121 | mod scrape_examples; |
| 122 | mod theme; |
| 123 | mod visit; |
| 124 | mod visit_ast; |
| 125 | mod visit_lib; |
| 126 | |
| 127 | pub fn main() { |
| 128 | // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs |
| 129 | // about jemalloc. |
| 130 | #[cfg (feature = "jemalloc" )] |
| 131 | { |
| 132 | use std::os::raw::{c_int, c_void}; |
| 133 | |
| 134 | #[used ] |
| 135 | static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc; |
| 136 | #[used ] |
| 137 | static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = |
| 138 | jemalloc_sys::posix_memalign; |
| 139 | #[used ] |
| 140 | static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc; |
| 141 | #[used ] |
| 142 | static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc; |
| 143 | #[used ] |
| 144 | static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc; |
| 145 | #[used ] |
| 146 | static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free; |
| 147 | |
| 148 | #[cfg (target_os = "macos" )] |
| 149 | { |
| 150 | unsafe extern "C" { |
| 151 | fn _rjem_je_zone_register(); |
| 152 | } |
| 153 | |
| 154 | #[used ] |
| 155 | static _F7: unsafe extern "C" fn() = _rjem_je_zone_register; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); |
| 160 | |
| 161 | rustc_driver::install_ice_hook( |
| 162 | "https://github.com/rust-lang/rust/issues/new\ |
| 163 | ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md" , |
| 164 | |_| (), |
| 165 | ); |
| 166 | |
| 167 | // When using CI artifacts with `download-rustc`, tracing is unconditionally built |
| 168 | // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid |
| 169 | // this, compile our own version of `tracing` that logs all levels. |
| 170 | // NOTE: this compiles both versions of tracing unconditionally, because |
| 171 | // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and |
| 172 | // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled |
| 173 | // NOTE: The reason this doesn't show double logging when `download-rustc = false` and |
| 174 | // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one |
| 175 | // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml). |
| 176 | |
| 177 | init_logging(&early_dcx); |
| 178 | rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG" )); |
| 179 | |
| 180 | let exit_code = rustc_driver::catch_with_exit_code(|| { |
| 181 | let at_args = rustc_driver::args::raw_args(&early_dcx); |
| 182 | main_args(&mut early_dcx, &at_args); |
| 183 | }); |
| 184 | process::exit(exit_code); |
| 185 | } |
| 186 | |
| 187 | fn init_logging(early_dcx: &EarlyDiagCtxt) { |
| 188 | let color_logs = match env::var("RUSTDOC_LOG_COLOR" ).as_deref() { |
| 189 | Ok("always" ) => true, |
| 190 | Ok("never" ) => false, |
| 191 | Ok("auto" ) | Err(VarError::NotPresent) => io::stdout().is_terminal(), |
| 192 | Ok(value) => early_dcx.early_fatal(format!( |
| 193 | "invalid log color value ' {value}': expected one of always, never, or auto" , |
| 194 | )), |
| 195 | Err(VarError::NotUnicode(value)) => early_dcx.early_fatal(format!( |
| 196 | "invalid log color value ' {}': expected one of always, never, or auto" , |
| 197 | value.to_string_lossy() |
| 198 | )), |
| 199 | }; |
| 200 | let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG" ); |
| 201 | let layer = tracing_tree::HierarchicalLayer::default() |
| 202 | .with_writer(io::stderr) |
| 203 | .with_ansi(color_logs) |
| 204 | .with_targets(true) |
| 205 | .with_wraparound(10) |
| 206 | .with_verbose_exit(true) |
| 207 | .with_verbose_entry(true) |
| 208 | .with_indent_amount(2); |
| 209 | #[cfg (debug_assertions)] |
| 210 | let layer = layer.with_thread_ids(true).with_thread_names(true); |
| 211 | |
| 212 | use tracing_subscriber::layer::SubscriberExt; |
| 213 | let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); |
| 214 | tracing::subscriber::set_global_default(subscriber).unwrap(); |
| 215 | } |
| 216 | |
| 217 | fn opts() -> Vec<RustcOptGroup> { |
| 218 | use rustc_session::config::OptionKind::{Flag, FlagMulti, Multi, Opt}; |
| 219 | use rustc_session::config::OptionStability::{Stable, Unstable}; |
| 220 | use rustc_session::config::make_opt as opt; |
| 221 | |
| 222 | vec![ |
| 223 | opt(Stable, FlagMulti, "h" , "help" , "show this help message" , "" ), |
| 224 | opt(Stable, FlagMulti, "V" , "version" , "print rustdoc's version" , "" ), |
| 225 | opt(Stable, FlagMulti, "v" , "verbose" , "use verbose output" , "" ), |
| 226 | opt(Stable, Opt, "w" , "output-format" , "the output type to write" , "[html]" ), |
| 227 | opt( |
| 228 | Stable, |
| 229 | Opt, |
| 230 | "" , |
| 231 | "output" , |
| 232 | "Which directory to place the output. This option is deprecated, use --out-dir instead." , |
| 233 | "PATH" , |
| 234 | ), |
| 235 | opt(Stable, Opt, "o" , "out-dir" , "which directory to place the output" , "PATH" ), |
| 236 | opt(Stable, Opt, "" , "crate-name" , "specify the name of this crate" , "NAME" ), |
| 237 | make_crate_type_option(), |
| 238 | opt(Stable, Multi, "L" , "library-path" , "directory to add to crate search path" , "DIR" ), |
| 239 | opt(Stable, Multi, "" , "cfg" , "pass a --cfg to rustc" , "" ), |
| 240 | opt(Stable, Multi, "" , "check-cfg" , "pass a --check-cfg to rustc" , "" ), |
| 241 | opt(Stable, Multi, "" , "extern" , "pass an --extern to rustc" , "NAME[=PATH]" ), |
| 242 | opt( |
| 243 | Unstable, |
| 244 | Multi, |
| 245 | "" , |
| 246 | "extern-html-root-url" , |
| 247 | "base URL to use for dependencies; for example, \ |
| 248 | \"std=/doc \" links std::vec::Vec to /doc/std/vec/struct.Vec.html" , |
| 249 | "NAME=URL" , |
| 250 | ), |
| 251 | opt( |
| 252 | Unstable, |
| 253 | FlagMulti, |
| 254 | "" , |
| 255 | "extern-html-root-takes-precedence" , |
| 256 | "give precedence to `--extern-html-root-url`, not `html_root_url`" , |
| 257 | "" , |
| 258 | ), |
| 259 | opt(Stable, Multi, "C" , "codegen" , "pass a codegen option to rustc" , "OPT[=VALUE]" ), |
| 260 | opt(Stable, FlagMulti, "" , "document-private-items" , "document private items" , "" ), |
| 261 | opt( |
| 262 | Unstable, |
| 263 | FlagMulti, |
| 264 | "" , |
| 265 | "document-hidden-items" , |
| 266 | "document items that have doc(hidden)" , |
| 267 | "" , |
| 268 | ), |
| 269 | opt(Stable, FlagMulti, "" , "test" , "run code examples as tests" , "" ), |
| 270 | opt(Stable, Multi, "" , "test-args" , "arguments to pass to the test runner" , "ARGS" ), |
| 271 | opt( |
| 272 | Stable, |
| 273 | Opt, |
| 274 | "" , |
| 275 | "test-run-directory" , |
| 276 | "The working directory in which to run tests" , |
| 277 | "PATH" , |
| 278 | ), |
| 279 | opt(Stable, Opt, "" , "target" , "target triple to document" , "TRIPLE" ), |
| 280 | opt( |
| 281 | Stable, |
| 282 | Multi, |
| 283 | "" , |
| 284 | "markdown-css" , |
| 285 | "CSS files to include via <link> in a rendered Markdown file" , |
| 286 | "FILES" , |
| 287 | ), |
| 288 | opt( |
| 289 | Stable, |
| 290 | Multi, |
| 291 | "" , |
| 292 | "html-in-header" , |
| 293 | "files to include inline in the <head> section of a rendered Markdown file \ |
| 294 | or generated documentation" , |
| 295 | "FILES" , |
| 296 | ), |
| 297 | opt( |
| 298 | Stable, |
| 299 | Multi, |
| 300 | "" , |
| 301 | "html-before-content" , |
| 302 | "files to include inline between <body> and the content of a rendered \ |
| 303 | Markdown file or generated documentation" , |
| 304 | "FILES" , |
| 305 | ), |
| 306 | opt( |
| 307 | Stable, |
| 308 | Multi, |
| 309 | "" , |
| 310 | "html-after-content" , |
| 311 | "files to include inline between the content and </body> of a rendered \ |
| 312 | Markdown file or generated documentation" , |
| 313 | "FILES" , |
| 314 | ), |
| 315 | opt( |
| 316 | Unstable, |
| 317 | Multi, |
| 318 | "" , |
| 319 | "markdown-before-content" , |
| 320 | "files to include inline between <body> and the content of a rendered \ |
| 321 | Markdown file or generated documentation" , |
| 322 | "FILES" , |
| 323 | ), |
| 324 | opt( |
| 325 | Unstable, |
| 326 | Multi, |
| 327 | "" , |
| 328 | "markdown-after-content" , |
| 329 | "files to include inline between the content and </body> of a rendered \ |
| 330 | Markdown file or generated documentation" , |
| 331 | "FILES" , |
| 332 | ), |
| 333 | opt(Stable, Opt, "" , "markdown-playground-url" , "URL to send code snippets to" , "URL" ), |
| 334 | opt(Stable, FlagMulti, "" , "markdown-no-toc" , "don't include table of contents" , "" ), |
| 335 | opt( |
| 336 | Stable, |
| 337 | Opt, |
| 338 | "e" , |
| 339 | "extend-css" , |
| 340 | "To add some CSS rules with a given file to generate doc with your own theme. \ |
| 341 | However, your theme might break if the rustdoc's generated HTML changes, so be careful!" , |
| 342 | "PATH" , |
| 343 | ), |
| 344 | opt( |
| 345 | Unstable, |
| 346 | Multi, |
| 347 | "Z" , |
| 348 | "" , |
| 349 | "unstable / perma-unstable options (only on nightly build)" , |
| 350 | "FLAG" , |
| 351 | ), |
| 352 | opt(Stable, Opt, "" , "sysroot" , "Override the system root" , "PATH" ), |
| 353 | opt( |
| 354 | Unstable, |
| 355 | Opt, |
| 356 | "" , |
| 357 | "playground-url" , |
| 358 | "URL to send code snippets to, may be reset by --markdown-playground-url \ |
| 359 | or `#![doc(html_playground_url=...)]`" , |
| 360 | "URL" , |
| 361 | ), |
| 362 | opt( |
| 363 | Unstable, |
| 364 | FlagMulti, |
| 365 | "" , |
| 366 | "display-doctest-warnings" , |
| 367 | "show warnings that originate in doctests" , |
| 368 | "" , |
| 369 | ), |
| 370 | opt( |
| 371 | Stable, |
| 372 | Opt, |
| 373 | "" , |
| 374 | "crate-version" , |
| 375 | "crate version to print into documentation" , |
| 376 | "VERSION" , |
| 377 | ), |
| 378 | opt( |
| 379 | Unstable, |
| 380 | FlagMulti, |
| 381 | "" , |
| 382 | "sort-modules-by-appearance" , |
| 383 | "sort modules by where they appear in the program, rather than alphabetically" , |
| 384 | "" , |
| 385 | ), |
| 386 | opt( |
| 387 | Stable, |
| 388 | Opt, |
| 389 | "" , |
| 390 | "default-theme" , |
| 391 | "Set the default theme. THEME should be the theme name, generally lowercase. \ |
| 392 | If an unknown default theme is specified, the builtin default is used. \ |
| 393 | The set of themes, and the rustdoc built-in default, are not stable." , |
| 394 | "THEME" , |
| 395 | ), |
| 396 | opt( |
| 397 | Unstable, |
| 398 | Multi, |
| 399 | "" , |
| 400 | "default-setting" , |
| 401 | "Default value for a rustdoc setting (used when \"rustdoc-SETTING \" is absent \ |
| 402 | from web browser Local Storage). If VALUE is not supplied, \"true \" is used. \ |
| 403 | Supported SETTINGs and VALUEs are not documented and not stable." , |
| 404 | "SETTING[=VALUE]" , |
| 405 | ), |
| 406 | opt( |
| 407 | Stable, |
| 408 | Multi, |
| 409 | "" , |
| 410 | "theme" , |
| 411 | "additional themes which will be added to the generated docs" , |
| 412 | "FILES" , |
| 413 | ), |
| 414 | opt(Stable, Multi, "" , "check-theme" , "check if given theme is valid" , "FILES" ), |
| 415 | opt( |
| 416 | Unstable, |
| 417 | Opt, |
| 418 | "" , |
| 419 | "resource-suffix" , |
| 420 | "suffix to add to CSS and JavaScript files, \ |
| 421 | e.g., \"search-index.js \" will become \"search-index-suffix.js \"" , |
| 422 | "PATH" , |
| 423 | ), |
| 424 | opt( |
| 425 | Stable, |
| 426 | Opt, |
| 427 | "" , |
| 428 | "edition" , |
| 429 | "edition to use when compiling rust code (default: 2015)" , |
| 430 | "EDITION" , |
| 431 | ), |
| 432 | opt( |
| 433 | Stable, |
| 434 | Opt, |
| 435 | "" , |
| 436 | "color" , |
| 437 | "Configure coloring of output: |
| 438 | auto = colorize, if output goes to a tty (default); |
| 439 | always = always colorize output; |
| 440 | never = never colorize output" , |
| 441 | "auto|always|never" , |
| 442 | ), |
| 443 | opt( |
| 444 | Stable, |
| 445 | Opt, |
| 446 | "" , |
| 447 | "error-format" , |
| 448 | "How errors and other messages are produced" , |
| 449 | "human|json|short" , |
| 450 | ), |
| 451 | opt( |
| 452 | Stable, |
| 453 | Opt, |
| 454 | "" , |
| 455 | "diagnostic-width" , |
| 456 | "Provide width of the output for truncated error messages" , |
| 457 | "WIDTH" , |
| 458 | ), |
| 459 | opt(Stable, Opt, "" , "json" , "Configure the structure of JSON diagnostics" , "CONFIG" ), |
| 460 | opt(Stable, Multi, "A" , "allow" , "Set lint allowed" , "LINT" ), |
| 461 | opt(Stable, Multi, "W" , "warn" , "Set lint warnings" , "LINT" ), |
| 462 | opt(Stable, Multi, "" , "force-warn" , "Set lint force-warn" , "LINT" ), |
| 463 | opt(Stable, Multi, "D" , "deny" , "Set lint denied" , "LINT" ), |
| 464 | opt(Stable, Multi, "F" , "forbid" , "Set lint forbidden" , "LINT" ), |
| 465 | opt( |
| 466 | Stable, |
| 467 | Multi, |
| 468 | "" , |
| 469 | "cap-lints" , |
| 470 | "Set the most restrictive lint level. \ |
| 471 | More restrictive lints are capped at this level. \ |
| 472 | By default, it is at `forbid` level." , |
| 473 | "LEVEL" , |
| 474 | ), |
| 475 | opt(Unstable, Opt, "" , "index-page" , "Markdown file to be used as index page" , "PATH" ), |
| 476 | opt( |
| 477 | Unstable, |
| 478 | FlagMulti, |
| 479 | "" , |
| 480 | "enable-index-page" , |
| 481 | "To enable generation of the index page" , |
| 482 | "" , |
| 483 | ), |
| 484 | opt( |
| 485 | Unstable, |
| 486 | Opt, |
| 487 | "" , |
| 488 | "static-root-path" , |
| 489 | "Path string to force loading static files from in output pages. \ |
| 490 | If not set, uses combinations of '../' to reach the documentation root." , |
| 491 | "PATH" , |
| 492 | ), |
| 493 | opt( |
| 494 | Unstable, |
| 495 | Opt, |
| 496 | "" , |
| 497 | "persist-doctests" , |
| 498 | "Directory to persist doctest executables into" , |
| 499 | "PATH" , |
| 500 | ), |
| 501 | opt( |
| 502 | Unstable, |
| 503 | FlagMulti, |
| 504 | "" , |
| 505 | "show-coverage" , |
| 506 | "calculate percentage of public items with documentation" , |
| 507 | "" , |
| 508 | ), |
| 509 | opt( |
| 510 | Unstable, |
| 511 | FlagMulti, |
| 512 | "" , |
| 513 | "enable-per-target-ignores" , |
| 514 | "parse ignore-foo for ignoring doctests on a per-target basis" , |
| 515 | "" , |
| 516 | ), |
| 517 | opt( |
| 518 | Unstable, |
| 519 | Opt, |
| 520 | "" , |
| 521 | "runtool" , |
| 522 | "" , |
| 523 | "The tool to run tests with when building for a different target than host" , |
| 524 | ), |
| 525 | opt( |
| 526 | Unstable, |
| 527 | Multi, |
| 528 | "" , |
| 529 | "runtool-arg" , |
| 530 | "" , |
| 531 | "One (of possibly many) arguments to pass to the runtool" , |
| 532 | ), |
| 533 | opt( |
| 534 | Unstable, |
| 535 | Opt, |
| 536 | "" , |
| 537 | "test-builder" , |
| 538 | "The rustc-like binary to use as the test builder" , |
| 539 | "PATH" , |
| 540 | ), |
| 541 | opt( |
| 542 | Unstable, |
| 543 | Multi, |
| 544 | "" , |
| 545 | "test-builder-wrapper" , |
| 546 | "Wrapper program to pass test-builder and arguments" , |
| 547 | "PATH" , |
| 548 | ), |
| 549 | opt(Unstable, FlagMulti, "" , "check" , "Run rustdoc checks" , "" ), |
| 550 | opt( |
| 551 | Unstable, |
| 552 | FlagMulti, |
| 553 | "" , |
| 554 | "generate-redirect-map" , |
| 555 | "Generate JSON file at the top level instead of generating HTML redirection files" , |
| 556 | "" , |
| 557 | ), |
| 558 | opt( |
| 559 | Unstable, |
| 560 | Multi, |
| 561 | "" , |
| 562 | "emit" , |
| 563 | "Comma separated list of types of output for rustdoc to emit" , |
| 564 | "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]" , |
| 565 | ), |
| 566 | opt(Unstable, FlagMulti, "" , "no-run" , "Compile doctests without running them" , "" ), |
| 567 | opt( |
| 568 | Unstable, |
| 569 | Multi, |
| 570 | "" , |
| 571 | "remap-path-prefix" , |
| 572 | "Remap source names in compiler messages" , |
| 573 | "FROM=TO" , |
| 574 | ), |
| 575 | opt( |
| 576 | Unstable, |
| 577 | FlagMulti, |
| 578 | "" , |
| 579 | "show-type-layout" , |
| 580 | "Include the memory layout of types in the docs" , |
| 581 | "" , |
| 582 | ), |
| 583 | opt(Unstable, Flag, "" , "nocapture" , "Don't capture stdout and stderr of tests" , "" ), |
| 584 | opt( |
| 585 | Unstable, |
| 586 | Flag, |
| 587 | "" , |
| 588 | "generate-link-to-definition" , |
| 589 | "Make the identifiers in the HTML source code pages navigable" , |
| 590 | "" , |
| 591 | ), |
| 592 | opt( |
| 593 | Unstable, |
| 594 | Opt, |
| 595 | "" , |
| 596 | "scrape-examples-output-path" , |
| 597 | "" , |
| 598 | "collect function call information and output at the given path" , |
| 599 | ), |
| 600 | opt( |
| 601 | Unstable, |
| 602 | Multi, |
| 603 | "" , |
| 604 | "scrape-examples-target-crate" , |
| 605 | "" , |
| 606 | "collect function call information for functions from the target crate" , |
| 607 | ), |
| 608 | opt(Unstable, Flag, "" , "scrape-tests" , "Include test code when scraping examples" , "" ), |
| 609 | opt( |
| 610 | Unstable, |
| 611 | Multi, |
| 612 | "" , |
| 613 | "with-examples" , |
| 614 | "" , |
| 615 | "path to function call information (for displaying examples in the documentation)" , |
| 616 | ), |
| 617 | opt( |
| 618 | Unstable, |
| 619 | Opt, |
| 620 | "" , |
| 621 | "merge" , |
| 622 | "Controls how rustdoc handles files from previously documented crates in the doc root \n\ |
| 623 | none = Do not write cross-crate information to the --out-dir \n\ |
| 624 | shared = Append current crate's info to files found in the --out-dir \n\ |
| 625 | finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files" , |
| 626 | "none|shared|finalize" , |
| 627 | ), |
| 628 | opt( |
| 629 | Unstable, |
| 630 | Opt, |
| 631 | "" , |
| 632 | "parts-out-dir" , |
| 633 | "Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none" , |
| 634 | "path/to/doc.parts/<crate-name>" , |
| 635 | ), |
| 636 | opt( |
| 637 | Unstable, |
| 638 | Multi, |
| 639 | "" , |
| 640 | "include-parts-dir" , |
| 641 | "Includes trait implementations and other crate info from provided path. Only use with --merge=finalize" , |
| 642 | "path/to/doc.parts/<crate-name>" , |
| 643 | ), |
| 644 | opt(Unstable, Flag, "" , "html-no-source" , "Disable HTML source code pages generation" , "" ), |
| 645 | opt( |
| 646 | Unstable, |
| 647 | Multi, |
| 648 | "" , |
| 649 | "doctest-compilation-args" , |
| 650 | "" , |
| 651 | "add arguments to be used when compiling doctests" , |
| 652 | ), |
| 653 | opt( |
| 654 | Unstable, |
| 655 | FlagMulti, |
| 656 | "" , |
| 657 | "disable-minification" , |
| 658 | "disable the minification of CSS/JS files (perma-unstable, do not use with cached files)" , |
| 659 | "" , |
| 660 | ), |
| 661 | // deprecated / removed options |
| 662 | opt( |
| 663 | Stable, |
| 664 | Multi, |
| 665 | "" , |
| 666 | "plugin-path" , |
| 667 | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information" , |
| 668 | "DIR" , |
| 669 | ), |
| 670 | opt( |
| 671 | Stable, |
| 672 | Multi, |
| 673 | "" , |
| 674 | "passes" , |
| 675 | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information" , |
| 676 | "PASSES" , |
| 677 | ), |
| 678 | opt( |
| 679 | Stable, |
| 680 | Multi, |
| 681 | "" , |
| 682 | "plugins" , |
| 683 | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information" , |
| 684 | "PLUGINS" , |
| 685 | ), |
| 686 | opt( |
| 687 | Stable, |
| 688 | FlagMulti, |
| 689 | "" , |
| 690 | "no-defaults" , |
| 691 | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information" , |
| 692 | "" , |
| 693 | ), |
| 694 | opt( |
| 695 | Stable, |
| 696 | Opt, |
| 697 | "r" , |
| 698 | "input-format" , |
| 699 | "removed, see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information" , |
| 700 | "[rust]" , |
| 701 | ), |
| 702 | ] |
| 703 | } |
| 704 | |
| 705 | fn usage(argv0: &str) { |
| 706 | let mut options = getopts::Options::new(); |
| 707 | for option: as IntoIterator>::Item in opts() { |
| 708 | option.apply(&mut options); |
| 709 | } |
| 710 | println!(" {}" , options.usage(&format!(" {argv0} [options] <input>" ))); |
| 711 | println!(" @path Read newline separated options from `path` \n" ); |
| 712 | println!( |
| 713 | "More information available at {DOC_RUST_LANG_ORG_VERSION}/rustdoc/what-is-rustdoc.html" , |
| 714 | ); |
| 715 | } |
| 716 | |
| 717 | pub(crate) fn wrap_return(dcx: DiagCtxtHandle<'_>, res: Result<(), String>) { |
| 718 | match res { |
| 719 | Ok(()) => dcx.abort_if_errors(), |
| 720 | Err(err: String) => dcx.fatal(err), |
| 721 | } |
| 722 | } |
| 723 | |
| 724 | fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( |
| 725 | krate: clean::Crate, |
| 726 | renderopts: config::RenderOptions, |
| 727 | cache: formats::cache::Cache, |
| 728 | tcx: TyCtxt<'tcx>, |
| 729 | ) { |
| 730 | match formats::run_format::<T>(krate, options:renderopts, cache, tcx) { |
| 731 | Ok(_) => tcx.dcx().abort_if_errors(), |
| 732 | Err(e: Error) => { |
| 733 | let mut msg = |
| 734 | tcx.dcx().struct_fatal(format!("couldn't generate documentation: {}" , e.error)); |
| 735 | let file: String = e.file.display().to_string(); |
| 736 | if !file.is_empty() { |
| 737 | msg.note(format!("failed to create or modify \"{file}\"" )); |
| 738 | } |
| 739 | msg.emit(); |
| 740 | } |
| 741 | } |
| 742 | } |
| 743 | |
| 744 | /// Renders and writes cross-crate info files, like the search index. This function exists so that |
| 745 | /// we can run rustdoc without a crate root in the `--merge=finalize` mode. Cross-crate info files |
| 746 | /// discovered via `--include-parts-dir` are combined and written to the doc root. |
| 747 | fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> { |
| 748 | assert!( |
| 749 | opt.should_merge.write_rendered_cci, |
| 750 | "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize" |
| 751 | ); |
| 752 | assert!( |
| 753 | !opt.should_merge.read_rendered_cci, |
| 754 | "config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize" |
| 755 | ); |
| 756 | let crates: Vec = html::render::CrateInfo::read_many(&opt.include_parts_dir)?; |
| 757 | let include_sources: bool = !opt.html_no_source; |
| 758 | html::render::write_not_crate_specific( |
| 759 | &crates, |
| 760 | &opt.output, |
| 761 | &opt, |
| 762 | &opt.themes, |
| 763 | css_file_extension:opt.extension_css.as_deref(), |
| 764 | &opt.resource_suffix, |
| 765 | include_sources, |
| 766 | )?; |
| 767 | Ok(()) |
| 768 | } |
| 769 | |
| 770 | fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { |
| 771 | // Throw away the first argument, the name of the binary. |
| 772 | // In case of at_args being empty, as might be the case by |
| 773 | // passing empty argument array to execve under some platforms, |
| 774 | // just use an empty slice. |
| 775 | // |
| 776 | // This situation was possible before due to arg_expand_all being |
| 777 | // called before removing the argument, enabling a crash by calling |
| 778 | // the compiler with @empty_file as argv[0] and no more arguments. |
| 779 | let at_args = at_args.get(1..).unwrap_or_default(); |
| 780 | |
| 781 | let args = rustc_driver::args::arg_expand_all(early_dcx, at_args); |
| 782 | |
| 783 | let mut options = getopts::Options::new(); |
| 784 | for option in opts() { |
| 785 | option.apply(&mut options); |
| 786 | } |
| 787 | let matches = match options.parse(&args) { |
| 788 | Ok(m) => m, |
| 789 | Err(err) => { |
| 790 | early_dcx.early_fatal(err.to_string()); |
| 791 | } |
| 792 | }; |
| 793 | |
| 794 | // Note that we discard any distinction between different non-zero exit |
| 795 | // codes from `from_matches` here. |
| 796 | let (input, options, render_options) = |
| 797 | match config::Options::from_matches(early_dcx, &matches, args) { |
| 798 | Some(opts) => opts, |
| 799 | None => return, |
| 800 | }; |
| 801 | |
| 802 | let dcx = |
| 803 | core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts); |
| 804 | let dcx = dcx.handle(); |
| 805 | |
| 806 | let input = match input { |
| 807 | config::InputMode::HasFile(input) => input, |
| 808 | config::InputMode::NoInputMergeFinalize => { |
| 809 | return wrap_return( |
| 810 | dcx, |
| 811 | run_merge_finalize(render_options) |
| 812 | .map_err(|e| format!("could not write merged cross-crate info: {e}" )), |
| 813 | ); |
| 814 | } |
| 815 | }; |
| 816 | |
| 817 | let output_format = options.output_format; |
| 818 | |
| 819 | match ( |
| 820 | options.should_test || output_format == config::OutputFormat::Doctest, |
| 821 | config::markdown_input(&input), |
| 822 | ) { |
| 823 | (true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)), |
| 824 | (true, None) => return doctest::run(dcx, input, options), |
| 825 | (false, Some(md_input)) => { |
| 826 | let md_input = md_input.to_owned(); |
| 827 | let edition = options.edition; |
| 828 | let config = core::create_config(input, options, &render_options); |
| 829 | |
| 830 | // `markdown::render` can invoke `doctest::make_test`, which |
| 831 | // requires session globals and a thread pool, so we use |
| 832 | // `run_compiler`. |
| 833 | return wrap_return( |
| 834 | dcx, |
| 835 | interface::run_compiler(config, |_compiler| { |
| 836 | markdown::render_and_write(&md_input, render_options, edition) |
| 837 | }), |
| 838 | ); |
| 839 | } |
| 840 | (false, None) => {} |
| 841 | } |
| 842 | |
| 843 | // need to move these items separately because we lose them by the time the closure is called, |
| 844 | // but we can't create the dcx ahead of time because it's not Send |
| 845 | let show_coverage = options.show_coverage; |
| 846 | let run_check = options.run_check; |
| 847 | |
| 848 | // First, parse the crate and extract all relevant information. |
| 849 | info!("starting to run rustc" ); |
| 850 | |
| 851 | // Interpret the input file as a rust source file, passing it through the |
| 852 | // compiler all the way through the analysis passes. The rustdoc output is |
| 853 | // then generated from the cleaned AST of the crate. This runs all the |
| 854 | // plug/cleaning passes. |
| 855 | let crate_version = options.crate_version.clone(); |
| 856 | |
| 857 | let scrape_examples_options = options.scrape_examples_options.clone(); |
| 858 | let bin_crate = options.bin_crate; |
| 859 | |
| 860 | let config = core::create_config(input, options, &render_options); |
| 861 | |
| 862 | let registered_lints = config.register_lints.is_some(); |
| 863 | |
| 864 | interface::run_compiler(config, |compiler| { |
| 865 | let sess = &compiler.sess; |
| 866 | |
| 867 | if sess.opts.describe_lints { |
| 868 | rustc_driver::describe_lints(sess, registered_lints); |
| 869 | return; |
| 870 | } |
| 871 | |
| 872 | let krate = rustc_interface::passes::parse(sess); |
| 873 | rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { |
| 874 | if sess.dcx().has_errors().is_some() { |
| 875 | sess.dcx().fatal("Compilation failed, aborting rustdoc" ); |
| 876 | } |
| 877 | |
| 878 | let (krate, render_opts, mut cache) = sess.time("run_global_ctxt" , || { |
| 879 | core::run_global_ctxt(tcx, show_coverage, render_options, output_format) |
| 880 | }); |
| 881 | info!("finished with rustc" ); |
| 882 | |
| 883 | if let Some(options) = scrape_examples_options { |
| 884 | return scrape_examples::run(krate, render_opts, cache, tcx, options, bin_crate); |
| 885 | } |
| 886 | |
| 887 | cache.crate_version = crate_version; |
| 888 | |
| 889 | if show_coverage { |
| 890 | // if we ran coverage, bail early, we don't need to also generate docs at this point |
| 891 | // (also we didn't load in any of the useful passes) |
| 892 | return; |
| 893 | } |
| 894 | |
| 895 | if render_opts.dep_info().is_some() { |
| 896 | rustc_interface::passes::write_dep_info(tcx); |
| 897 | } |
| 898 | |
| 899 | if run_check { |
| 900 | // Since we're in "check" mode, no need to generate anything beyond this point. |
| 901 | return; |
| 902 | } |
| 903 | |
| 904 | info!("going to format" ); |
| 905 | match output_format { |
| 906 | config::OutputFormat::Html => sess.time("render_html" , || { |
| 907 | run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx) |
| 908 | }), |
| 909 | config::OutputFormat::Json => sess.time("render_json" , || { |
| 910 | run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) |
| 911 | }), |
| 912 | // Already handled above with doctest runners. |
| 913 | config::OutputFormat::Doctest => unreachable!(), |
| 914 | } |
| 915 | }) |
| 916 | }) |
| 917 | } |
| 918 | |