]>
Commit | Line | Data |
---|---|---|
60c5eb7d XL |
1 | #![doc( |
2 | html_root_url = "https://doc.rust-lang.org/nightly/", | |
3 | html_playground_url = "https://play.rust-lang.org/" | |
4 | )] | |
3b2f2976 | 5 | #![feature(rustc_private)] |
29967ef6 | 6 | #![feature(array_methods)] |
85aaf69f | 7 | #![feature(box_patterns)] |
1a4d82fc | 8 | #![feature(box_syntax)] |
532ac7d7 | 9 | #![feature(in_band_lifetimes)] |
0bf4aa26 | 10 | #![feature(nll)] |
85aaf69f | 11 | #![feature(test)] |
8faf50e0 | 12 | #![feature(crate_visibility_modifier)] |
532ac7d7 | 13 | #![feature(never_type)] |
3dfed10e | 14 | #![feature(once_cell)] |
fc512014 | 15 | #![feature(type_ascription)] |
5869c6ff | 16 | #![feature(iter_intersperse)] |
60c5eb7d | 17 | #![recursion_limit = "256"] |
cdc7bbd5 | 18 | #![warn(rustc::internal)] |
94b46f34 | 19 | |
3dfed10e XL |
20 | #[macro_use] |
21 | extern crate lazy_static; | |
1b1a35ee XL |
22 | #[macro_use] |
23 | extern crate tracing; | |
24 | ||
25 | // N.B. these need `extern crate` even in 2018 edition | |
26 | // because they're loaded implicitly from the sysroot. | |
27 | // The reason they're loaded from the sysroot is because | |
28 | // the rustdoc artifacts aren't stored in rustc's cargo target directory. | |
29 | // So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. | |
30 | // | |
31 | // Dependencies listed in Cargo.toml do not need `extern crate`. | |
cdc7bbd5 | 32 | |
74b04a01 XL |
33 | extern crate rustc_ast; |
34 | extern crate rustc_ast_pretty; | |
35 | extern crate rustc_attr; | |
9e0c209e | 36 | extern crate rustc_data_structures; |
1a4d82fc | 37 | extern crate rustc_driver; |
dfeec247 XL |
38 | extern crate rustc_errors; |
39 | extern crate rustc_expand; | |
60c5eb7d | 40 | extern crate rustc_feature; |
dfeec247 | 41 | extern crate rustc_hir; |
ba9703b0 | 42 | extern crate rustc_hir_pretty; |
60c5eb7d | 43 | extern crate rustc_index; |
74b04a01 | 44 | extern crate rustc_infer; |
532ac7d7 | 45 | extern crate rustc_interface; |
60c5eb7d XL |
46 | extern crate rustc_lexer; |
47 | extern crate rustc_lint; | |
6a06907d | 48 | extern crate rustc_lint_defs; |
92a42be0 | 49 | extern crate rustc_metadata; |
ba9703b0 | 50 | extern crate rustc_middle; |
dfeec247 | 51 | extern crate rustc_mir; |
60c5eb7d | 52 | extern crate rustc_parse; |
6a06907d | 53 | extern crate rustc_passes; |
60c5eb7d | 54 | extern crate rustc_resolve; |
dfeec247 | 55 | extern crate rustc_session; |
136023e0 | 56 | extern crate rustc_span; |
83c7162d | 57 | extern crate rustc_target; |
ba9703b0 | 58 | extern crate rustc_trait_selection; |
7cac9316 | 59 | extern crate rustc_typeck; |
136023e0 | 60 | extern crate test; |
1a4d82fc | 61 | |
cdc7bbd5 XL |
62 | #[cfg(feature = "jemalloc")] |
63 | extern crate tikv_jemalloc_sys; | |
64 | #[cfg(feature = "jemalloc")] | |
65 | use tikv_jemalloc_sys as jemalloc_sys; | |
66 | #[cfg(feature = "jemalloc")] | |
67 | extern crate tikv_jemallocator; | |
68 | #[cfg(feature = "jemalloc")] | |
69 | use tikv_jemallocator as jemallocator; | |
70 | ||
9cc50fc6 | 71 | use std::default::Default; |
85aaf69f | 72 | use std::env; |
62682a34 | 73 | use std::process; |
c34b1796 | 74 | |
cdc7bbd5 | 75 | use rustc_driver::{abort_on_err, describe_lints}; |
3dfed10e | 76 | use rustc_errors::ErrorReported; |
fc512014 | 77 | use rustc_interface::interface; |
5869c6ff | 78 | use rustc_middle::ty::TyCtxt; |
ba9703b0 XL |
79 | use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; |
80 | use rustc_session::getopts; | |
81 | use rustc_session::{early_error, early_warn}; | |
1a4d82fc | 82 | |
17df50a5 XL |
83 | use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL; |
84 | ||
6a06907d XL |
85 | /// A macro to create a FxHashMap. |
86 | /// | |
87 | /// Example: | |
88 | /// | |
89 | /// ``` | |
90 | /// let letters = map!{"a" => "b", "c" => "d"}; | |
91 | /// ``` | |
92 | /// | |
93 | /// Trailing commas are allowed. | |
94 | /// Commas between elements are required (even if the expression is a block). | |
95 | macro_rules! map { | |
96 | ($( $key: expr => $val: expr ),* $(,)*) => {{ | |
97 | let mut map = ::rustc_data_structures::fx::FxHashMap::default(); | |
98 | $( map.insert($key, $val); )* | |
99 | map | |
100 | }} | |
101 | } | |
102 | ||
1a4d82fc | 103 | #[macro_use] |
8faf50e0 | 104 | mod externalfiles; |
1a4d82fc | 105 | |
8faf50e0 | 106 | mod clean; |
a1dfa0c6 | 107 | mod config; |
8faf50e0 | 108 | mod core; |
dc9dc135 | 109 | mod docfs; |
8faf50e0 | 110 | mod doctree; |
3dfed10e XL |
111 | #[macro_use] |
112 | mod error; | |
1b1a35ee | 113 | mod doctest; |
8faf50e0 | 114 | mod fold; |
5869c6ff XL |
115 | mod formats; |
116 | // used by the error-index generator, so it needs to be public | |
3dfed10e XL |
117 | pub mod html; |
118 | mod json; | |
6a06907d | 119 | crate mod lint; |
8faf50e0 XL |
120 | mod markdown; |
121 | mod passes; | |
8faf50e0 | 122 | mod theme; |
60c5eb7d XL |
123 | mod visit_ast; |
124 | mod visit_lib; | |
1a4d82fc | 125 | |
cdc7bbd5 XL |
126 | // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs |
127 | // about jemallocator | |
128 | #[cfg(feature = "jemalloc")] | |
129 | #[global_allocator] | |
130 | static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; | |
131 | ||
1a4d82fc | 132 | pub fn main() { |
cdc7bbd5 XL |
133 | // See docs in https://github.com/rust-lang/rust/blob/master/compiler/rustc/src/main.rs |
134 | // about jemalloc-sys | |
135 | #[cfg(feature = "jemalloc")] | |
136 | { | |
137 | use std::os::raw::{c_int, c_void}; | |
138 | ||
139 | #[used] | |
140 | static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc; | |
141 | #[used] | |
142 | static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int = | |
143 | jemalloc_sys::posix_memalign; | |
144 | #[used] | |
145 | static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc; | |
146 | #[used] | |
147 | static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc; | |
148 | #[used] | |
149 | static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc; | |
150 | #[used] | |
151 | static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free; | |
152 | ||
153 | // On OSX, jemalloc doesn't directly override malloc/free, but instead | |
154 | // registers itself with the allocator's zone APIs in a ctor. However, | |
155 | // the linker doesn't seem to consider ctors as "used" when statically | |
156 | // linking, so we need to explicitly depend on the function. | |
157 | #[cfg(target_os = "macos")] | |
158 | { | |
159 | extern "C" { | |
160 | fn _rjem_je_zone_register(); | |
161 | } | |
162 | ||
163 | #[used] | |
164 | static _F7: unsafe extern "C" fn() = _rjem_je_zone_register; | |
165 | } | |
166 | } | |
167 | ||
83c7162d | 168 | rustc_driver::set_sigpipe_handler(); |
3dfed10e | 169 | rustc_driver::install_ice_hook(); |
6a06907d XL |
170 | |
171 | // When using CI artifacts (with `download_stage1 = true`), tracing is unconditionally built | |
172 | // with `--features=static_max_level_info`, which disables almost all rustdoc logging. To avoid | |
173 | // this, compile our own version of `tracing` that logs all levels. | |
174 | // NOTE: this compiles both versions of tracing unconditionally, because | |
175 | // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and | |
176 | // - Otherwise, there's no warning that logging is being ignored when `download_stage1 = true`. | |
177 | // NOTE: The reason this doesn't show double logging when `download_stage1 = false` and | |
178 | // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one | |
179 | // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml). | |
180 | init_logging(); | |
3dfed10e | 181 | rustc_driver::init_env_logger("RUSTDOC_LOG"); |
6a06907d | 182 | |
3dfed10e XL |
183 | let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() { |
184 | Some(args) => main_args(&args), | |
185 | _ => Err(ErrorReported), | |
186 | }); | |
187 | process::exit(exit_code); | |
1a4d82fc JJ |
188 | } |
189 | ||
6a06907d XL |
190 | fn init_logging() { |
191 | use std::io; | |
192 | ||
193 | // FIXME remove these and use winapi 0.3 instead | |
194 | // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs, rustc_driver/lib.rs | |
195 | #[cfg(unix)] | |
196 | fn stdout_isatty() -> bool { | |
197 | extern crate libc; | |
198 | unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } | |
199 | } | |
200 | ||
201 | #[cfg(windows)] | |
202 | fn stdout_isatty() -> bool { | |
203 | extern crate winapi; | |
204 | use winapi::um::consoleapi::GetConsoleMode; | |
205 | use winapi::um::processenv::GetStdHandle; | |
206 | use winapi::um::winbase::STD_OUTPUT_HANDLE; | |
207 | ||
208 | unsafe { | |
209 | let handle = GetStdHandle(STD_OUTPUT_HANDLE); | |
210 | let mut out = 0; | |
211 | GetConsoleMode(handle, &mut out) != 0 | |
212 | } | |
213 | } | |
214 | ||
215 | let color_logs = match std::env::var("RUSTDOC_LOG_COLOR") { | |
216 | Ok(value) => match value.as_ref() { | |
217 | "always" => true, | |
218 | "never" => false, | |
219 | "auto" => stdout_isatty(), | |
220 | _ => early_error( | |
221 | ErrorOutputType::default(), | |
222 | &format!( | |
223 | "invalid log color value '{}': expected one of always, never, or auto", | |
224 | value | |
225 | ), | |
226 | ), | |
227 | }, | |
228 | Err(std::env::VarError::NotPresent) => stdout_isatty(), | |
229 | Err(std::env::VarError::NotUnicode(_value)) => early_error( | |
230 | ErrorOutputType::default(), | |
231 | "non-Unicode log color value: expected one of always, never, or auto", | |
232 | ), | |
233 | }; | |
234 | let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG"); | |
235 | let layer = tracing_tree::HierarchicalLayer::default() | |
236 | .with_writer(io::stderr) | |
237 | .with_indent_lines(true) | |
238 | .with_ansi(color_logs) | |
239 | .with_targets(true) | |
240 | .with_wraparound(10) | |
241 | .with_verbose_exit(true) | |
242 | .with_verbose_entry(true) | |
243 | .with_indent_amount(2); | |
244 | #[cfg(parallel_compiler)] | |
245 | let layer = layer.with_thread_ids(true).with_thread_names(true); | |
246 | ||
247 | use tracing_subscriber::layer::SubscriberExt; | |
248 | let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer); | |
249 | tracing::subscriber::set_global_default(subscriber).unwrap(); | |
250 | } | |
251 | ||
7cac9316 | 252 | fn get_args() -> Option<Vec<String>> { |
60c5eb7d XL |
253 | env::args_os() |
254 | .enumerate() | |
255 | .map(|(i, arg)| { | |
256 | arg.into_string() | |
257 | .map_err(|arg| { | |
258 | early_warn( | |
259 | ErrorOutputType::default(), | |
260 | &format!("Argument {} is not valid Unicode: {:?}", i, arg), | |
261 | ); | |
262 | }) | |
263 | .ok() | |
264 | }) | |
7cac9316 XL |
265 | .collect() |
266 | } | |
267 | ||
8faf50e0 | 268 | fn opts() -> Vec<RustcOptGroup> { |
fc512014 XL |
269 | let stable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::stable; |
270 | let unstable: fn(_, fn(&mut getopts::Options) -> &mut _) -> _ = RustcOptGroup::unstable; | |
c30ab7b3 | 271 | vec![ |
136023e0 XL |
272 | stable("h", |o| o.optflagmulti("h", "help", "show this help message")), |
273 | stable("V", |o| o.optflagmulti("V", "version", "print rustdoc's version")), | |
274 | stable("v", |o| o.optflagmulti("v", "verbose", "use verbose output")), | |
041b39d2 | 275 | stable("r", |o| { |
60c5eb7d | 276 | o.optopt("r", "input-format", "the input type of the specified file", "[rust]") |
041b39d2 | 277 | }), |
60c5eb7d | 278 | stable("w", |o| o.optopt("w", "output-format", "the output type to write", "[html]")), |
041b39d2 XL |
279 | stable("o", |o| o.optopt("o", "output", "where to place the output", "PATH")), |
280 | stable("crate-name", |o| { | |
281 | o.optopt("", "crate-name", "specify the name of this crate", "NAME") | |
282 | }), | |
e1599b0c | 283 | make_crate_type_option(), |
041b39d2 | 284 | stable("L", |o| { |
60c5eb7d | 285 | o.optmulti("L", "library-path", "directory to add to crate search path", "DIR") |
041b39d2 XL |
286 | }), |
287 | stable("cfg", |o| o.optmulti("", "cfg", "pass a --cfg to rustc", "")), | |
60c5eb7d | 288 | stable("extern", |o| o.optmulti("", "extern", "pass an --extern to rustc", "NAME[=PATH]")), |
b7449926 | 289 | unstable("extern-html-root-url", |o| { |
cdc7bbd5 XL |
290 | o.optmulti( |
291 | "", | |
292 | "extern-html-root-url", | |
293 | "base URL to use for dependencies; for example, \ | |
294 | \"std=/doc\" links std::vec::Vec to /doc/std/vec/struct.Vec.html", | |
295 | "NAME=URL", | |
296 | ) | |
041b39d2 | 297 | }), |
60c5eb7d | 298 | stable("plugin-path", |o| o.optmulti("", "plugin-path", "removed", "DIR")), |
83c7162d XL |
299 | stable("C", |o| { |
300 | o.optmulti("C", "codegen", "pass a codegen option to rustc", "OPT[=VALUE]") | |
301 | }), | |
041b39d2 | 302 | stable("passes", |o| { |
60c5eb7d XL |
303 | o.optmulti( |
304 | "", | |
305 | "passes", | |
f035d41b | 306 | "list of passes to also run, you might want to pass it multiple times; a value of \ |
1b1a35ee | 307 | `list` will print available passes", |
60c5eb7d XL |
308 | "PASSES", |
309 | ) | |
041b39d2 | 310 | }), |
60c5eb7d | 311 | stable("plugins", |o| o.optmulti("", "plugins", "removed", "PLUGINS")), |
136023e0 | 312 | stable("no-default", |o| o.optflagmulti("", "no-defaults", "don't run the default passes")), |
abe05a73 | 313 | stable("document-private-items", |o| { |
136023e0 | 314 | o.optflagmulti("", "document-private-items", "document private items") |
abe05a73 | 315 | }), |
60c5eb7d | 316 | unstable("document-hidden-items", |o| { |
136023e0 | 317 | o.optflagmulti("", "document-hidden-items", "document items that have doc(hidden)") |
60c5eb7d | 318 | }), |
136023e0 | 319 | stable("test", |o| o.optflagmulti("", "test", "run code examples as tests")), |
041b39d2 | 320 | stable("test-args", |o| { |
60c5eb7d | 321 | o.optmulti("", "test-args", "arguments to pass to the test runner", "ARGS") |
041b39d2 | 322 | }), |
5869c6ff XL |
323 | unstable("test-run-directory", |o| { |
324 | o.optopt( | |
325 | "", | |
326 | "test-run-directory", | |
327 | "The working directory in which to run tests", | |
328 | "PATH", | |
329 | ) | |
330 | }), | |
041b39d2 XL |
331 | stable("target", |o| o.optopt("", "target", "target triple to document", "TRIPLE")), |
332 | stable("markdown-css", |o| { | |
60c5eb7d XL |
333 | o.optmulti( |
334 | "", | |
335 | "markdown-css", | |
336 | "CSS files to include via <link> in a rendered Markdown file", | |
337 | "FILES", | |
338 | ) | |
041b39d2 | 339 | }), |
60c5eb7d XL |
340 | stable("html-in-header", |o| { |
341 | o.optmulti( | |
342 | "", | |
343 | "html-in-header", | |
344 | "files to include inline in the <head> section of a rendered Markdown file \ | |
1b1a35ee | 345 | or generated documentation", |
60c5eb7d XL |
346 | "FILES", |
347 | ) | |
041b39d2 XL |
348 | }), |
349 | stable("html-before-content", |o| { | |
60c5eb7d XL |
350 | o.optmulti( |
351 | "", | |
352 | "html-before-content", | |
353 | "files to include inline between <body> and the content of a rendered \ | |
1b1a35ee | 354 | Markdown file or generated documentation", |
60c5eb7d XL |
355 | "FILES", |
356 | ) | |
041b39d2 XL |
357 | }), |
358 | stable("html-after-content", |o| { | |
60c5eb7d XL |
359 | o.optmulti( |
360 | "", | |
361 | "html-after-content", | |
362 | "files to include inline between the content and </body> of a rendered \ | |
1b1a35ee | 363 | Markdown file or generated documentation", |
60c5eb7d XL |
364 | "FILES", |
365 | ) | |
041b39d2 XL |
366 | }), |
367 | unstable("markdown-before-content", |o| { | |
60c5eb7d XL |
368 | o.optmulti( |
369 | "", | |
370 | "markdown-before-content", | |
371 | "files to include inline between <body> and the content of a rendered \ | |
1b1a35ee | 372 | Markdown file or generated documentation", |
60c5eb7d XL |
373 | "FILES", |
374 | ) | |
041b39d2 XL |
375 | }), |
376 | unstable("markdown-after-content", |o| { | |
60c5eb7d XL |
377 | o.optmulti( |
378 | "", | |
379 | "markdown-after-content", | |
380 | "files to include inline between the content and </body> of a rendered \ | |
1b1a35ee | 381 | Markdown file or generated documentation", |
60c5eb7d XL |
382 | "FILES", |
383 | ) | |
041b39d2 XL |
384 | }), |
385 | stable("markdown-playground-url", |o| { | |
60c5eb7d | 386 | o.optopt("", "markdown-playground-url", "URL to send code snippets to", "URL") |
041b39d2 XL |
387 | }), |
388 | stable("markdown-no-toc", |o| { | |
136023e0 | 389 | o.optflagmulti("", "markdown-no-toc", "don't include table of contents") |
041b39d2 XL |
390 | }), |
391 | stable("e", |o| { | |
60c5eb7d XL |
392 | o.optopt( |
393 | "e", | |
394 | "extend-css", | |
395 | "To add some CSS rules with a given file to generate doc with your \ | |
1b1a35ee XL |
396 | own theme. However, your theme might break if the rustdoc's generated HTML \ |
397 | changes, so be careful!", | |
60c5eb7d XL |
398 | "PATH", |
399 | ) | |
041b39d2 XL |
400 | }), |
401 | unstable("Z", |o| { | |
60c5eb7d | 402 | o.optmulti("Z", "", "internal and debugging options (only on nightly build)", "FLAG") |
041b39d2 | 403 | }), |
60c5eb7d | 404 | stable("sysroot", |o| o.optopt("", "sysroot", "Override the system root", "PATH")), |
041b39d2 | 405 | unstable("playground-url", |o| { |
60c5eb7d XL |
406 | o.optopt( |
407 | "", | |
408 | "playground-url", | |
409 | "URL to send code snippets to, may be reset by --markdown-playground-url \ | |
1b1a35ee | 410 | or `#![doc(html_playground_url=...)]`", |
60c5eb7d XL |
411 | "URL", |
412 | ) | |
041b39d2 | 413 | }), |
041b39d2 | 414 | unstable("display-warnings", |o| { |
136023e0 | 415 | o.optflagmulti("", "display-warnings", "to print code warnings when testing doc") |
041b39d2 | 416 | }), |
ba9703b0 | 417 | stable("crate-version", |o| { |
abe05a73 XL |
418 | o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") |
419 | }), | |
ff7c6d11 | 420 | unstable("sort-modules-by-appearance", |o| { |
136023e0 | 421 | o.optflagmulti( |
60c5eb7d XL |
422 | "", |
423 | "sort-modules-by-appearance", | |
f035d41b | 424 | "sort modules by where they appear in the program, rather than alphabetically", |
60c5eb7d | 425 | ) |
ff7c6d11 | 426 | }), |
5869c6ff | 427 | stable("default-theme", |o| { |
29967ef6 XL |
428 | o.optopt( |
429 | "", | |
430 | "default-theme", | |
431 | "Set the default theme. THEME should be the theme name, generally lowercase. \ | |
432 | If an unknown default theme is specified, the builtin default is used. \ | |
5869c6ff | 433 | The set of themes, and the rustdoc built-in default, are not stable.", |
29967ef6 XL |
434 | "THEME", |
435 | ) | |
436 | }), | |
437 | unstable("default-setting", |o| { | |
438 | o.optmulti( | |
439 | "", | |
440 | "default-setting", | |
441 | "Default value for a rustdoc setting (used when \"rustdoc-SETTING\" is absent \ | |
442 | from web browser Local Storage). If VALUE is not supplied, \"true\" is used. \ | |
443 | Supported SETTINGs and VALUEs are not documented and not stable.", | |
444 | "SETTING[=VALUE]", | |
445 | ) | |
446 | }), | |
60c5eb7d XL |
447 | stable("theme", |o| { |
448 | o.optmulti( | |
449 | "", | |
450 | "theme", | |
451 | "additional themes which will be added to the generated docs", | |
452 | "FILES", | |
453 | ) | |
2c00a5a8 | 454 | }), |
60c5eb7d XL |
455 | stable("check-theme", |o| { |
456 | o.optmulti("", "check-theme", "check if given theme is valid", "FILES") | |
2c00a5a8 | 457 | }), |
0531ce1d | 458 | unstable("resource-suffix", |o| { |
60c5eb7d XL |
459 | o.optopt( |
460 | "", | |
461 | "resource-suffix", | |
462 | "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ | |
1b1a35ee | 463 | \"light-suffix.css\"", |
60c5eb7d XL |
464 | "PATH", |
465 | ) | |
0531ce1d | 466 | }), |
0bf4aa26 | 467 | stable("edition", |o| { |
60c5eb7d XL |
468 | o.optopt( |
469 | "", | |
470 | "edition", | |
471 | "edition to use when compiling rust code (default: 2015)", | |
472 | "EDITION", | |
473 | ) | |
0531ce1d | 474 | }), |
b7449926 | 475 | stable("color", |o| { |
60c5eb7d XL |
476 | o.optopt( |
477 | "", | |
478 | "color", | |
479 | "Configure coloring of output: | |
83c7162d XL |
480 | auto = colorize, if output goes to a tty (default); |
481 | always = always colorize output; | |
482 | never = never colorize output", | |
60c5eb7d XL |
483 | "auto|always|never", |
484 | ) | |
83c7162d | 485 | }), |
b7449926 | 486 | stable("error-format", |o| { |
60c5eb7d XL |
487 | o.optopt( |
488 | "", | |
489 | "error-format", | |
490 | "How errors and other messages are produced", | |
491 | "human|json|short", | |
492 | ) | |
83c7162d | 493 | }), |
416331ca | 494 | stable("json", |o| { |
60c5eb7d | 495 | o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG") |
416331ca | 496 | }), |
94b46f34 | 497 | unstable("disable-minification", |o| { |
136023e0 | 498 | o.optflagmulti("", "disable-minification", "Disable minification applied on JS files") |
8faf50e0 | 499 | }), |
60c5eb7d XL |
500 | stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "OPT")), |
501 | stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "OPT")), | |
502 | stable("deny", |o| o.optmulti("D", "deny", "Set lint denied", "OPT")), | |
503 | stable("forbid", |o| o.optmulti("F", "forbid", "Set lint forbidden", "OPT")), | |
8faf50e0 XL |
504 | stable("cap-lints", |o| { |
505 | o.optmulti( | |
506 | "", | |
507 | "cap-lints", | |
508 | "Set the most restrictive lint level. \ | |
509 | More restrictive lints are capped at this \ | |
510 | level. By default, it is at `forbid` level.", | |
511 | "LEVEL", | |
512 | ) | |
513 | }), | |
136023e0 | 514 | unstable("force-warn", |o| { |
17df50a5 XL |
515 | o.optopt( |
516 | "", | |
136023e0 | 517 | "force-warn", |
17df50a5 XL |
518 | "Lints that will warn even if allowed somewhere else", |
519 | "LINTS", | |
520 | ) | |
521 | }), | |
a1dfa0c6 | 522 | unstable("index-page", |o| { |
60c5eb7d | 523 | o.optopt("", "index-page", "Markdown file to be used as index page", "PATH") |
a1dfa0c6 XL |
524 | }), |
525 | unstable("enable-index-page", |o| { | |
136023e0 | 526 | o.optflagmulti("", "enable-index-page", "To enable generation of the index page") |
a1dfa0c6 | 527 | }), |
0731742a | 528 | unstable("static-root-path", |o| { |
60c5eb7d XL |
529 | o.optopt( |
530 | "", | |
531 | "static-root-path", | |
532 | "Path string to force loading static files from in output pages. \ | |
1b1a35ee | 533 | If not set, uses combinations of '../' to reach the documentation root.", |
60c5eb7d XL |
534 | "PATH", |
535 | ) | |
0731742a XL |
536 | }), |
537 | unstable("disable-per-crate-search", |o| { | |
136023e0 | 538 | o.optflagmulti( |
60c5eb7d XL |
539 | "", |
540 | "disable-per-crate-search", | |
541 | "disables generating the crate selector on the search box", | |
542 | ) | |
0731742a | 543 | }), |
9fa01778 | 544 | unstable("persist-doctests", |o| { |
60c5eb7d XL |
545 | o.optopt( |
546 | "", | |
547 | "persist-doctests", | |
548 | "Directory to persist doctest executables into", | |
549 | "PATH", | |
550 | ) | |
9fa01778 | 551 | }), |
532ac7d7 | 552 | unstable("show-coverage", |o| { |
136023e0 | 553 | o.optflagmulti( |
60c5eb7d XL |
554 | "", |
555 | "show-coverage", | |
556 | "calculate percentage of public items with documentation", | |
557 | ) | |
532ac7d7 | 558 | }), |
e1599b0c | 559 | unstable("enable-per-target-ignores", |o| { |
136023e0 | 560 | o.optflagmulti( |
60c5eb7d XL |
561 | "", |
562 | "enable-per-target-ignores", | |
563 | "parse ignore-foo for ignoring doctests on a per-target basis", | |
564 | ) | |
e1599b0c XL |
565 | }), |
566 | unstable("runtool", |o| { | |
60c5eb7d XL |
567 | o.optopt( |
568 | "", | |
569 | "runtool", | |
570 | "", | |
571 | "The tool to run tests with when building for a different target than host", | |
572 | ) | |
e1599b0c XL |
573 | }), |
574 | unstable("runtool-arg", |o| { | |
60c5eb7d XL |
575 | o.optmulti( |
576 | "", | |
577 | "runtool-arg", | |
578 | "", | |
579 | "One (of possibly many) arguments to pass to the runtool", | |
580 | ) | |
e1599b0c XL |
581 | }), |
582 | unstable("test-builder", |o| { | |
5869c6ff | 583 | o.optopt("", "test-builder", "The rustc-like binary to use as the test builder", "PATH") |
e1599b0c | 584 | }), |
136023e0 | 585 | unstable("check", |o| o.optflagmulti("", "check", "Run rustdoc checks")), |
6a06907d | 586 | unstable("generate-redirect-map", |o| { |
136023e0 | 587 | o.optflagmulti( |
6a06907d XL |
588 | "", |
589 | "generate-redirect-map", | |
590 | "Generate JSON file at the top level instead of generating HTML redirection files", | |
591 | ) | |
592 | }), | |
cdc7bbd5 XL |
593 | unstable("emit", |o| { |
594 | o.optmulti( | |
595 | "", | |
596 | "emit", | |
597 | "Comma separated list of types of output for rustdoc to emit", | |
598 | "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]", | |
599 | ) | |
600 | }), | |
136023e0 XL |
601 | unstable("no-run", |o| { |
602 | o.optflagmulti("", "no-run", "Compile doctests without running them") | |
603 | }), | |
17df50a5 | 604 | unstable("show-type-layout", |o| { |
136023e0 XL |
605 | o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") |
606 | }), | |
607 | unstable("nocapture", |o| { | |
608 | o.optflag("", "nocapture", "Don't capture stdout and stderr of tests") | |
17df50a5 | 609 | }), |
c30ab7b3 | 610 | ] |
1a4d82fc JJ |
611 | } |
612 | ||
8faf50e0 | 613 | fn usage(argv0: &str) { |
041b39d2 XL |
614 | let mut options = getopts::Options::new(); |
615 | for option in opts() { | |
616 | (option.apply)(&mut options); | |
617 | } | |
618 | println!("{}", options.usage(&format!("{} [options] <input>", argv0))); | |
6a06907d | 619 | println!(" @path Read newline separated options from `path`\n"); |
17df50a5 XL |
620 | println!( |
621 | "More information available at {}/rustdoc/what-is-rustdoc.html", | |
622 | DOC_RUST_LANG_ORG_CHANNEL | |
623 | ); | |
1a4d82fc JJ |
624 | } |
625 | ||
3dfed10e XL |
626 | /// A result type used by several functions under `main()`. |
627 | type MainResult = Result<(), ErrorReported>; | |
628 | ||
6a06907d XL |
629 | fn main_args(at_args: &[String]) -> MainResult { |
630 | let args = rustc_driver::args::arg_expand_all(at_args); | |
631 | ||
041b39d2 XL |
632 | let mut options = getopts::Options::new(); |
633 | for option in opts() { | |
634 | (option.apply)(&mut options); | |
635 | } | |
636 | let matches = match options.parse(&args[1..]) { | |
1a4d82fc JJ |
637 | Ok(m) => m, |
638 | Err(err) => { | |
94b46f34 | 639 | early_error(ErrorOutputType::default(), &err.to_string()); |
1a4d82fc JJ |
640 | } |
641 | }; | |
3dfed10e XL |
642 | |
643 | // Note that we discard any distinction between different non-zero exit | |
644 | // codes from `from_matches` here. | |
a1dfa0c6 XL |
645 | let options = match config::Options::from_matches(&matches) { |
646 | Ok(opts) => opts, | |
3dfed10e | 647 | Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) }, |
b7449926 | 648 | }; |
3dfed10e | 649 | rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals( |
f035d41b | 650 | options.edition, |
3dfed10e XL |
651 | 1, // this runs single-threaded, even in a parallel compiler |
652 | &None, | |
f035d41b XL |
653 | move || main_options(options), |
654 | ) | |
dc9dc135 | 655 | } |
1a4d82fc | 656 | |
3dfed10e | 657 | fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult { |
f9f354fc | 658 | match res { |
3dfed10e | 659 | Ok(()) => Ok(()), |
f9f354fc | 660 | Err(err) => { |
3dfed10e XL |
661 | diag.struct_err(&err).emit(); |
662 | Err(ErrorReported) | |
663 | } | |
664 | } | |
665 | } | |
666 | ||
fc512014 | 667 | fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>( |
3dfed10e XL |
668 | krate: clean::Crate, |
669 | renderopts: config::RenderOptions, | |
6a06907d | 670 | cache: formats::cache::Cache, |
5869c6ff | 671 | tcx: TyCtxt<'tcx>, |
3dfed10e | 672 | ) -> MainResult { |
cdc7bbd5 | 673 | match formats::run_format::<T>(krate, renderopts, cache, tcx) { |
3dfed10e XL |
674 | Ok(_) => Ok(()), |
675 | Err(e) => { | |
cdc7bbd5 XL |
676 | let mut msg = |
677 | tcx.sess.struct_err(&format!("couldn't generate documentation: {}", e.error)); | |
3dfed10e XL |
678 | let file = e.file.display().to_string(); |
679 | if file.is_empty() { | |
680 | msg.emit() | |
681 | } else { | |
682 | msg.note(&format!("failed to create or modify \"{}\"", file)).emit() | |
f9f354fc | 683 | } |
3dfed10e | 684 | Err(ErrorReported) |
f9f354fc XL |
685 | } |
686 | } | |
687 | } | |
688 | ||
3dfed10e | 689 | fn main_options(options: config::Options) -> MainResult { |
1b1a35ee | 690 | let diag = core::new_handler(options.error_format, None, &options.debugging_opts); |
1a4d82fc | 691 | |
a1dfa0c6 | 692 | match (options.should_test, options.markdown_input()) { |
f9f354fc | 693 | (true, true) => return wrap_return(&diag, markdown::test(options)), |
1b1a35ee | 694 | (true, false) => return doctest::run(options), |
60c5eb7d | 695 | (false, true) => { |
f9f354fc XL |
696 | return wrap_return( |
697 | &diag, | |
698 | markdown::render(&options.input, options.render_options, options.edition), | |
699 | ); | |
60c5eb7d | 700 | } |
1a4d82fc JJ |
701 | (false, false) => {} |
702 | } | |
476ff2be | 703 | |
a1dfa0c6 | 704 | // need to move these items separately because we lose them by the time the closure is called, |
fc512014 | 705 | // but we can't create the Handler ahead of time because it's not Send |
532ac7d7 | 706 | let show_coverage = options.show_coverage; |
fc512014 | 707 | let run_check = options.run_check; |
f035d41b XL |
708 | |
709 | // First, parse the crate and extract all relevant information. | |
710 | info!("starting to run rustc"); | |
711 | ||
712 | // Interpret the input file as a rust source file, passing it through the | |
713 | // compiler all the way through the analysis passes. The rustdoc output is | |
714 | // then generated from the cleaned AST of the crate. This runs all the | |
715 | // plug/cleaning passes. | |
3dfed10e | 716 | let crate_version = options.crate_version.clone(); |
fc512014 XL |
717 | |
718 | let default_passes = options.default_passes; | |
3dfed10e | 719 | let output_format = options.output_format; |
fc512014 | 720 | // FIXME: fix this clone (especially render_options) |
17df50a5 | 721 | let externs = options.externs.clone(); |
fc512014 XL |
722 | let manual_passes = options.manual_passes.clone(); |
723 | let render_options = options.render_options.clone(); | |
724 | let config = core::create_config(options); | |
f035d41b | 725 | |
fc512014 XL |
726 | interface::create_compiler_and_run(config, |compiler| { |
727 | compiler.enter(|queries| { | |
728 | let sess = compiler.session(); | |
f035d41b | 729 | |
cdc7bbd5 XL |
730 | if sess.opts.describe_lints { |
731 | let (_, lint_store) = &*queries.register_plugins()?.peek(); | |
732 | describe_lints(sess, lint_store, true); | |
733 | return Ok(()); | |
734 | } | |
735 | ||
fc512014 XL |
736 | // We need to hold on to the complete resolver, so we cause everything to be |
737 | // cloned for the analysis passes to use. Suboptimal, but necessary in the | |
738 | // current architecture. | |
17df50a5 | 739 | let resolver = core::create_resolver(externs, queries, &sess); |
f035d41b | 740 | |
fc512014 XL |
741 | if sess.has_errors() { |
742 | sess.fatal("Compilation failed, aborting rustdoc"); | |
743 | } | |
f035d41b | 744 | |
5869c6ff | 745 | let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).peek_mut(); |
8faf50e0 | 746 | |
fc512014 | 747 | global_ctxt.enter(|tcx| { |
6a06907d | 748 | let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || { |
fc512014 XL |
749 | core::run_global_ctxt( |
750 | tcx, | |
751 | resolver, | |
752 | default_passes, | |
753 | manual_passes, | |
754 | render_options, | |
755 | output_format, | |
756 | ) | |
757 | }); | |
758 | info!("finished with rustc"); | |
759 | ||
6a06907d | 760 | cache.crate_version = crate_version; |
fc512014 XL |
761 | |
762 | if show_coverage { | |
763 | // if we ran coverage, bail early, we don't need to also generate docs at this point | |
764 | // (also we didn't load in any of the useful passes) | |
765 | return Ok(()); | |
766 | } else if run_check { | |
767 | // Since we're in "check" mode, no need to generate anything beyond this point. | |
768 | return Ok(()); | |
769 | } | |
770 | ||
771 | info!("going to format"); | |
fc512014 | 772 | match output_format { |
5869c6ff | 773 | config::OutputFormat::Html => sess.time("render_html", || { |
cdc7bbd5 | 774 | run_renderer::<html::render::Context<'_>>(krate, render_opts, cache, tcx) |
fc512014 | 775 | }), |
5869c6ff | 776 | config::OutputFormat::Json => sess.time("render_json", || { |
cdc7bbd5 | 777 | run_renderer::<json::JsonRenderer<'_>>(krate, render_opts, cache, tcx) |
fc512014 XL |
778 | }), |
779 | } | |
780 | }) | |
781 | }) | |
782 | }) | |
1a4d82fc | 783 | } |