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 | |