]>
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; |
3b2f2976 | 13 | use std::path::{PathBuf, Path}; |
7453a54e | 14 | |
0731742a | 15 | use crate::Mode; |
48663c56 | 16 | use build_helper::{t, up_to_date}; |
7453a54e | 17 | |
0731742a XL |
18 | use crate::util::symlink_dir; |
19 | use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; | |
20 | use crate::tool::{self, prepare_tool_cargo, Tool, SourceType}; | |
21 | use crate::compile; | |
22 | use crate::cache::{INTERNER, Interned}; | |
23 | use crate::config::Config; | |
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 { | |
30 | target: Interned<String>, | |
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), | |
dc9dc135 | 52 | src: doc_src(builder), |
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!( |
416331ca XL |
63 | EditionGuide, "src/doc/edition-guide", "edition-guide"; |
64 | EmbeddedBook, "src/doc/embedded-book", "embedded-book"; | |
65 | Nomicon, "src/doc/nomicon", "nomicon"; | |
66 | Reference, "src/doc/reference", "reference"; | |
67 | RustByExample, "src/doc/rust-by-example", "rust-by-example"; | |
68 | RustcBook, "src/doc/rustc", "rustc"; | |
69 | RustdocBook, "src/doc/rustdoc", "rustdoc"; | |
3b2f2976 XL |
70 | ); |
71 | ||
dc9dc135 XL |
72 | fn doc_src(builder: &Builder<'_>) -> Interned<PathBuf> { |
73 | INTERNER.intern_path(builder.src.join("src/doc")) | |
cc61c64b XL |
74 | } |
75 | ||
3b2f2976 XL |
76 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
77 | pub struct UnstableBook { | |
78 | target: Interned<String>, | |
79 | } | |
cc61c64b | 80 | |
3b2f2976 XL |
81 | impl Step for UnstableBook { |
82 | type Output = (); | |
83 | const DEFAULT: bool = true; | |
cc61c64b | 84 | |
9fa01778 | 85 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 86 | let builder = run.builder; |
83c7162d | 87 | run.path("src/doc/unstable-book").default_condition(builder.config.docs) |
3b2f2976 XL |
88 | } |
89 | ||
9fa01778 | 90 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
91 | run.builder.ensure(UnstableBook { |
92 | target: run.target, | |
93 | }); | |
94 | } | |
95 | ||
9fa01778 | 96 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
97 | builder.ensure(UnstableBookGen { |
98 | target: self.target, | |
99 | }); | |
100 | builder.ensure(RustbookSrc { | |
101 | target: self.target, | |
102 | name: INTERNER.intern_str("unstable-book"), | |
83c7162d | 103 | src: builder.md_doc_out(self.target), |
3b2f2976 XL |
104 | }) |
105 | } | |
106 | } | |
107 | ||
abe05a73 XL |
108 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
109 | pub struct CargoBook { | |
110 | target: Interned<String>, | |
111 | name: Interned<String>, | |
112 | } | |
113 | ||
114 | impl Step for CargoBook { | |
115 | type Output = (); | |
116 | const DEFAULT: bool = true; | |
117 | ||
9fa01778 | 118 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
abe05a73 | 119 | let builder = run.builder; |
83c7162d | 120 | run.path("src/tools/cargo/src/doc/book").default_condition(builder.config.docs) |
abe05a73 XL |
121 | } |
122 | ||
9fa01778 | 123 | fn make_run(run: RunConfig<'_>) { |
abe05a73 XL |
124 | run.builder.ensure(CargoBook { |
125 | target: run.target, | |
126 | name: INTERNER.intern_str("cargo"), | |
127 | }); | |
128 | } | |
129 | ||
9fa01778 | 130 | fn run(self, builder: &Builder<'_>) { |
abe05a73 XL |
131 | let target = self.target; |
132 | let name = self.name; | |
83c7162d | 133 | let src = builder.src.join("src/tools/cargo/src/doc"); |
abe05a73 | 134 | |
83c7162d | 135 | let out = builder.doc_out(target); |
abe05a73 XL |
136 | t!(fs::create_dir_all(&out)); |
137 | ||
138 | let out = out.join(name); | |
139 | ||
83c7162d | 140 | builder.info(&format!("Cargo Book ({}) - {}", target, name)); |
abe05a73 XL |
141 | |
142 | let _ = fs::remove_dir_all(&out); | |
143 | ||
83c7162d | 144 | builder.run(builder.tool_cmd(Tool::Rustbook) |
abe05a73 XL |
145 | .arg("build") |
146 | .arg(&src) | |
147 | .arg("-d") | |
148 | .arg(out)); | |
149 | } | |
150 | } | |
151 | ||
3b2f2976 XL |
152 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
153 | struct RustbookSrc { | |
154 | target: Interned<String>, | |
155 | name: Interned<String>, | |
156 | src: Interned<PathBuf>, | |
157 | } | |
158 | ||
159 | impl Step for RustbookSrc { | |
160 | type Output = (); | |
161 | ||
9fa01778 | 162 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 XL |
163 | run.never() |
164 | } | |
165 | ||
166 | /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path. | |
167 | /// | |
168 | /// This will not actually generate any documentation if the documentation has | |
169 | /// already been generated. | |
9fa01778 | 170 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
171 | let target = self.target; |
172 | let name = self.name; | |
173 | let src = self.src; | |
83c7162d | 174 | let out = builder.doc_out(target); |
3b2f2976 XL |
175 | t!(fs::create_dir_all(&out)); |
176 | ||
177 | let out = out.join(name); | |
178 | let src = src.join(name); | |
179 | let index = out.join("index.html"); | |
180 | let rustbook = builder.tool_exe(Tool::Rustbook); | |
83c7162d | 181 | let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); |
3b2f2976 XL |
182 | if up_to_date(&src, &index) && up_to_date(&rustbook, &index) { |
183 | return | |
184 | } | |
83c7162d | 185 | builder.info(&format!("Rustbook ({}) - {}", target, name)); |
3b2f2976 | 186 | let _ = fs::remove_dir_all(&out); |
9fa01778 | 187 | |
83c7162d | 188 | builder.run(rustbook_cmd |
3b2f2976 XL |
189 | .arg("build") |
190 | .arg(&src) | |
191 | .arg("-d") | |
416331ca | 192 | .arg(out)); |
3b2f2976 XL |
193 | } |
194 | } | |
195 | ||
196 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
197 | pub struct TheBook { | |
198 | compiler: Compiler, | |
199 | target: Interned<String>, | |
200 | name: &'static str, | |
201 | } | |
cc61c64b | 202 | |
3b2f2976 XL |
203 | impl Step for TheBook { |
204 | type Output = (); | |
205 | const DEFAULT: bool = true; | |
206 | ||
9fa01778 | 207 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 208 | let builder = run.builder; |
83c7162d | 209 | run.path("src/doc/book").default_condition(builder.config.docs) |
3b2f2976 XL |
210 | } |
211 | ||
9fa01778 | 212 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 213 | run.builder.ensure(TheBook { |
83c7162d | 214 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 XL |
215 | target: run.target, |
216 | name: "book", | |
217 | }); | |
218 | } | |
219 | ||
9fa01778 | 220 | /// Builds the book and associated stuff. |
3b2f2976 XL |
221 | /// |
222 | /// We need to build: | |
223 | /// | |
224 | /// * Book (first edition) | |
225 | /// * Book (second edition) | |
abe05a73 | 226 | /// * Version info and CSS |
3b2f2976 XL |
227 | /// * Index page |
228 | /// * Redirect pages | |
9fa01778 | 229 | fn run(self, builder: &Builder<'_>) { |
abe05a73 | 230 | let compiler = self.compiler; |
3b2f2976 XL |
231 | let target = self.target; |
232 | let name = self.name; | |
13cf67c4 XL |
233 | |
234 | // build book | |
dc9dc135 | 235 | builder.ensure(RustbookSrc { |
3b2f2976 | 236 | target, |
13cf67c4 | 237 | name: INTERNER.intern_string(name.to_string()), |
dc9dc135 | 238 | src: doc_src(builder), |
3b2f2976 XL |
239 | }); |
240 | ||
13cf67c4 XL |
241 | // building older edition redirects |
242 | ||
243 | let source_name = format!("{}/first-edition", name); | |
dc9dc135 | 244 | builder.ensure(RustbookSrc { |
3b2f2976 | 245 | target, |
13cf67c4 | 246 | name: INTERNER.intern_string(source_name), |
dc9dc135 | 247 | src: doc_src(builder), |
3b2f2976 XL |
248 | }); |
249 | ||
13cf67c4 | 250 | let source_name = format!("{}/second-edition", name); |
dc9dc135 | 251 | builder.ensure(RustbookSrc { |
94b46f34 | 252 | target, |
13cf67c4 | 253 | name: INTERNER.intern_string(source_name), |
dc9dc135 | 254 | src: doc_src(builder), |
13cf67c4 XL |
255 | }); |
256 | ||
257 | let source_name = format!("{}/2018-edition", name); | |
dc9dc135 | 258 | builder.ensure(RustbookSrc { |
13cf67c4 XL |
259 | target, |
260 | name: INTERNER.intern_string(source_name), | |
dc9dc135 | 261 | src: doc_src(builder), |
94b46f34 XL |
262 | }); |
263 | ||
abe05a73 XL |
264 | // build the version info page and CSS |
265 | builder.ensure(Standalone { | |
266 | compiler, | |
267 | target, | |
268 | }); | |
269 | ||
3b2f2976 | 270 | // build the redirect pages |
83c7162d XL |
271 | builder.info(&format!("Documenting book redirect pages ({})", target)); |
272 | for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) { | |
3b2f2976 XL |
273 | let file = t!(file); |
274 | let path = file.path(); | |
275 | let path = path.to_str().unwrap(); | |
276 | ||
abe05a73 | 277 | invoke_rustdoc(builder, compiler, target, path); |
3b2f2976 XL |
278 | } |
279 | } | |
280 | } | |
281 | ||
9fa01778 XL |
282 | fn invoke_rustdoc( |
283 | builder: &Builder<'_>, | |
284 | compiler: Compiler, | |
285 | target: Interned<String>, | |
286 | markdown: &str, | |
287 | ) { | |
83c7162d | 288 | let out = builder.doc_out(target); |
3b2f2976 | 289 | |
83c7162d | 290 | let path = builder.src.join("src/doc").join(markdown); |
cc61c64b | 291 | |
532ac7d7 | 292 | let header = builder.src.join("src/doc/redirect.inc"); |
83c7162d | 293 | let footer = builder.src.join("src/doc/footer.inc"); |
cc61c64b XL |
294 | let version_info = out.join("version_info.html"); |
295 | ||
532ac7d7 | 296 | let mut cmd = builder.rustdoc_cmd(compiler); |
cc61c64b XL |
297 | |
298 | let out = out.join("book"); | |
299 | ||
cc61c64b XL |
300 | cmd.arg("--html-after-content").arg(&footer) |
301 | .arg("--html-before-content").arg(&version_info) | |
532ac7d7 | 302 | .arg("--html-in-header").arg(&header) |
0531ce1d | 303 | .arg("--markdown-no-toc") |
9fa01778 XL |
304 | .arg("--markdown-playground-url").arg("https://play.rust-lang.org/") |
305 | .arg("-o").arg(&out).arg(&path) | |
306 | .arg("--markdown-css").arg("../rust.css"); | |
cc61c64b | 307 | |
83c7162d | 308 | builder.run(&mut cmd); |
cc61c64b XL |
309 | } |
310 | ||
3b2f2976 XL |
311 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
312 | pub struct Standalone { | |
313 | compiler: Compiler, | |
314 | target: Interned<String>, | |
315 | } | |
7453a54e | 316 | |
3b2f2976 XL |
317 | impl Step for Standalone { |
318 | type Output = (); | |
319 | const DEFAULT: bool = true; | |
7453a54e | 320 | |
9fa01778 | 321 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 322 | let builder = run.builder; |
83c7162d | 323 | run.path("src/doc").default_condition(builder.config.docs) |
3b2f2976 | 324 | } |
7453a54e | 325 | |
9fa01778 | 326 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 | 327 | run.builder.ensure(Standalone { |
83c7162d | 328 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), |
3b2f2976 XL |
329 | target: run.target, |
330 | }); | |
7453a54e SL |
331 | } |
332 | ||
3b2f2976 XL |
333 | /// Generates all standalone documentation as compiled by the rustdoc in `stage` |
334 | /// for the `target` into `out`. | |
335 | /// | |
336 | /// This will list all of `src/doc` looking for markdown files and appropriately | |
337 | /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and | |
338 | /// `STAMP` along with providing the various header/footer HTML we've customized. | |
339 | /// | |
340 | /// In the end, this is just a glorified wrapper around rustdoc! | |
9fa01778 | 341 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
342 | let target = self.target; |
343 | let compiler = self.compiler; | |
83c7162d XL |
344 | builder.info(&format!("Documenting standalone ({})", target)); |
345 | let out = builder.doc_out(target); | |
3b2f2976 XL |
346 | t!(fs::create_dir_all(&out)); |
347 | ||
83c7162d XL |
348 | let favicon = builder.src.join("src/doc/favicon.inc"); |
349 | let footer = builder.src.join("src/doc/footer.inc"); | |
350 | let full_toc = builder.src.join("src/doc/full-toc.inc"); | |
351 | t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css"))); | |
3b2f2976 | 352 | |
83c7162d | 353 | let version_input = builder.src.join("src/doc/version_info.html.template"); |
3b2f2976 XL |
354 | let version_info = out.join("version_info.html"); |
355 | ||
83c7162d | 356 | if !builder.config.dry_run && !up_to_date(&version_input, &version_info) { |
0731742a XL |
357 | let info = t!(fs::read_to_string(&version_input)) |
358 | .replace("VERSION", &builder.rust_release()) | |
359 | .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or("")) | |
360 | .replace("STAMP", builder.rust_info.sha().unwrap_or("")); | |
361 | t!(fs::write(&version_info, &info)); | |
7453a54e SL |
362 | } |
363 | ||
83c7162d | 364 | for file in t!(fs::read_dir(builder.src.join("src/doc"))) { |
3b2f2976 XL |
365 | let file = t!(file); |
366 | let path = file.path(); | |
367 | let filename = path.file_name().unwrap().to_str().unwrap(); | |
368 | if !filename.ends_with(".md") || filename == "README.md" { | |
369 | continue | |
370 | } | |
371 | ||
372 | let html = out.join(filename).with_extension("html"); | |
532ac7d7 | 373 | let rustdoc = builder.rustdoc(compiler); |
3b2f2976 XL |
374 | if up_to_date(&path, &html) && |
375 | up_to_date(&footer, &html) && | |
376 | up_to_date(&favicon, &html) && | |
377 | up_to_date(&full_toc, &html) && | |
e1599b0c | 378 | (builder.config.dry_run || up_to_date(&version_info, &html)) && |
83c7162d | 379 | (builder.config.dry_run || up_to_date(&rustdoc, &html)) { |
3b2f2976 XL |
380 | continue |
381 | } | |
382 | ||
532ac7d7 | 383 | let mut cmd = builder.rustdoc_cmd(compiler); |
3b2f2976 XL |
384 | cmd.arg("--html-after-content").arg(&footer) |
385 | .arg("--html-before-content").arg(&version_info) | |
386 | .arg("--html-in-header").arg(&favicon) | |
a1dfa0c6 XL |
387 | .arg("--markdown-no-toc") |
388 | .arg("--index-page").arg(&builder.src.join("src/doc/index.md")) | |
9fa01778 | 389 | .arg("--markdown-playground-url").arg("https://play.rust-lang.org/") |
3b2f2976 XL |
390 | .arg("-o").arg(&out) |
391 | .arg(&path); | |
392 | ||
393 | if filename == "not_found.md" { | |
a1dfa0c6 | 394 | cmd.arg("--markdown-css") |
3b2f2976 XL |
395 | .arg("https://doc.rust-lang.org/rust.css"); |
396 | } else { | |
397 | cmd.arg("--markdown-css").arg("rust.css"); | |
398 | } | |
83c7162d | 399 | builder.run(&mut cmd); |
7453a54e | 400 | } |
3b2f2976 XL |
401 | } |
402 | } | |
403 | ||
404 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
405 | pub struct Std { | |
2c00a5a8 XL |
406 | pub stage: u32, |
407 | pub target: Interned<String>, | |
3b2f2976 XL |
408 | } |
409 | ||
410 | impl Step for Std { | |
411 | type Output = (); | |
412 | const DEFAULT: bool = true; | |
413 | ||
9fa01778 | 414 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 415 | let builder = run.builder; |
e1599b0c | 416 | run.all_krates("test").default_condition(builder.config.docs) |
3b2f2976 XL |
417 | } |
418 | ||
9fa01778 | 419 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
420 | run.builder.ensure(Std { |
421 | stage: run.builder.top_stage, | |
422 | target: run.target | |
423 | }); | |
424 | } | |
7453a54e | 425 | |
3b2f2976 XL |
426 | /// Compile all standard library documentation. |
427 | /// | |
428 | /// This will generate all documentation for the standard library and its | |
429 | /// dependencies. This is largely just a wrapper around `cargo doc`. | |
9fa01778 | 430 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
431 | let stage = self.stage; |
432 | let target = self.target; | |
83c7162d XL |
433 | builder.info(&format!("Documenting stage{} std ({})", stage, target)); |
434 | let out = builder.doc_out(target); | |
3b2f2976 | 435 | t!(fs::create_dir_all(&out)); |
60c5eb7d | 436 | let compiler = builder.compiler(stage, builder.config.build); |
3b2f2976 XL |
437 | |
438 | builder.ensure(compile::Std { compiler, target }); | |
94b46f34 | 439 | let out_dir = builder.stage_out(compiler, Mode::Std) |
3b2f2976 XL |
440 | .join(target).join("doc"); |
441 | ||
442 | // Here what we're doing is creating a *symlink* (directory junction on | |
443 | // Windows) to the final output location. This is not done as an | |
444 | // optimization but rather for correctness. We've got three trees of | |
445 | // documentation, one for std, one for test, and one for rustc. It's then | |
446 | // our job to merge them all together. | |
447 | // | |
448 | // Unfortunately rustbuild doesn't know nearly as well how to merge doc | |
449 | // trees as rustdoc does itself, so instead of actually having three | |
450 | // separate trees we just have rustdoc output to the same location across | |
451 | // all of them. | |
452 | // | |
453 | // This way rustdoc generates output directly into the output, and rustdoc | |
454 | // will also directly handle merging. | |
83c7162d | 455 | let my_out = builder.crate_doc_out(target); |
83c7162d | 456 | t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); |
a1dfa0c6 | 457 | t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css"))); |
3b2f2976 | 458 | |
a1dfa0c6 XL |
459 | let run_cargo_rustdoc_for = |package: &str| { |
460 | let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc"); | |
461 | compile::std_cargo(builder, &compiler, target, &mut cargo); | |
0531ce1d | 462 | |
a1dfa0c6 XL |
463 | // Keep a whitelist so we do not build internal stdlib crates, these will be |
464 | // build by the rustc step later if enabled. | |
465 | cargo.arg("-Z").arg("unstable-options") | |
466 | .arg("-p").arg(package); | |
0531ce1d XL |
467 | // Create all crate output directories first to make sure rustdoc uses |
468 | // relative links. | |
469 | // FIXME: Cargo should probably do this itself. | |
a1dfa0c6 XL |
470 | t!(fs::create_dir_all(out_dir.join(package))); |
471 | cargo.arg("--") | |
472 | .arg("--markdown-css").arg("rust.css") | |
473 | .arg("--markdown-no-toc") | |
9fa01778 XL |
474 | .arg("--generate-redirect-pages") |
475 | .arg("--resource-suffix").arg(crate::channel::CFG_RELEASE_NUM) | |
a1dfa0c6 XL |
476 | .arg("--index-page").arg(&builder.src.join("src/doc/index.md")); |
477 | ||
e1599b0c | 478 | builder.run(&mut cargo.into()); |
a1dfa0c6 | 479 | }; |
e1599b0c | 480 | for krate in &["alloc", "core", "std", "proc_macro", "test"] { |
a1dfa0c6 | 481 | run_cargo_rustdoc_for(krate); |
7453a54e | 482 | } |
83c7162d | 483 | builder.cp_r(&my_out, &out); |
8bb4bdeb | 484 | } |
3b2f2976 | 485 | } |
8bb4bdeb | 486 | |
0531ce1d XL |
487 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
488 | pub struct Rustc { | |
489 | stage: u32, | |
490 | target: Interned<String>, | |
491 | } | |
492 | ||
493 | impl Step for Rustc { | |
494 | type Output = (); | |
495 | const DEFAULT: bool = true; | |
496 | const ONLY_HOSTS: bool = true; | |
497 | ||
9fa01778 | 498 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
0531ce1d | 499 | let builder = run.builder; |
83c7162d | 500 | run.krate("rustc-main").default_condition(builder.config.docs) |
0531ce1d XL |
501 | } |
502 | ||
9fa01778 | 503 | fn make_run(run: RunConfig<'_>) { |
0531ce1d XL |
504 | run.builder.ensure(Rustc { |
505 | stage: run.builder.top_stage, | |
506 | target: run.target, | |
507 | }); | |
508 | } | |
509 | ||
9fa01778 | 510 | /// Generates compiler documentation. |
0531ce1d XL |
511 | /// |
512 | /// This will generate all documentation for compiler and dependencies. | |
513 | /// Compiler documentation is distributed separately, so we make sure | |
514 | /// we do not merge it with the other documentation from std, test and | |
515 | /// proc_macros. This is largely just a wrapper around `cargo doc`. | |
9fa01778 | 516 | fn run(self, builder: &Builder<'_>) { |
0531ce1d XL |
517 | let stage = self.stage; |
518 | let target = self.target; | |
83c7162d | 519 | builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); |
94b46f34 XL |
520 | |
521 | // This is the intended out directory for compiler documentation. | |
83c7162d | 522 | let out = builder.compiler_doc_out(target); |
0531ce1d | 523 | t!(fs::create_dir_all(&out)); |
94b46f34 XL |
524 | |
525 | // Get the correct compiler for this stage. | |
dc9dc135 | 526 | let compiler = builder.compiler_for(stage, builder.config.build, target); |
0531ce1d | 527 | |
83c7162d | 528 | if !builder.config.compiler_docs { |
8faf50e0 | 529 | builder.info("\tskipping - compiler/librustdoc docs disabled"); |
0531ce1d XL |
530 | return; |
531 | } | |
532 | ||
94b46f34 | 533 | // Build rustc. |
0531ce1d | 534 | builder.ensure(compile::Rustc { compiler, target }); |
94b46f34 | 535 | |
0531ce1d XL |
536 | // We do not symlink to the same shared folder that already contains std library |
537 | // documentation from previous steps as we do not want to include that. | |
94b46f34 | 538 | let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc"); |
83c7162d | 539 | t!(symlink_dir_force(&builder.config, &out, &out_dir)); |
0531ce1d | 540 | |
94b46f34 XL |
541 | // Build cargo command. |
542 | let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); | |
dc9dc135 | 543 | cargo.env("RUSTDOCFLAGS", "--document-private-items --passes strip-hidden"); |
60c5eb7d | 544 | compile::rustc_cargo(builder, &mut cargo, target); |
0531ce1d XL |
545 | |
546 | // Only include compiler crates, no dependencies of those, such as `libc`. | |
547 | cargo.arg("--no-deps"); | |
548 | ||
549 | // Find dependencies for top level crates. | |
550 | let mut compiler_crates = HashSet::new(); | |
0731742a | 551 | for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { |
0531ce1d | 552 | let interned_root_crate = INTERNER.intern_str(root_crate); |
83c7162d | 553 | find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates); |
0531ce1d XL |
554 | } |
555 | ||
556 | for krate in &compiler_crates { | |
0731742a XL |
557 | // Create all crate output directories first to make sure rustdoc uses |
558 | // relative links. | |
559 | // FIXME: Cargo should probably do this itself. | |
560 | t!(fs::create_dir_all(out_dir.join(krate))); | |
0531ce1d XL |
561 | cargo.arg("-p").arg(krate); |
562 | } | |
563 | ||
e1599b0c | 564 | builder.run(&mut cargo.into()); |
0531ce1d XL |
565 | } |
566 | } | |
567 | ||
568 | fn find_compiler_crates( | |
9fa01778 | 569 | builder: &Builder<'_>, |
0531ce1d XL |
570 | name: &Interned<String>, |
571 | crates: &mut HashSet<Interned<String>> | |
572 | ) { | |
573 | // Add current crate. | |
574 | crates.insert(*name); | |
575 | ||
576 | // Look for dependencies. | |
83c7162d XL |
577 | for dep in builder.crates.get(name).unwrap().deps.iter() { |
578 | if builder.crates.get(dep).unwrap().is_local(builder) { | |
579 | find_compiler_crates(builder, dep, crates); | |
0531ce1d XL |
580 | } |
581 | } | |
582 | } | |
583 | ||
94b46f34 XL |
584 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
585 | pub struct Rustdoc { | |
586 | stage: u32, | |
587 | target: Interned<String>, | |
588 | } | |
589 | ||
590 | impl Step for Rustdoc { | |
591 | type Output = (); | |
592 | const DEFAULT: bool = true; | |
593 | const ONLY_HOSTS: bool = true; | |
594 | ||
9fa01778 | 595 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
94b46f34 XL |
596 | run.krate("rustdoc-tool") |
597 | } | |
598 | ||
9fa01778 | 599 | fn make_run(run: RunConfig<'_>) { |
94b46f34 XL |
600 | run.builder.ensure(Rustdoc { |
601 | stage: run.builder.top_stage, | |
602 | target: run.target, | |
603 | }); | |
604 | } | |
605 | ||
9fa01778 | 606 | /// Generates compiler documentation. |
94b46f34 XL |
607 | /// |
608 | /// This will generate all documentation for compiler and dependencies. | |
609 | /// Compiler documentation is distributed separately, so we make sure | |
610 | /// we do not merge it with the other documentation from std, test and | |
611 | /// proc_macros. This is largely just a wrapper around `cargo doc`. | |
9fa01778 | 612 | fn run(self, builder: &Builder<'_>) { |
94b46f34 XL |
613 | let stage = self.stage; |
614 | let target = self.target; | |
615 | builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target)); | |
616 | ||
617 | // This is the intended out directory for compiler documentation. | |
618 | let out = builder.compiler_doc_out(target); | |
619 | t!(fs::create_dir_all(&out)); | |
620 | ||
621 | // Get the correct compiler for this stage. | |
dc9dc135 | 622 | let compiler = builder.compiler_for(stage, builder.config.build, target); |
94b46f34 XL |
623 | |
624 | if !builder.config.compiler_docs { | |
8faf50e0 | 625 | builder.info("\tskipping - compiler/librustdoc docs disabled"); |
94b46f34 XL |
626 | return; |
627 | } | |
628 | ||
0731742a XL |
629 | // Build rustc docs so that we generate relative links. |
630 | builder.ensure(Rustc { stage, target }); | |
94b46f34 XL |
631 | |
632 | // Build rustdoc. | |
532ac7d7 | 633 | builder.ensure(tool::Rustdoc { compiler: compiler }); |
94b46f34 XL |
634 | |
635 | // Symlink compiler docs to the output directory of rustdoc documentation. | |
8faf50e0 XL |
636 | let out_dir = builder.stage_out(compiler, Mode::ToolRustc) |
637 | .join(target) | |
638 | .join("doc"); | |
94b46f34 | 639 | t!(fs::create_dir_all(&out_dir)); |
94b46f34 XL |
640 | t!(symlink_dir_force(&builder.config, &out, &out_dir)); |
641 | ||
642 | // Build cargo command. | |
643 | let mut cargo = prepare_tool_cargo( | |
8faf50e0 XL |
644 | builder, |
645 | compiler, | |
646 | Mode::ToolRustc, | |
647 | target, | |
648 | "doc", | |
649 | "src/tools/rustdoc", | |
650 | SourceType::InTree, | |
0bf4aa26 | 651 | &[] |
8faf50e0 | 652 | ); |
94b46f34 | 653 | |
0731742a XL |
654 | // Only include compiler crates, no dependencies of those, such as `libc`. |
655 | cargo.arg("--no-deps"); | |
656 | cargo.arg("-p").arg("rustdoc"); | |
657 | ||
94b46f34 | 658 | cargo.env("RUSTDOCFLAGS", "--document-private-items"); |
e1599b0c | 659 | builder.run(&mut cargo.into()); |
94b46f34 XL |
660 | } |
661 | } | |
662 | ||
3b2f2976 XL |
663 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
664 | pub struct ErrorIndex { | |
665 | target: Interned<String>, | |
54a0048b SL |
666 | } |
667 | ||
3b2f2976 XL |
668 | impl Step for ErrorIndex { |
669 | type Output = (); | |
670 | const DEFAULT: bool = true; | |
671 | const ONLY_HOSTS: bool = true; | |
672 | ||
9fa01778 | 673 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 674 | let builder = run.builder; |
83c7162d | 675 | run.path("src/tools/error_index_generator").default_condition(builder.config.docs) |
3b2f2976 XL |
676 | } |
677 | ||
9fa01778 | 678 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
679 | run.builder.ensure(ErrorIndex { |
680 | target: run.target, | |
681 | }); | |
682 | } | |
683 | ||
684 | /// Generates the HTML rendered error-index by running the | |
685 | /// `error_index_generator` tool. | |
9fa01778 | 686 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 | 687 | let target = self.target; |
54a0048b | 688 | |
83c7162d XL |
689 | builder.info(&format!("Documenting error index ({})", target)); |
690 | let out = builder.doc_out(target); | |
3b2f2976 | 691 | t!(fs::create_dir_all(&out)); |
532ac7d7 XL |
692 | let compiler = builder.compiler(2, builder.config.build); |
693 | let mut index = tool::ErrorIndex::command( | |
694 | builder, | |
695 | compiler, | |
696 | ); | |
3b2f2976 XL |
697 | index.arg("html"); |
698 | index.arg(out.join("error-index.html")); | |
9fa01778 | 699 | index.arg(crate::channel::CFG_RELEASE_NUM); |
3b2f2976 XL |
700 | |
701 | // FIXME: shouldn't have to pass this env var | |
e1599b0c | 702 | index.env("CFG_BUILD", &builder.config.build); |
3b2f2976 | 703 | |
83c7162d | 704 | builder.run(&mut index); |
3b2f2976 XL |
705 | } |
706 | } | |
707 | ||
708 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
709 | pub struct UnstableBookGen { | |
710 | target: Interned<String>, | |
54a0048b | 711 | } |
8bb4bdeb | 712 | |
3b2f2976 XL |
713 | impl Step for UnstableBookGen { |
714 | type Output = (); | |
715 | const DEFAULT: bool = true; | |
716 | const ONLY_HOSTS: bool = true; | |
041b39d2 | 717 | |
9fa01778 | 718 | fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { |
3b2f2976 | 719 | let builder = run.builder; |
83c7162d | 720 | run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs) |
3b2f2976 XL |
721 | } |
722 | ||
9fa01778 | 723 | fn make_run(run: RunConfig<'_>) { |
3b2f2976 XL |
724 | run.builder.ensure(UnstableBookGen { |
725 | target: run.target, | |
726 | }); | |
727 | } | |
728 | ||
9fa01778 | 729 | fn run(self, builder: &Builder<'_>) { |
3b2f2976 XL |
730 | let target = self.target; |
731 | ||
83c7162d XL |
732 | builder.info(&format!("Generating unstable book md files ({})", target)); |
733 | let out = builder.md_doc_out(target).join("unstable-book"); | |
734 | builder.create_dir(&out); | |
735 | builder.remove_dir(&out); | |
3b2f2976 | 736 | let mut cmd = builder.tool_cmd(Tool::UnstableBookGen); |
83c7162d | 737 | cmd.arg(builder.src.join("src")); |
3b2f2976 XL |
738 | cmd.arg(out); |
739 | ||
83c7162d | 740 | builder.run(&mut cmd); |
3b2f2976 | 741 | } |
041b39d2 XL |
742 | } |
743 | ||
83c7162d XL |
744 | fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> { |
745 | if config.dry_run { | |
746 | return Ok(()); | |
747 | } | |
8bb4bdeb XL |
748 | if let Ok(m) = fs::symlink_metadata(dst) { |
749 | if m.file_type().is_dir() { | |
a1dfa0c6 | 750 | fs::remove_dir_all(dst)?; |
8bb4bdeb XL |
751 | } else { |
752 | // handle directory junctions on windows by falling back to | |
753 | // `remove_dir`. | |
a1dfa0c6 | 754 | fs::remove_file(dst).or_else(|_| { |
8bb4bdeb | 755 | fs::remove_dir(dst) |
a1dfa0c6 | 756 | })?; |
8bb4bdeb XL |
757 | } |
758 | } | |
759 | ||
83c7162d | 760 | symlink_dir(config, src, dst) |
8bb4bdeb | 761 | } |