]>
Commit | Line | Data |
---|---|---|
83c7162d | 1 | //! Documentation generation for rustbuilder. |
a7813a04 XL |
2 | //! |
3 | //! This module implements generation for all bits and pieces of documentation | |
4 | //! for the Rust project. This notably includes suites like the rust book, the | |
2c00a5a8 | 5 | //! nomicon, rust by example, standalone documentation, etc. |
a7813a04 XL |
6 | //! |
7 | //! Everything here is basically just a shim around calling either `rustbook` or | |
8 | //! `rustdoc`. | |
9 | ||
0531ce1d | 10 | use std::collections::HashSet; |
0731742a | 11 | use std::fs; |
8bb4bdeb | 12 | use std::io; |
dfeec247 | 13 | use std::path::{Path, PathBuf}; |
7453a54e | 14 | |
0731742a | 15 | use crate::Mode; |
48663c56 | 16 | use build_helper::{t, up_to_date}; |
7453a54e | 17 | |
0731742a | 18 | use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; |
dfeec247 | 19 | use crate::cache::{Interned, INTERNER}; |
0731742a | 20 | use crate::compile; |
3dfed10e | 21 | use crate::config::{Config, TargetSelection}; |
dfeec247 XL |
22 | use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; |
23 | use crate::util::symlink_dir; | |
3b2f2976 XL |
24 | |
25 | macro_rules! book { | |
416331ca | 26 | ($($name:ident, $path:expr, $book_name:expr;)+) => { |
3b2f2976 XL |
27 | $( |
28 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
29 | pub struct $name { | |
3dfed10e | 30 | target: TargetSelection, |
3b2f2976 XL |
31 | } |
32 | ||
33 | impl Step for $name { | |
34 | type Output = (); | |
35 | const DEFAULT: bool = true; | |
36 | ||
9fa01778 | 37 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 38 | let builder = run.builder; |
83c7162d | 39 | run.path($path).default_condition(builder.config.docs) |
3b2f2976 XL |
40 | } |
41 | ||
9fa01778 | 42 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
43 | run.builder.ensure($name { |
44 | target: run.target, | |
45 | }); | |
46 | } | |
47 | ||
9fa01778 | 48 | fn run(self, builder: &Builder<'_>) { |
dc9dc135 | 49 | builder.ensure(RustbookSrc { |
3b2f2976 XL |
50 | target: self.target, |
51 | name: INTERNER.intern_str($book_name), | |
dfeec247 | 52 | src: INTERNER.intern_path(builder.src.join($path)), |
3b2f2976 XL |
53 | }) |
54 | } | |
55 | } | |
56 | )+ | |
57 | } | |
041b39d2 XL |
58 | } |
59 | ||
9fa01778 XL |
60 | // NOTE: When adding a book here, make sure to ALSO build the book by |
61 | // adding a build step in `src/bootstrap/builder.rs`! | |
3b2f2976 | 62 | book!( |
dfeec247 | 63 | CargoBook, "src/tools/cargo/src/doc", "cargo"; |
416331ca XL |
64 | EditionGuide, "src/doc/edition-guide", "edition-guide"; |
65 | EmbeddedBook, "src/doc/embedded-book", "embedded-book"; | |
66 | Nomicon, "src/doc/nomicon", "nomicon"; | |
67 | Reference, "src/doc/reference", "reference"; | |
68 | RustByExample, "src/doc/rust-by-example", "rust-by-example"; | |
416331ca | 69 | RustdocBook, "src/doc/rustdoc", "rustdoc"; |
3b2f2976 XL |
70 | ); |
71 | ||
f9f354fc XL |
72 | fn open(builder: &Builder<'_>, path: impl AsRef<Path>) { |
73 | if builder.config.dry_run || !builder.config.cmd.open() { | |
74 | return; | |
75 | } | |
76 | ||
77 | let path = path.as_ref(); | |
78 | builder.info(&format!("Opening doc {}", path.display())); | |
79 | if let Err(err) = opener::open(path) { | |
80 | builder.info(&format!("{}\n", err)); | |
81 | } | |
82 | } | |
83 | ||
3dfed10e | 84 | // "library/std" -> ["library", "std"] |
f9f354fc XL |
85 | // |
86 | // Used for deciding whether a particular step is one requested by the user on | |
87 | // the `x.py doc` command line, which determines whether `--open` will open that | |
88 | // page. | |
89 | fn components_simplified(path: &PathBuf) -> Vec<&str> { | |
90 | path.iter().map(|component| component.to_str().unwrap_or("???")).collect() | |
91 | } | |
92 | ||
93 | fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool { | |
94 | builder | |
95 | .paths | |
96 | .iter() | |
97 | .map(components_simplified) | |
3dfed10e | 98 | .any(|requested| requested.iter().copied().eq(path.split('/'))) |
f9f354fc XL |
99 | } |
100 | ||
3b2f2976 XL |
101 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
102 | pub struct UnstableBook { | |
3dfed10e | 103 | target: TargetSelection, |
3b2f2976 | 104 | } |
cc61c64b | 105 | |
3b2f2976 XL |
106 | impl Step for UnstableBook { |
107 | type Output = (); | |
108 | const DEFAULT: bool = true; | |
cc61c64b | 109 | |
9fa01778 | 110 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 111 | let builder = run.builder; |
83c7162d | 112 | run.path("src/doc/unstable-book").default_condition(builder.config.docs) |
3b2f2976 XL |
113 | } |
114 | ||
9fa01778 | 115 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 116 | run.builder.ensure(UnstableBook { target: run.target }); |
3b2f2976 XL |
117 | } |
118 | ||
9fa01778 | 119 | fn run(self, builder: &Builder<'_>) { |
dfeec247 | 120 | builder.ensure(UnstableBookGen { target: self.target }); |
3b2f2976 XL |
121 | builder.ensure(RustbookSrc { |
122 | target: self.target, | |
123 | name: INTERNER.intern_str("unstable-book"), | |
dfeec247 | 124 | src: INTERNER.intern_path(builder.md_doc_out(self.target).join("unstable-book")), |
3b2f2976 XL |
125 | }) |
126 | } | |
127 | } | |
128 | ||
129 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
130 | struct RustbookSrc { | |
3dfed10e | 131 | target: TargetSelection, |
3b2f2976 XL |
132 | name: Interned<String>, |
133 | src: Interned<PathBuf>, | |
134 | } | |
135 | ||
136 | impl Step for RustbookSrc { | |
137 | type Output = (); | |
138 | ||
9fa01778 | 139 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
140 | run.never() |
141 | } | |
142 | ||
143 | /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path. | |
144 | /// | |
145 | /// This will not actually generate any documentation if the documentation has | |
146 | /// already been generated. | |
9fa01778 | 147 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
148 | let target = self.target; |
149 | let name = self.name; | |
150 | let src = self.src; | |
83c7162d | 151 | let out = builder.doc_out(target); |
3b2f2976 XL |
152 | t!(fs::create_dir_all(&out)); |
153 | ||
154 | let out = out.join(name); | |
3b2f2976 XL |
155 | let index = out.join("index.html"); |
156 | let rustbook = builder.tool_exe(Tool::Rustbook); | |
83c7162d | 157 | let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); |
f035d41b | 158 | if builder.config.dry_run || up_to_date(&src, &index) && up_to_date(&rustbook, &index) { |
dfeec247 | 159 | return; |
3b2f2976 | 160 | } |
83c7162d | 161 | builder.info(&format!("Rustbook ({}) - {}", target, name)); |
3b2f2976 | 162 | let _ = fs::remove_dir_all(&out); |
9fa01778 | 163 | |
dfeec247 | 164 | builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(out)); |
3b2f2976 XL |
165 | } |
166 | } | |
167 | ||
168 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
169 | pub struct TheBook { | |
170 | compiler: Compiler, | |
3dfed10e | 171 | target: TargetSelection, |
3b2f2976 | 172 | } |
cc61c64b | 173 | |
3b2f2976 XL |
174 | impl Step for TheBook { |
175 | type Output = (); | |
176 | const DEFAULT: bool = true; | |
177 | ||
9fa01778 | 178 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 179 | let builder = run.builder; |
83c7162d | 180 | run.path("src/doc/book").default_condition(builder.config.docs) |
3b2f2976 XL |
181 | } |
182 | ||
9fa01778 | 183 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 184 | run.builder.ensure(TheBook { |
83c7162d | 185 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 | 186 | target: run.target, |
3b2f2976 XL |
187 | }); |
188 | } | |
189 | ||
9fa01778 | 190 | /// Builds the book and associated stuff. |
3b2f2976 XL |
191 | /// |
192 | /// We need to build: | |
193 | /// | |
dfeec247 XL |
194 | /// * Book |
195 | /// * Older edition redirects | |
abe05a73 | 196 | /// * Version info and CSS |
3b2f2976 XL |
197 | /// * Index page |
198 | /// * Redirect pages | |
9fa01778 | 199 | fn run(self, builder: &Builder<'_>) { |
abe05a73 | 200 | let compiler = self.compiler; |
3b2f2976 | 201 | let target = self.target; |
13cf67c4 XL |
202 | |
203 | // build book | |
dc9dc135 | 204 | builder.ensure(RustbookSrc { |
3b2f2976 | 205 | target, |
dfeec247 XL |
206 | name: INTERNER.intern_str("book"), |
207 | src: INTERNER.intern_path(builder.src.join("src/doc/book")), | |
3b2f2976 XL |
208 | }); |
209 | ||
13cf67c4 | 210 | // building older edition redirects |
dfeec247 XL |
211 | for edition in &["first-edition", "second-edition", "2018-edition"] { |
212 | builder.ensure(RustbookSrc { | |
213 | target, | |
214 | name: INTERNER.intern_string(format!("book/{}", edition)), | |
215 | src: INTERNER.intern_path(builder.src.join("src/doc/book").join(edition)), | |
216 | }); | |
217 | } | |
94b46f34 | 218 | |
abe05a73 | 219 | // build the version info page and CSS |
dfeec247 | 220 | builder.ensure(Standalone { compiler, target }); |
abe05a73 | 221 | |
3b2f2976 | 222 | // build the redirect pages |
83c7162d XL |
223 | builder.info(&format!("Documenting book redirect pages ({})", target)); |
224 | for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) { | |
3b2f2976 XL |
225 | let file = t!(file); |
226 | let path = file.path(); | |
227 | let path = path.to_str().unwrap(); | |
228 | ||
abe05a73 | 229 | invoke_rustdoc(builder, compiler, target, path); |
3b2f2976 | 230 | } |
f9f354fc XL |
231 | |
232 | if is_explicit_request(builder, "src/doc/book") { | |
233 | let out = builder.doc_out(target); | |
234 | let index = out.join("book").join("index.html"); | |
235 | open(builder, &index); | |
236 | } | |
3b2f2976 XL |
237 | } |
238 | } | |
239 | ||
9fa01778 XL |
240 | fn invoke_rustdoc( |
241 | builder: &Builder<'_>, | |
242 | compiler: Compiler, | |
3dfed10e | 243 | target: TargetSelection, |
9fa01778 XL |
244 | markdown: &str, |
245 | ) { | |
83c7162d | 246 | let out = builder.doc_out(target); |
3b2f2976 | 247 | |
83c7162d | 248 | let path = builder.src.join("src/doc").join(markdown); |
cc61c64b | 249 | |
532ac7d7 | 250 | let header = builder.src.join("src/doc/redirect.inc"); |
83c7162d | 251 | let footer = builder.src.join("src/doc/footer.inc"); |
cc61c64b XL |
252 | let version_info = out.join("version_info.html"); |
253 | ||
532ac7d7 | 254 | let mut cmd = builder.rustdoc_cmd(compiler); |
cc61c64b XL |
255 | |
256 | let out = out.join("book"); | |
257 | ||
dfeec247 XL |
258 | cmd.arg("--html-after-content") |
259 | .arg(&footer) | |
260 | .arg("--html-before-content") | |
261 | .arg(&version_info) | |
262 | .arg("--html-in-header") | |
263 | .arg(&header) | |
0531ce1d | 264 | .arg("--markdown-no-toc") |
dfeec247 XL |
265 | .arg("--markdown-playground-url") |
266 | .arg("https://play.rust-lang.org/") | |
267 | .arg("-o") | |
268 | .arg(&out) | |
269 | .arg(&path) | |
270 | .arg("--markdown-css") | |
271 | .arg("../rust.css"); | |
cc61c64b | 272 | |
6a06907d XL |
273 | if !builder.config.docs_minification { |
274 | cmd.arg("-Z").arg("unstable-options").arg("--disable-minification"); | |
275 | } | |
276 | ||
83c7162d | 277 | builder.run(&mut cmd); |
cc61c64b XL |
278 | } |
279 | ||
3b2f2976 XL |
280 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
281 | pub struct Standalone { | |
282 | compiler: Compiler, | |
3dfed10e | 283 | target: TargetSelection, |
3b2f2976 | 284 | } |
7453a54e | 285 | |
3b2f2976 XL |
286 | impl Step for Standalone { |
287 | type Output = (); | |
288 | const DEFAULT: bool = true; | |
7453a54e | 289 | |
9fa01778 | 290 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 291 | let builder = run.builder; |
83c7162d | 292 | run.path("src/doc").default_condition(builder.config.docs) |
3b2f2976 | 293 | } |
7453a54e | 294 | |
9fa01778 | 295 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 296 | run.builder.ensure(Standalone { |
83c7162d | 297 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 XL |
298 | target: run.target, |
299 | }); | |
7453a54e SL |
300 | } |
301 | ||
3b2f2976 XL |
302 | /// Generates all standalone documentation as compiled by the rustdoc in `stage` |
303 | /// for the `target` into `out`. | |
304 | /// | |
305 | /// This will list all of `src/doc` looking for markdown files and appropriately | |
306 | /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and | |
307 | /// `STAMP` along with providing the various header/footer HTML we've customized. | |
308 | /// | |
309 | /// In the end, this is just a glorified wrapper around rustdoc! | |
9fa01778 | 310 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
311 | let target = self.target; |
312 | let compiler = self.compiler; | |
83c7162d XL |
313 | builder.info(&format!("Documenting standalone ({})", target)); |
314 | let out = builder.doc_out(target); | |
3b2f2976 XL |
315 | t!(fs::create_dir_all(&out)); |
316 | ||
83c7162d XL |
317 | let favicon = builder.src.join("src/doc/favicon.inc"); |
318 | let footer = builder.src.join("src/doc/footer.inc"); | |
319 | let full_toc = builder.src.join("src/doc/full-toc.inc"); | |
320 | t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css"))); | |
3b2f2976 | 321 | |
83c7162d | 322 | let version_input = builder.src.join("src/doc/version_info.html.template"); |
3b2f2976 XL |
323 | let version_info = out.join("version_info.html"); |
324 | ||
83c7162d | 325 | if !builder.config.dry_run && !up_to_date(&version_input, &version_info) { |
0731742a XL |
326 | let info = t!(fs::read_to_string(&version_input)) |
327 | .replace("VERSION", &builder.rust_release()) | |
328 | .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or("")) | |
329 | .replace("STAMP", builder.rust_info.sha().unwrap_or("")); | |
330 | t!(fs::write(&version_info, &info)); | |
7453a54e SL |
331 | } |
332 | ||
83c7162d | 333 | for file in t!(fs::read_dir(builder.src.join("src/doc"))) { |
3b2f2976 XL |
334 | let file = t!(file); |
335 | let path = file.path(); | |
336 | let filename = path.file_name().unwrap().to_str().unwrap(); | |
337 | if !filename.ends_with(".md") || filename == "README.md" { | |
dfeec247 | 338 | continue; |
3b2f2976 XL |
339 | } |
340 | ||
341 | let html = out.join(filename).with_extension("html"); | |
532ac7d7 | 342 | let rustdoc = builder.rustdoc(compiler); |
dfeec247 XL |
343 | if up_to_date(&path, &html) |
344 | && up_to_date(&footer, &html) | |
345 | && up_to_date(&favicon, &html) | |
346 | && up_to_date(&full_toc, &html) | |
347 | && (builder.config.dry_run || up_to_date(&version_info, &html)) | |
348 | && (builder.config.dry_run || up_to_date(&rustdoc, &html)) | |
349 | { | |
350 | continue; | |
3b2f2976 XL |
351 | } |
352 | ||
532ac7d7 | 353 | let mut cmd = builder.rustdoc_cmd(compiler); |
ba9703b0 XL |
354 | // Needed for --index-page flag |
355 | cmd.arg("-Z").arg("unstable-options"); | |
356 | ||
dfeec247 XL |
357 | cmd.arg("--html-after-content") |
358 | .arg(&footer) | |
359 | .arg("--html-before-content") | |
360 | .arg(&version_info) | |
361 | .arg("--html-in-header") | |
362 | .arg(&favicon) | |
363 | .arg("--markdown-no-toc") | |
364 | .arg("--index-page") | |
365 | .arg(&builder.src.join("src/doc/index.md")) | |
366 | .arg("--markdown-playground-url") | |
367 | .arg("https://play.rust-lang.org/") | |
368 | .arg("-o") | |
369 | .arg(&out) | |
370 | .arg(&path); | |
3b2f2976 | 371 | |
6a06907d XL |
372 | if !builder.config.docs_minification { |
373 | cmd.arg("--disable-minification"); | |
374 | } | |
375 | ||
3b2f2976 | 376 | if filename == "not_found.md" { |
dfeec247 | 377 | cmd.arg("--markdown-css").arg("https://doc.rust-lang.org/rust.css"); |
3b2f2976 XL |
378 | } else { |
379 | cmd.arg("--markdown-css").arg("rust.css"); | |
380 | } | |
83c7162d | 381 | builder.run(&mut cmd); |
7453a54e | 382 | } |
f9f354fc XL |
383 | |
384 | // We open doc/index.html as the default if invoked as `x.py doc --open` | |
3dfed10e | 385 | // with no particular explicit doc requested (e.g. library/core). |
f9f354fc XL |
386 | if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") { |
387 | let index = out.join("index.html"); | |
388 | open(builder, &index); | |
389 | } | |
3b2f2976 XL |
390 | } |
391 | } | |
392 | ||
393 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
394 | pub struct Std { | |
2c00a5a8 | 395 | pub stage: u32, |
3dfed10e | 396 | pub target: TargetSelection, |
3b2f2976 XL |
397 | } |
398 | ||
399 | impl Step for Std { | |
400 | type Output = (); | |
401 | const DEFAULT: bool = true; | |
402 | ||
9fa01778 | 403 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 404 | let builder = run.builder; |
e1599b0c | 405 | run.all_krates("test").default_condition(builder.config.docs) |
3b2f2976 XL |
406 | } |
407 | ||
9fa01778 | 408 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 409 | run.builder.ensure(Std { stage: run.builder.top_stage, target: run.target }); |
3b2f2976 | 410 | } |
7453a54e | 411 | |
3b2f2976 XL |
412 | /// Compile all standard library documentation. |
413 | /// | |
414 | /// This will generate all documentation for the standard library and its | |
415 | /// dependencies. This is largely just a wrapper around `cargo doc`. | |
9fa01778 | 416 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
417 | let stage = self.stage; |
418 | let target = self.target; | |
83c7162d XL |
419 | builder.info(&format!("Documenting stage{} std ({})", stage, target)); |
420 | let out = builder.doc_out(target); | |
3b2f2976 | 421 | t!(fs::create_dir_all(&out)); |
60c5eb7d | 422 | let compiler = builder.compiler(stage, builder.config.build); |
3b2f2976 XL |
423 | |
424 | builder.ensure(compile::Std { compiler, target }); | |
3dfed10e | 425 | let out_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join("doc"); |
3b2f2976 | 426 | |
a1dfa0c6 | 427 | t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css"))); |
3b2f2976 | 428 | |
a1dfa0c6 | 429 | let run_cargo_rustdoc_for = |package: &str| { |
f035d41b XL |
430 | let mut cargo = |
431 | builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); | |
f9f354fc | 432 | compile::std_cargo(builder, target, compiler.stage, &mut cargo); |
0531ce1d | 433 | |
dfeec247 | 434 | cargo |
3dfed10e XL |
435 | .arg("-p") |
436 | .arg(package) | |
dfeec247 XL |
437 | .arg("--") |
438 | .arg("--markdown-css") | |
439 | .arg("rust.css") | |
440 | .arg("--markdown-no-toc") | |
ba9703b0 XL |
441 | .arg("-Z") |
442 | .arg("unstable-options") | |
dfeec247 | 443 | .arg("--resource-suffix") |
1b1a35ee | 444 | .arg(&builder.version) |
dfeec247 XL |
445 | .arg("--index-page") |
446 | .arg(&builder.src.join("src/doc/index.md")); | |
a1dfa0c6 | 447 | |
6a06907d XL |
448 | if !builder.config.docs_minification { |
449 | cargo.arg("--disable-minification"); | |
450 | } | |
451 | ||
e1599b0c | 452 | builder.run(&mut cargo.into()); |
a1dfa0c6 | 453 | }; |
f035d41b XL |
454 | // Only build the following crates. While we could just iterate over the |
455 | // folder structure, that would also build internal crates that we do | |
456 | // not want to show in documentation. These crates will later be visited | |
457 | // by the rustc step, so internal documentation will show them. | |
3dfed10e XL |
458 | // |
459 | // Note that the order here is important! The crates need to be | |
460 | // processed starting from the leaves, otherwise rustdoc will not | |
461 | // create correct links between crates because rustdoc depends on the | |
462 | // existence of the output directories to know if it should be a local | |
463 | // or remote link. | |
464 | let krates = ["core", "alloc", "std", "proc_macro", "test"]; | |
f9f354fc | 465 | for krate in &krates { |
a1dfa0c6 | 466 | run_cargo_rustdoc_for(krate); |
7453a54e | 467 | } |
3dfed10e | 468 | builder.cp_r(&out_dir, &out); |
f9f354fc | 469 | |
3dfed10e | 470 | // Look for library/std, library/core etc in the `x.py doc` arguments and |
f9f354fc XL |
471 | // open the corresponding rendered docs. |
472 | for path in builder.paths.iter().map(components_simplified) { | |
3dfed10e XL |
473 | if path.get(0) == Some(&"library") { |
474 | let requested_crate = &path[1]; | |
f9f354fc XL |
475 | if krates.contains(&requested_crate) { |
476 | let index = out.join(requested_crate).join("index.html"); | |
477 | open(builder, &index); | |
478 | } | |
479 | } | |
480 | } | |
8bb4bdeb | 481 | } |
3b2f2976 | 482 | } |
8bb4bdeb | 483 | |
0531ce1d XL |
484 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
485 | pub struct Rustc { | |
486 | stage: u32, | |
3dfed10e | 487 | target: TargetSelection, |
0531ce1d XL |
488 | } |
489 | ||
490 | impl Step for Rustc { | |
491 | type Output = (); | |
492 | const DEFAULT: bool = true; | |
493 | const ONLY_HOSTS: bool = true; | |
494 | ||
9fa01778 | 495 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
0531ce1d | 496 | let builder = run.builder; |
83c7162d | 497 | run.krate("rustc-main").default_condition(builder.config.docs) |
0531ce1d XL |
498 | } |
499 | ||
9fa01778 | 500 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 501 | run.builder.ensure(Rustc { stage: run.builder.top_stage, target: run.target }); |
0531ce1d XL |
502 | } |
503 | ||
9fa01778 | 504 | /// Generates compiler documentation. |
0531ce1d XL |
505 | /// |
506 | /// This will generate all documentation for compiler and dependencies. | |
507 | /// Compiler documentation is distributed separately, so we make sure | |
508 | /// we do not merge it with the other documentation from std, test and | |
509 | /// proc_macros. This is largely just a wrapper around `cargo doc`. | |
9fa01778 | 510 | fn run(self, builder: &Builder<'_>) { |
0531ce1d XL |
511 | let stage = self.stage; |
512 | let target = self.target; | |
83c7162d | 513 | builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); |
94b46f34 | 514 | |
83c7162d | 515 | if !builder.config.compiler_docs { |
8faf50e0 | 516 | builder.info("\tskipping - compiler/librustdoc docs disabled"); |
0531ce1d XL |
517 | return; |
518 | } | |
519 | ||
5869c6ff XL |
520 | // This is the intended out directory for compiler documentation. |
521 | let out = builder.compiler_doc_out(target); | |
522 | t!(fs::create_dir_all(&out)); | |
523 | ||
94b46f34 | 524 | // Build rustc. |
5869c6ff | 525 | let compiler = builder.compiler(stage, builder.config.build); |
0531ce1d | 526 | builder.ensure(compile::Rustc { compiler, target }); |
94b46f34 | 527 | |
3dfed10e XL |
528 | // This uses a shared directory so that librustdoc documentation gets |
529 | // correctly built and merged with the rustc documentation. This is | |
530 | // needed because rustdoc is built in a different directory from | |
531 | // rustc. rustdoc needs to be able to see everything, for example when | |
532 | // merging the search index, or generating local (relative) links. | |
533 | let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc"); | |
83c7162d | 534 | t!(symlink_dir_force(&builder.config, &out, &out_dir)); |
5869c6ff XL |
535 | // Cargo puts proc macros in `target/doc` even if you pass `--target` |
536 | // explicitly (https://github.com/rust-lang/cargo/issues/7677). | |
537 | let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc"); | |
538 | t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir)); | |
0531ce1d | 539 | |
94b46f34 | 540 | // Build cargo command. |
f035d41b | 541 | let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc"); |
3dfed10e XL |
542 | cargo.rustdocflag("--document-private-items"); |
543 | cargo.rustdocflag("--enable-index-page"); | |
544 | cargo.rustdocflag("-Zunstable-options"); | |
5869c6ff | 545 | cargo.rustdocflag("-Znormalize-docs"); |
60c5eb7d | 546 | compile::rustc_cargo(builder, &mut cargo, target); |
0531ce1d XL |
547 | |
548 | // Only include compiler crates, no dependencies of those, such as `libc`. | |
549 | cargo.arg("--no-deps"); | |
550 | ||
551 | // Find dependencies for top level crates. | |
552 | let mut compiler_crates = HashSet::new(); | |
0731742a | 553 | for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { |
29967ef6 XL |
554 | compiler_crates.extend( |
555 | builder | |
556 | .in_tree_crates(root_crate, Some(target)) | |
557 | .into_iter() | |
558 | .map(|krate| krate.name), | |
559 | ); | |
0531ce1d XL |
560 | } |
561 | ||
562 | for krate in &compiler_crates { | |
0731742a XL |
563 | // Create all crate output directories first to make sure rustdoc uses |
564 | // relative links. | |
565 | // FIXME: Cargo should probably do this itself. | |
566 | t!(fs::create_dir_all(out_dir.join(krate))); | |
0531ce1d XL |
567 | cargo.arg("-p").arg(krate); |
568 | } | |
569 | ||
e1599b0c | 570 | builder.run(&mut cargo.into()); |
0531ce1d XL |
571 | } |
572 | } | |
573 | ||
94b46f34 XL |
574 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
575 | pub struct Rustdoc { | |
576 | stage: u32, | |
3dfed10e | 577 | target: TargetSelection, |
94b46f34 XL |
578 | } |
579 | ||
580 | impl Step for Rustdoc { | |
581 | type Output = (); | |
582 | const DEFAULT: bool = true; | |
583 | const ONLY_HOSTS: bool = true; | |
584 | ||
9fa01778 | 585 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
94b46f34 XL |
586 | run.krate("rustdoc-tool") |
587 | } | |
588 | ||
9fa01778 | 589 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 590 | run.builder.ensure(Rustdoc { stage: run.builder.top_stage, target: run.target }); |
94b46f34 XL |
591 | } |
592 | ||
9fa01778 | 593 | /// Generates compiler documentation. |
94b46f34 XL |
594 | /// |
595 | /// This will generate all documentation for compiler and dependencies. | |
596 | /// Compiler documentation is distributed separately, so we make sure | |
597 | /// we do not merge it with the other documentation from std, test and | |
598 | /// proc_macros. This is largely just a wrapper around `cargo doc`. | |
9fa01778 | 599 | fn run(self, builder: &Builder<'_>) { |
94b46f34 XL |
600 | let stage = self.stage; |
601 | let target = self.target; | |
602 | builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target)); | |
603 | ||
604 | // This is the intended out directory for compiler documentation. | |
605 | let out = builder.compiler_doc_out(target); | |
606 | t!(fs::create_dir_all(&out)); | |
607 | ||
f035d41b | 608 | let compiler = builder.compiler(stage, builder.config.build); |
94b46f34 XL |
609 | |
610 | if !builder.config.compiler_docs { | |
8faf50e0 | 611 | builder.info("\tskipping - compiler/librustdoc docs disabled"); |
94b46f34 XL |
612 | return; |
613 | } | |
614 | ||
0731742a XL |
615 | // Build rustc docs so that we generate relative links. |
616 | builder.ensure(Rustc { stage, target }); | |
94b46f34 XL |
617 | |
618 | // Build rustdoc. | |
74b04a01 | 619 | builder.ensure(tool::Rustdoc { compiler }); |
94b46f34 XL |
620 | |
621 | // Symlink compiler docs to the output directory of rustdoc documentation. | |
3dfed10e | 622 | let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc"); |
94b46f34 | 623 | t!(fs::create_dir_all(&out_dir)); |
94b46f34 XL |
624 | t!(symlink_dir_force(&builder.config, &out, &out_dir)); |
625 | ||
626 | // Build cargo command. | |
627 | let mut cargo = prepare_tool_cargo( | |
8faf50e0 XL |
628 | builder, |
629 | compiler, | |
630 | Mode::ToolRustc, | |
631 | target, | |
632 | "doc", | |
633 | "src/tools/rustdoc", | |
634 | SourceType::InTree, | |
dfeec247 | 635 | &[], |
8faf50e0 | 636 | ); |
94b46f34 | 637 | |
0731742a XL |
638 | // Only include compiler crates, no dependencies of those, such as `libc`. |
639 | cargo.arg("--no-deps"); | |
640 | cargo.arg("-p").arg("rustdoc"); | |
6a06907d | 641 | cargo.arg("-p").arg("rustdoc-json-types"); |
0731742a | 642 | |
3dfed10e | 643 | cargo.rustdocflag("--document-private-items"); |
5869c6ff XL |
644 | cargo.rustdocflag("--enable-index-page"); |
645 | cargo.rustdocflag("-Zunstable-options"); | |
e1599b0c | 646 | builder.run(&mut cargo.into()); |
94b46f34 XL |
647 | } |
648 | } | |
649 | ||
f035d41b | 650 | #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] |
3b2f2976 | 651 | pub struct ErrorIndex { |
3dfed10e | 652 | pub target: TargetSelection, |
54a0048b SL |
653 | } |
654 | ||
3b2f2976 XL |
655 | impl Step for ErrorIndex { |
656 | type Output = (); | |
657 | const DEFAULT: bool = true; | |
658 | const ONLY_HOSTS: bool = true; | |
659 | ||
9fa01778 | 660 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 661 | let builder = run.builder; |
83c7162d | 662 | run.path("src/tools/error_index_generator").default_condition(builder.config.docs) |
3b2f2976 XL |
663 | } |
664 | ||
9fa01778 | 665 | fn make_run(run: RunConfig<'_>) { |
f035d41b | 666 | let target = run.target; |
5869c6ff | 667 | run.builder.ensure(ErrorIndex { target }); |
3b2f2976 XL |
668 | } |
669 | ||
670 | /// Generates the HTML rendered error-index by running the | |
671 | /// `error_index_generator` tool. | |
9fa01778 | 672 | fn run(self, builder: &Builder<'_>) { |
f035d41b XL |
673 | builder.info(&format!("Documenting error index ({})", self.target)); |
674 | let out = builder.doc_out(self.target); | |
3b2f2976 | 675 | t!(fs::create_dir_all(&out)); |
5869c6ff | 676 | let mut index = tool::ErrorIndex::command(builder); |
3b2f2976 XL |
677 | index.arg("html"); |
678 | index.arg(out.join("error-index.html")); | |
1b1a35ee | 679 | index.arg(&builder.version); |
3b2f2976 | 680 | |
83c7162d | 681 | builder.run(&mut index); |
3b2f2976 XL |
682 | } |
683 | } | |
684 | ||
685 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
686 | pub struct UnstableBookGen { | |
3dfed10e | 687 | target: TargetSelection, |
54a0048b | 688 | } |
8bb4bdeb | 689 | |
3b2f2976 XL |
690 | impl Step for UnstableBookGen { |
691 | type Output = (); | |
692 | const DEFAULT: bool = true; | |
693 | const ONLY_HOSTS: bool = true; | |
041b39d2 | 694 | |
9fa01778 | 695 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 696 | let builder = run.builder; |
83c7162d | 697 | run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs) |
3b2f2976 XL |
698 | } |
699 | ||
9fa01778 | 700 | fn make_run(run: RunConfig<'_>) { |
dfeec247 | 701 | run.builder.ensure(UnstableBookGen { target: run.target }); |
3b2f2976 XL |
702 | } |
703 | ||
9fa01778 | 704 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
705 | let target = self.target; |
706 | ||
83c7162d XL |
707 | builder.info(&format!("Generating unstable book md files ({})", target)); |
708 | let out = builder.md_doc_out(target).join("unstable-book"); | |
709 | builder.create_dir(&out); | |
710 | builder.remove_dir(&out); | |
3b2f2976 | 711 | let mut cmd = builder.tool_cmd(Tool::UnstableBookGen); |
3dfed10e | 712 | cmd.arg(builder.src.join("library")); |
1b1a35ee | 713 | cmd.arg(builder.src.join("compiler")); |
83c7162d | 714 | cmd.arg(builder.src.join("src")); |
3b2f2976 XL |
715 | cmd.arg(out); |
716 | ||
83c7162d | 717 | builder.run(&mut cmd); |
3b2f2976 | 718 | } |
041b39d2 XL |
719 | } |
720 | ||
83c7162d XL |
721 | fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> { |
722 | if config.dry_run { | |
723 | return Ok(()); | |
724 | } | |
8bb4bdeb XL |
725 | if let Ok(m) = fs::symlink_metadata(dst) { |
726 | if m.file_type().is_dir() { | |
a1dfa0c6 | 727 | fs::remove_dir_all(dst)?; |
8bb4bdeb XL |
728 | } else { |
729 | // handle directory junctions on windows by falling back to | |
730 | // `remove_dir`. | |
dfeec247 | 731 | fs::remove_file(dst).or_else(|_| fs::remove_dir(dst))?; |
8bb4bdeb XL |
732 | } |
733 | } | |
734 | ||
83c7162d | 735 | symlink_dir(config, src, dst) |
8bb4bdeb | 736 | } |
1b1a35ee XL |
737 | |
738 | #[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
739 | pub struct RustcBook { | |
740 | pub compiler: Compiler, | |
741 | pub target: TargetSelection, | |
fc512014 | 742 | pub validate: bool, |
1b1a35ee XL |
743 | } |
744 | ||
745 | impl Step for RustcBook { | |
746 | type Output = (); | |
747 | const DEFAULT: bool = true; | |
748 | const ONLY_HOSTS: bool = true; | |
749 | ||
750 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { | |
751 | let builder = run.builder; | |
752 | run.path("src/doc/rustc").default_condition(builder.config.docs) | |
753 | } | |
754 | ||
755 | fn make_run(run: RunConfig<'_>) { | |
756 | run.builder.ensure(RustcBook { | |
757 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), | |
758 | target: run.target, | |
fc512014 | 759 | validate: false, |
1b1a35ee XL |
760 | }); |
761 | } | |
762 | ||
763 | /// Builds the rustc book. | |
764 | /// | |
765 | /// The lints are auto-generated by a tool, and then merged into the book | |
766 | /// in the "md-doc" directory in the build output directory. Then | |
767 | /// "rustbook" is used to convert it to HTML. | |
768 | fn run(self, builder: &Builder<'_>) { | |
769 | let out_base = builder.md_doc_out(self.target).join("rustc"); | |
770 | t!(fs::create_dir_all(&out_base)); | |
771 | let out_listing = out_base.join("src/lints"); | |
772 | builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); | |
773 | builder.info(&format!("Generating lint docs ({})", self.target)); | |
774 | ||
775 | let rustc = builder.rustc(self.compiler); | |
776 | // The tool runs `rustc` for extracting output examples, so it needs a | |
777 | // functional sysroot. | |
778 | builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); | |
779 | let mut cmd = builder.tool_cmd(Tool::LintDocs); | |
780 | cmd.arg("--src"); | |
781 | cmd.arg(builder.src.join("compiler")); | |
782 | cmd.arg("--out"); | |
783 | cmd.arg(&out_listing); | |
784 | cmd.arg("--rustc"); | |
785 | cmd.arg(&rustc); | |
786 | cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg()); | |
787 | if builder.config.verbose() { | |
788 | cmd.arg("--verbose"); | |
789 | } | |
fc512014 XL |
790 | if self.validate { |
791 | cmd.arg("--validate"); | |
792 | } | |
1b1a35ee XL |
793 | // If the lib directories are in an unusual location (changed in |
794 | // config.toml), then this needs to explicitly update the dylib search | |
795 | // path. | |
796 | builder.add_rustc_lib_path(self.compiler, &mut cmd); | |
797 | builder.run(&mut cmd); | |
798 | // Run rustbook/mdbook to generate the HTML pages. | |
799 | builder.ensure(RustbookSrc { | |
800 | target: self.target, | |
801 | name: INTERNER.intern_str("rustc"), | |
802 | src: INTERNER.intern_path(out_base), | |
803 | }); | |
804 | if is_explicit_request(builder, "src/doc/rustc") { | |
805 | let out = builder.doc_out(self.target); | |
806 | let index = out.join("rustc").join("index.html"); | |
807 | open(builder, &index); | |
808 | } | |
809 | } | |
810 | } |