]>
Commit | Line | Data |
---|---|---|
7453a54e SL |
1 | // Copyright 2016 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
a7813a04 XL |
11 | //! Documentation generation for rustbuild. |
12 | //! | |
13 | //! This module implements generation for all bits and pieces of documentation | |
14 | //! for the Rust project. This notably includes suites like the rust book, the | |
2c00a5a8 | 15 | //! nomicon, rust by example, standalone documentation, etc. |
a7813a04 XL |
16 | //! |
17 | //! Everything here is basically just a shim around calling either `rustbook` or | |
18 | //! `rustdoc`. | |
19 | ||
0531ce1d | 20 | use std::collections::HashSet; |
7453a54e SL |
21 | use std::fs::{self, File}; |
22 | use std::io::prelude::*; | |
8bb4bdeb | 23 | use std::io; |
3b2f2976 | 24 | use std::path::{PathBuf, Path}; |
7453a54e | 25 | |
0531ce1d | 26 | use {Build, Mode}; |
8bb4bdeb | 27 | use build_helper::up_to_date; |
7453a54e | 28 | |
3b2f2976 XL |
29 | use util::{cp_r, symlink_dir}; |
30 | use builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; | |
31 | use tool::Tool; | |
32 | use compile; | |
33 | use cache::{INTERNER, Interned}; | |
34 | ||
35 | macro_rules! book { | |
36 | ($($name:ident, $path:expr, $book_name:expr;)+) => { | |
37 | $( | |
38 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
39 | pub struct $name { | |
40 | target: Interned<String>, | |
41 | } | |
42 | ||
43 | impl Step for $name { | |
44 | type Output = (); | |
45 | const DEFAULT: bool = true; | |
46 | ||
47 | fn should_run(run: ShouldRun) -> ShouldRun { | |
48 | let builder = run.builder; | |
49 | run.path($path).default_condition(builder.build.config.docs) | |
50 | } | |
51 | ||
52 | fn make_run(run: RunConfig) { | |
53 | run.builder.ensure($name { | |
54 | target: run.target, | |
55 | }); | |
56 | } | |
57 | ||
58 | fn run(self, builder: &Builder) { | |
59 | builder.ensure(Rustbook { | |
60 | target: self.target, | |
61 | name: INTERNER.intern_str($book_name), | |
62 | }) | |
63 | } | |
64 | } | |
65 | )+ | |
66 | } | |
041b39d2 XL |
67 | } |
68 | ||
3b2f2976 | 69 | book!( |
abe05a73 | 70 | Nomicon, "src/doc/nomicon", "nomicon"; |
3b2f2976 XL |
71 | Reference, "src/doc/reference", "reference"; |
72 | Rustdoc, "src/doc/rustdoc", "rustdoc"; | |
2c00a5a8 | 73 | RustByExample, "src/doc/rust-by-example", "rust-by-example"; |
3b2f2976 XL |
74 | ); |
75 | ||
76 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
77 | struct Rustbook { | |
78 | target: Interned<String>, | |
79 | name: Interned<String>, | |
7453a54e SL |
80 | } |
81 | ||
3b2f2976 XL |
82 | impl Step for Rustbook { |
83 | type Output = (); | |
84 | ||
85 | // rustbook is never directly called, and only serves as a shim for the nomicon and the | |
86 | // reference. | |
87 | fn should_run(run: ShouldRun) -> ShouldRun { | |
88 | run.never() | |
89 | } | |
90 | ||
91 | /// Invoke `rustbook` for `target` for the doc book `name`. | |
92 | /// | |
93 | /// This will not actually generate any documentation if the documentation has | |
94 | /// already been generated. | |
95 | fn run(self, builder: &Builder) { | |
96 | let src = builder.build.src.join("src/doc"); | |
97 | builder.ensure(RustbookSrc { | |
98 | target: self.target, | |
99 | name: self.name, | |
100 | src: INTERNER.intern_path(src), | |
101 | }); | |
cc61c64b XL |
102 | } |
103 | } | |
104 | ||
3b2f2976 XL |
105 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
106 | pub struct UnstableBook { | |
107 | target: Interned<String>, | |
108 | } | |
cc61c64b | 109 | |
3b2f2976 XL |
110 | impl Step for UnstableBook { |
111 | type Output = (); | |
112 | const DEFAULT: bool = true; | |
cc61c64b | 113 | |
3b2f2976 XL |
114 | fn should_run(run: ShouldRun) -> ShouldRun { |
115 | let builder = run.builder; | |
116 | run.path("src/doc/unstable-book").default_condition(builder.build.config.docs) | |
117 | } | |
118 | ||
119 | fn make_run(run: RunConfig) { | |
120 | run.builder.ensure(UnstableBook { | |
121 | target: run.target, | |
122 | }); | |
123 | } | |
124 | ||
125 | fn run(self, builder: &Builder) { | |
126 | builder.ensure(UnstableBookGen { | |
127 | target: self.target, | |
128 | }); | |
129 | builder.ensure(RustbookSrc { | |
130 | target: self.target, | |
131 | name: INTERNER.intern_str("unstable-book"), | |
132 | src: builder.build.md_doc_out(self.target), | |
133 | }) | |
134 | } | |
135 | } | |
136 | ||
abe05a73 XL |
137 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
138 | pub struct CargoBook { | |
139 | target: Interned<String>, | |
140 | name: Interned<String>, | |
141 | } | |
142 | ||
143 | impl Step for CargoBook { | |
144 | type Output = (); | |
145 | const DEFAULT: bool = true; | |
146 | ||
147 | fn should_run(run: ShouldRun) -> ShouldRun { | |
148 | let builder = run.builder; | |
149 | run.path("src/tools/cargo/src/doc/book").default_condition(builder.build.config.docs) | |
150 | } | |
151 | ||
152 | fn make_run(run: RunConfig) { | |
153 | run.builder.ensure(CargoBook { | |
154 | target: run.target, | |
155 | name: INTERNER.intern_str("cargo"), | |
156 | }); | |
157 | } | |
158 | ||
159 | fn run(self, builder: &Builder) { | |
160 | let build = builder.build; | |
161 | ||
162 | let target = self.target; | |
163 | let name = self.name; | |
2c00a5a8 | 164 | let src = build.src.join("src/tools/cargo/src/doc"); |
abe05a73 XL |
165 | |
166 | let out = build.doc_out(target); | |
167 | t!(fs::create_dir_all(&out)); | |
168 | ||
169 | let out = out.join(name); | |
170 | ||
171 | println!("Cargo Book ({}) - {}", target, name); | |
172 | ||
173 | let _ = fs::remove_dir_all(&out); | |
174 | ||
175 | build.run(builder.tool_cmd(Tool::Rustbook) | |
176 | .arg("build") | |
177 | .arg(&src) | |
178 | .arg("-d") | |
179 | .arg(out)); | |
180 | } | |
181 | } | |
182 | ||
3b2f2976 XL |
183 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
184 | struct RustbookSrc { | |
185 | target: Interned<String>, | |
186 | name: Interned<String>, | |
187 | src: Interned<PathBuf>, | |
188 | } | |
189 | ||
190 | impl Step for RustbookSrc { | |
191 | type Output = (); | |
192 | ||
193 | fn should_run(run: ShouldRun) -> ShouldRun { | |
194 | run.never() | |
195 | } | |
196 | ||
197 | /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path. | |
198 | /// | |
199 | /// This will not actually generate any documentation if the documentation has | |
200 | /// already been generated. | |
201 | fn run(self, builder: &Builder) { | |
202 | let build = builder.build; | |
203 | let target = self.target; | |
204 | let name = self.name; | |
205 | let src = self.src; | |
206 | let out = build.doc_out(target); | |
207 | t!(fs::create_dir_all(&out)); | |
208 | ||
209 | let out = out.join(name); | |
210 | let src = src.join(name); | |
211 | let index = out.join("index.html"); | |
212 | let rustbook = builder.tool_exe(Tool::Rustbook); | |
213 | if up_to_date(&src, &index) && up_to_date(&rustbook, &index) { | |
214 | return | |
215 | } | |
216 | println!("Rustbook ({}) - {}", target, name); | |
217 | let _ = fs::remove_dir_all(&out); | |
218 | build.run(builder.tool_cmd(Tool::Rustbook) | |
219 | .arg("build") | |
220 | .arg(&src) | |
221 | .arg("-d") | |
222 | .arg(out)); | |
223 | } | |
224 | } | |
225 | ||
226 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
227 | pub struct TheBook { | |
228 | compiler: Compiler, | |
229 | target: Interned<String>, | |
230 | name: &'static str, | |
231 | } | |
cc61c64b | 232 | |
3b2f2976 XL |
233 | impl Step for TheBook { |
234 | type Output = (); | |
235 | const DEFAULT: bool = true; | |
236 | ||
237 | fn should_run(run: ShouldRun) -> ShouldRun { | |
238 | let builder = run.builder; | |
239 | run.path("src/doc/book").default_condition(builder.build.config.docs) | |
240 | } | |
241 | ||
242 | fn make_run(run: RunConfig) { | |
243 | run.builder.ensure(TheBook { | |
244 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), | |
245 | target: run.target, | |
246 | name: "book", | |
247 | }); | |
248 | } | |
249 | ||
250 | /// Build the book and associated stuff. | |
251 | /// | |
252 | /// We need to build: | |
253 | /// | |
254 | /// * Book (first edition) | |
255 | /// * Book (second edition) | |
abe05a73 | 256 | /// * Version info and CSS |
3b2f2976 XL |
257 | /// * Index page |
258 | /// * Redirect pages | |
259 | fn run(self, builder: &Builder) { | |
260 | let build = builder.build; | |
abe05a73 | 261 | let compiler = self.compiler; |
3b2f2976 XL |
262 | let target = self.target; |
263 | let name = self.name; | |
264 | // build book first edition | |
265 | builder.ensure(Rustbook { | |
266 | target, | |
267 | name: INTERNER.intern_string(format!("{}/first-edition", name)), | |
268 | }); | |
269 | ||
270 | // build book second edition | |
271 | builder.ensure(Rustbook { | |
272 | target, | |
273 | name: INTERNER.intern_string(format!("{}/second-edition", name)), | |
274 | }); | |
275 | ||
abe05a73 XL |
276 | // build the version info page and CSS |
277 | builder.ensure(Standalone { | |
278 | compiler, | |
279 | target, | |
280 | }); | |
281 | ||
3b2f2976 XL |
282 | // build the index page |
283 | let index = format!("{}/index.md", name); | |
284 | println!("Documenting book index ({})", target); | |
abe05a73 | 285 | invoke_rustdoc(builder, compiler, target, &index); |
3b2f2976 XL |
286 | |
287 | // build the redirect pages | |
288 | println!("Documenting book redirect pages ({})", target); | |
289 | for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { | |
290 | let file = t!(file); | |
291 | let path = file.path(); | |
292 | let path = path.to_str().unwrap(); | |
293 | ||
abe05a73 | 294 | invoke_rustdoc(builder, compiler, target, path); |
3b2f2976 XL |
295 | } |
296 | } | |
297 | } | |
298 | ||
3b2f2976 XL |
299 | fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) { |
300 | let build = builder.build; | |
301 | let out = build.doc_out(target); | |
302 | ||
303 | let path = build.src.join("src/doc").join(markdown); | |
cc61c64b XL |
304 | |
305 | let favicon = build.src.join("src/doc/favicon.inc"); | |
306 | let footer = build.src.join("src/doc/footer.inc"); | |
cc61c64b XL |
307 | let version_info = out.join("version_info.html"); |
308 | ||
3b2f2976 | 309 | let mut cmd = builder.rustdoc_cmd(compiler.host); |
cc61c64b XL |
310 | |
311 | let out = out.join("book"); | |
312 | ||
cc61c64b XL |
313 | cmd.arg("--html-after-content").arg(&footer) |
314 | .arg("--html-before-content").arg(&version_info) | |
315 | .arg("--html-in-header").arg(&favicon) | |
0531ce1d | 316 | .arg("--markdown-no-toc") |
cc61c64b XL |
317 | .arg("--markdown-playground-url") |
318 | .arg("https://play.rust-lang.org/") | |
319 | .arg("-o").arg(&out) | |
320 | .arg(&path) | |
321 | .arg("--markdown-css") | |
abe05a73 | 322 | .arg("../rust.css"); |
cc61c64b XL |
323 | |
324 | build.run(&mut cmd); | |
325 | } | |
326 | ||
3b2f2976 XL |
327 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
328 | pub struct Standalone { | |
329 | compiler: Compiler, | |
330 | target: Interned<String>, | |
331 | } | |
7453a54e | 332 | |
3b2f2976 XL |
333 | impl Step for Standalone { |
334 | type Output = (); | |
335 | const DEFAULT: bool = true; | |
7453a54e | 336 | |
3b2f2976 XL |
337 | fn should_run(run: ShouldRun) -> ShouldRun { |
338 | let builder = run.builder; | |
339 | run.path("src/doc").default_condition(builder.build.config.docs) | |
340 | } | |
7453a54e | 341 | |
3b2f2976 XL |
342 | fn make_run(run: RunConfig) { |
343 | run.builder.ensure(Standalone { | |
344 | compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), | |
345 | target: run.target, | |
346 | }); | |
7453a54e SL |
347 | } |
348 | ||
3b2f2976 XL |
349 | /// Generates all standalone documentation as compiled by the rustdoc in `stage` |
350 | /// for the `target` into `out`. | |
351 | /// | |
352 | /// This will list all of `src/doc` looking for markdown files and appropriately | |
353 | /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and | |
354 | /// `STAMP` along with providing the various header/footer HTML we've customized. | |
355 | /// | |
356 | /// In the end, this is just a glorified wrapper around rustdoc! | |
357 | fn run(self, builder: &Builder) { | |
358 | let build = builder.build; | |
359 | let target = self.target; | |
360 | let compiler = self.compiler; | |
361 | println!("Documenting standalone ({})", target); | |
362 | let out = build.doc_out(target); | |
363 | t!(fs::create_dir_all(&out)); | |
364 | ||
365 | let favicon = build.src.join("src/doc/favicon.inc"); | |
366 | let footer = build.src.join("src/doc/footer.inc"); | |
367 | let full_toc = build.src.join("src/doc/full-toc.inc"); | |
368 | t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css"))); | |
369 | ||
370 | let version_input = build.src.join("src/doc/version_info.html.template"); | |
371 | let version_info = out.join("version_info.html"); | |
372 | ||
373 | if !up_to_date(&version_input, &version_info) { | |
374 | let mut info = String::new(); | |
375 | t!(t!(File::open(&version_input)).read_to_string(&mut info)); | |
376 | let info = info.replace("VERSION", &build.rust_release()) | |
377 | .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or("")) | |
378 | .replace("STAMP", build.rust_info.sha().unwrap_or("")); | |
379 | t!(t!(File::create(&version_info)).write_all(info.as_bytes())); | |
7453a54e SL |
380 | } |
381 | ||
3b2f2976 XL |
382 | for file in t!(fs::read_dir(build.src.join("src/doc"))) { |
383 | let file = t!(file); | |
384 | let path = file.path(); | |
385 | let filename = path.file_name().unwrap().to_str().unwrap(); | |
386 | if !filename.ends_with(".md") || filename == "README.md" { | |
387 | continue | |
388 | } | |
389 | ||
390 | let html = out.join(filename).with_extension("html"); | |
391 | let rustdoc = builder.rustdoc(compiler.host); | |
392 | if up_to_date(&path, &html) && | |
393 | up_to_date(&footer, &html) && | |
394 | up_to_date(&favicon, &html) && | |
395 | up_to_date(&full_toc, &html) && | |
396 | up_to_date(&version_info, &html) && | |
397 | up_to_date(&rustdoc, &html) { | |
398 | continue | |
399 | } | |
400 | ||
401 | let mut cmd = builder.rustdoc_cmd(compiler.host); | |
402 | cmd.arg("--html-after-content").arg(&footer) | |
403 | .arg("--html-before-content").arg(&version_info) | |
404 | .arg("--html-in-header").arg(&favicon) | |
405 | .arg("--markdown-playground-url") | |
406 | .arg("https://play.rust-lang.org/") | |
407 | .arg("-o").arg(&out) | |
408 | .arg(&path); | |
409 | ||
410 | if filename == "not_found.md" { | |
411 | cmd.arg("--markdown-no-toc") | |
412 | .arg("--markdown-css") | |
413 | .arg("https://doc.rust-lang.org/rust.css"); | |
414 | } else { | |
415 | cmd.arg("--markdown-css").arg("rust.css"); | |
416 | } | |
417 | build.run(&mut cmd); | |
7453a54e | 418 | } |
3b2f2976 XL |
419 | } |
420 | } | |
421 | ||
422 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
423 | pub struct Std { | |
2c00a5a8 XL |
424 | pub stage: u32, |
425 | pub target: Interned<String>, | |
3b2f2976 XL |
426 | } |
427 | ||
428 | impl Step for Std { | |
429 | type Output = (); | |
430 | const DEFAULT: bool = true; | |
431 | ||
432 | fn should_run(run: ShouldRun) -> ShouldRun { | |
433 | let builder = run.builder; | |
2c00a5a8 | 434 | run.all_krates("std").default_condition(builder.build.config.docs) |
3b2f2976 XL |
435 | } |
436 | ||
437 | fn make_run(run: RunConfig) { | |
438 | run.builder.ensure(Std { | |
439 | stage: run.builder.top_stage, | |
440 | target: run.target | |
441 | }); | |
442 | } | |
7453a54e | 443 | |
3b2f2976 XL |
444 | /// Compile all standard library documentation. |
445 | /// | |
446 | /// This will generate all documentation for the standard library and its | |
447 | /// dependencies. This is largely just a wrapper around `cargo doc`. | |
448 | fn run(self, builder: &Builder) { | |
449 | let build = builder.build; | |
450 | let stage = self.stage; | |
451 | let target = self.target; | |
452 | println!("Documenting stage{} std ({})", stage, target); | |
453 | let out = build.doc_out(target); | |
454 | t!(fs::create_dir_all(&out)); | |
455 | let compiler = builder.compiler(stage, build.build); | |
456 | let rustdoc = builder.rustdoc(compiler.host); | |
457 | let compiler = if build.force_use_stage1(compiler, target) { | |
458 | builder.compiler(1, compiler.host) | |
7453a54e | 459 | } else { |
3b2f2976 XL |
460 | compiler |
461 | }; | |
462 | ||
463 | builder.ensure(compile::Std { compiler, target }); | |
464 | let out_dir = build.stage_out(compiler, Mode::Libstd) | |
465 | .join(target).join("doc"); | |
466 | ||
467 | // Here what we're doing is creating a *symlink* (directory junction on | |
468 | // Windows) to the final output location. This is not done as an | |
469 | // optimization but rather for correctness. We've got three trees of | |
470 | // documentation, one for std, one for test, and one for rustc. It's then | |
471 | // our job to merge them all together. | |
472 | // | |
473 | // Unfortunately rustbuild doesn't know nearly as well how to merge doc | |
474 | // trees as rustdoc does itself, so instead of actually having three | |
475 | // separate trees we just have rustdoc output to the same location across | |
476 | // all of them. | |
477 | // | |
478 | // This way rustdoc generates output directly into the output, and rustdoc | |
479 | // will also directly handle merging. | |
480 | let my_out = build.crate_doc_out(target); | |
481 | build.clear_if_dirty(&my_out, &rustdoc); | |
482 | t!(symlink_dir_force(&my_out, &out_dir)); | |
483 | ||
484 | let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc"); | |
0531ce1d XL |
485 | compile::std_cargo(builder, &compiler, target, &mut cargo); |
486 | ||
487 | // Keep a whitelist so we do not build internal stdlib crates, these will be | |
488 | // build by the rustc step later if enabled. | |
489 | cargo.arg("--no-deps"); | |
490 | for krate in &["alloc", "core", "std", "std_unicode"] { | |
491 | cargo.arg("-p").arg(krate); | |
492 | // Create all crate output directories first to make sure rustdoc uses | |
493 | // relative links. | |
494 | // FIXME: Cargo should probably do this itself. | |
495 | t!(fs::create_dir_all(out_dir.join(krate))); | |
7453a54e | 496 | } |
3b2f2976 | 497 | |
3b2f2976 XL |
498 | build.run(&mut cargo); |
499 | cp_r(&my_out, &out); | |
7453a54e SL |
500 | } |
501 | } | |
54a0048b | 502 | |
3b2f2976 XL |
503 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
504 | pub struct Test { | |
505 | stage: u32, | |
506 | target: Interned<String>, | |
507 | } | |
508 | ||
509 | impl Step for Test { | |
510 | type Output = (); | |
511 | const DEFAULT: bool = true; | |
512 | ||
513 | fn should_run(run: ShouldRun) -> ShouldRun { | |
514 | let builder = run.builder; | |
0531ce1d | 515 | run.krate("test").default_condition(builder.build.config.docs) |
476ff2be SL |
516 | } |
517 | ||
3b2f2976 XL |
518 | fn make_run(run: RunConfig) { |
519 | run.builder.ensure(Test { | |
520 | stage: run.builder.top_stage, | |
521 | target: run.target, | |
522 | }); | |
523 | } | |
524 | ||
525 | /// Compile all libtest documentation. | |
526 | /// | |
527 | /// This will generate all documentation for libtest and its dependencies. This | |
528 | /// is largely just a wrapper around `cargo doc`. | |
529 | fn run(self, builder: &Builder) { | |
530 | let build = builder.build; | |
531 | let stage = self.stage; | |
532 | let target = self.target; | |
533 | println!("Documenting stage{} test ({})", stage, target); | |
534 | let out = build.doc_out(target); | |
535 | t!(fs::create_dir_all(&out)); | |
536 | let compiler = builder.compiler(stage, build.build); | |
537 | let rustdoc = builder.rustdoc(compiler.host); | |
538 | let compiler = if build.force_use_stage1(compiler, target) { | |
539 | builder.compiler(1, compiler.host) | |
540 | } else { | |
541 | compiler | |
542 | }; | |
543 | ||
544 | // Build libstd docs so that we generate relative links | |
545 | builder.ensure(Std { stage, target }); | |
32a655c1 | 546 | |
3b2f2976 XL |
547 | builder.ensure(compile::Test { compiler, target }); |
548 | let out_dir = build.stage_out(compiler, Mode::Libtest) | |
549 | .join(target).join("doc"); | |
550 | ||
551 | // See docs in std above for why we symlink | |
552 | let my_out = build.crate_doc_out(target); | |
553 | build.clear_if_dirty(&my_out, &rustdoc); | |
554 | t!(symlink_dir_force(&my_out, &out_dir)); | |
555 | ||
556 | let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc"); | |
557 | compile::test_cargo(build, &compiler, target, &mut cargo); | |
0531ce1d XL |
558 | |
559 | cargo.arg("--no-deps").arg("-p").arg("test"); | |
560 | ||
3b2f2976 XL |
561 | build.run(&mut cargo); |
562 | cp_r(&my_out, &out); | |
563 | } | |
54a0048b SL |
564 | } |
565 | ||
3b2f2976 | 566 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
0531ce1d | 567 | pub struct WhitelistedRustc { |
3b2f2976 XL |
568 | stage: u32, |
569 | target: Interned<String>, | |
54a0048b SL |
570 | } |
571 | ||
0531ce1d | 572 | impl Step for WhitelistedRustc { |
3b2f2976 XL |
573 | type Output = (); |
574 | const DEFAULT: bool = true; | |
575 | const ONLY_HOSTS: bool = true; | |
576 | ||
577 | fn should_run(run: ShouldRun) -> ShouldRun { | |
578 | let builder = run.builder; | |
579 | run.krate("rustc-main").default_condition(builder.build.config.docs) | |
580 | } | |
581 | ||
582 | fn make_run(run: RunConfig) { | |
0531ce1d | 583 | run.builder.ensure(WhitelistedRustc { |
3b2f2976 XL |
584 | stage: run.builder.top_stage, |
585 | target: run.target, | |
586 | }); | |
587 | } | |
588 | ||
0531ce1d | 589 | /// Generate whitelisted compiler crate documentation. |
3b2f2976 | 590 | /// |
0531ce1d XL |
591 | /// This will generate all documentation for crates that are whitelisted |
592 | /// to be included in the standard documentation. This documentation is | |
593 | /// included in the standard Rust documentation, so we should always | |
594 | /// document it and symlink to merge with the rest of the std and test | |
595 | /// documentation. We don't build other compiler documentation | |
596 | /// here as we want to be able to keep it separate from the standard | |
597 | /// documentation. This is largely just a wrapper around `cargo doc`. | |
3b2f2976 XL |
598 | fn run(self, builder: &Builder) { |
599 | let build = builder.build; | |
600 | let stage = self.stage; | |
601 | let target = self.target; | |
0531ce1d | 602 | println!("Documenting stage{} whitelisted compiler ({})", stage, target); |
3b2f2976 XL |
603 | let out = build.doc_out(target); |
604 | t!(fs::create_dir_all(&out)); | |
605 | let compiler = builder.compiler(stage, build.build); | |
606 | let rustdoc = builder.rustdoc(compiler.host); | |
607 | let compiler = if build.force_use_stage1(compiler, target) { | |
608 | builder.compiler(1, compiler.host) | |
609 | } else { | |
610 | compiler | |
611 | }; | |
612 | ||
613 | // Build libstd docs so that we generate relative links | |
614 | builder.ensure(Std { stage, target }); | |
615 | ||
616 | builder.ensure(compile::Rustc { compiler, target }); | |
617 | let out_dir = build.stage_out(compiler, Mode::Librustc) | |
618 | .join(target).join("doc"); | |
619 | ||
620 | // See docs in std above for why we symlink | |
621 | let my_out = build.crate_doc_out(target); | |
622 | build.clear_if_dirty(&my_out, &rustdoc); | |
623 | t!(symlink_dir_force(&my_out, &out_dir)); | |
624 | ||
625 | let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); | |
2c00a5a8 | 626 | compile::rustc_cargo(build, &mut cargo); |
3b2f2976 | 627 | |
0531ce1d XL |
628 | // We don't want to build docs for internal compiler dependencies in this |
629 | // step (there is another step for that). Therefore, we whitelist the crates | |
630 | // for which docs must be built. | |
631 | cargo.arg("--no-deps"); | |
632 | for krate in &["proc_macro"] { | |
633 | cargo.arg("-p").arg(krate); | |
8bb4bdeb | 634 | } |
3b2f2976 XL |
635 | |
636 | build.run(&mut cargo); | |
637 | cp_r(&my_out, &out); | |
8bb4bdeb | 638 | } |
3b2f2976 | 639 | } |
8bb4bdeb | 640 | |
0531ce1d XL |
641 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
642 | pub struct Rustc { | |
643 | stage: u32, | |
644 | target: Interned<String>, | |
645 | } | |
646 | ||
647 | impl Step for Rustc { | |
648 | type Output = (); | |
649 | const DEFAULT: bool = true; | |
650 | const ONLY_HOSTS: bool = true; | |
651 | ||
652 | fn should_run(run: ShouldRun) -> ShouldRun { | |
653 | let builder = run.builder; | |
654 | run.krate("rustc-main").default_condition(builder.build.config.docs) | |
655 | } | |
656 | ||
657 | fn make_run(run: RunConfig) { | |
658 | run.builder.ensure(Rustc { | |
659 | stage: run.builder.top_stage, | |
660 | target: run.target, | |
661 | }); | |
662 | } | |
663 | ||
664 | /// Generate compiler documentation. | |
665 | /// | |
666 | /// This will generate all documentation for compiler and dependencies. | |
667 | /// Compiler documentation is distributed separately, so we make sure | |
668 | /// we do not merge it with the other documentation from std, test and | |
669 | /// proc_macros. This is largely just a wrapper around `cargo doc`. | |
670 | fn run(self, builder: &Builder) { | |
671 | let build = builder.build; | |
672 | let stage = self.stage; | |
673 | let target = self.target; | |
674 | println!("Documenting stage{} compiler ({})", stage, target); | |
675 | let out = build.compiler_doc_out(target); | |
676 | t!(fs::create_dir_all(&out)); | |
677 | let compiler = builder.compiler(stage, build.build); | |
678 | let rustdoc = builder.rustdoc(compiler.host); | |
679 | let compiler = if build.force_use_stage1(compiler, target) { | |
680 | builder.compiler(1, compiler.host) | |
681 | } else { | |
682 | compiler | |
683 | }; | |
684 | ||
685 | if !build.config.compiler_docs { | |
686 | println!("\tskipping - compiler docs disabled"); | |
687 | return; | |
688 | } | |
689 | ||
690 | // Build libstd docs so that we generate relative links | |
691 | builder.ensure(Std { stage, target }); | |
692 | ||
693 | builder.ensure(compile::Rustc { compiler, target }); | |
694 | let out_dir = build.stage_out(compiler, Mode::Librustc) | |
695 | .join(target).join("doc"); | |
696 | // We do not symlink to the same shared folder that already contains std library | |
697 | // documentation from previous steps as we do not want to include that. | |
698 | build.clear_if_dirty(&out, &rustdoc); | |
699 | t!(symlink_dir_force(&out, &out_dir)); | |
700 | ||
701 | let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); | |
702 | compile::rustc_cargo(build, &mut cargo); | |
703 | ||
704 | // Only include compiler crates, no dependencies of those, such as `libc`. | |
705 | cargo.arg("--no-deps"); | |
706 | ||
707 | // Find dependencies for top level crates. | |
708 | let mut compiler_crates = HashSet::new(); | |
709 | for root_crate in &["rustc", "rustc_driver"] { | |
710 | let interned_root_crate = INTERNER.intern_str(root_crate); | |
711 | find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates); | |
712 | } | |
713 | ||
714 | for krate in &compiler_crates { | |
715 | cargo.arg("-p").arg(krate); | |
716 | } | |
717 | ||
718 | build.run(&mut cargo); | |
719 | } | |
720 | } | |
721 | ||
722 | fn find_compiler_crates( | |
723 | build: &Build, | |
724 | name: &Interned<String>, | |
725 | crates: &mut HashSet<Interned<String>> | |
726 | ) { | |
727 | // Add current crate. | |
728 | crates.insert(*name); | |
729 | ||
730 | // Look for dependencies. | |
731 | for dep in build.crates.get(name).unwrap().deps.iter() { | |
732 | if build.crates.get(dep).unwrap().is_local(build) { | |
733 | find_compiler_crates(build, dep, crates); | |
734 | } | |
735 | } | |
736 | } | |
737 | ||
3b2f2976 XL |
738 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] |
739 | pub struct ErrorIndex { | |
740 | target: Interned<String>, | |
54a0048b SL |
741 | } |
742 | ||
3b2f2976 XL |
743 | impl Step for ErrorIndex { |
744 | type Output = (); | |
745 | const DEFAULT: bool = true; | |
746 | const ONLY_HOSTS: bool = true; | |
747 | ||
748 | fn should_run(run: ShouldRun) -> ShouldRun { | |
749 | let builder = run.builder; | |
750 | run.path("src/tools/error_index_generator").default_condition(builder.build.config.docs) | |
751 | } | |
752 | ||
753 | fn make_run(run: RunConfig) { | |
754 | run.builder.ensure(ErrorIndex { | |
755 | target: run.target, | |
756 | }); | |
757 | } | |
758 | ||
759 | /// Generates the HTML rendered error-index by running the | |
760 | /// `error_index_generator` tool. | |
761 | fn run(self, builder: &Builder) { | |
762 | let build = builder.build; | |
763 | let target = self.target; | |
54a0048b | 764 | |
3b2f2976 XL |
765 | println!("Documenting error index ({})", target); |
766 | let out = build.doc_out(target); | |
767 | t!(fs::create_dir_all(&out)); | |
768 | let mut index = builder.tool_cmd(Tool::ErrorIndex); | |
769 | index.arg("html"); | |
770 | index.arg(out.join("error-index.html")); | |
771 | ||
772 | // FIXME: shouldn't have to pass this env var | |
ff7c6d11 XL |
773 | index.env("CFG_BUILD", &build.build) |
774 | .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir()); | |
3b2f2976 XL |
775 | |
776 | build.run(&mut index); | |
777 | } | |
778 | } | |
779 | ||
780 | #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] | |
781 | pub struct UnstableBookGen { | |
782 | target: Interned<String>, | |
54a0048b | 783 | } |
8bb4bdeb | 784 | |
3b2f2976 XL |
785 | impl Step for UnstableBookGen { |
786 | type Output = (); | |
787 | const DEFAULT: bool = true; | |
788 | const ONLY_HOSTS: bool = true; | |
041b39d2 | 789 | |
3b2f2976 XL |
790 | fn should_run(run: ShouldRun) -> ShouldRun { |
791 | let builder = run.builder; | |
792 | run.path("src/tools/unstable-book-gen").default_condition(builder.build.config.docs) | |
793 | } | |
794 | ||
795 | fn make_run(run: RunConfig) { | |
796 | run.builder.ensure(UnstableBookGen { | |
797 | target: run.target, | |
798 | }); | |
799 | } | |
800 | ||
801 | fn run(self, builder: &Builder) { | |
802 | let build = builder.build; | |
803 | let target = self.target; | |
804 | ||
805 | builder.ensure(compile::Std { | |
806 | compiler: builder.compiler(builder.top_stage, build.build), | |
807 | target, | |
808 | }); | |
809 | ||
810 | println!("Generating unstable book md files ({})", target); | |
811 | let out = build.md_doc_out(target).join("unstable-book"); | |
812 | t!(fs::create_dir_all(&out)); | |
813 | t!(fs::remove_dir_all(&out)); | |
814 | let mut cmd = builder.tool_cmd(Tool::UnstableBookGen); | |
815 | cmd.arg(build.src.join("src")); | |
816 | cmd.arg(out); | |
817 | ||
818 | build.run(&mut cmd); | |
819 | } | |
041b39d2 XL |
820 | } |
821 | ||
8bb4bdeb XL |
822 | fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { |
823 | if let Ok(m) = fs::symlink_metadata(dst) { | |
824 | if m.file_type().is_dir() { | |
825 | try!(fs::remove_dir_all(dst)); | |
826 | } else { | |
827 | // handle directory junctions on windows by falling back to | |
828 | // `remove_dir`. | |
829 | try!(fs::remove_file(dst).or_else(|_| { | |
830 | fs::remove_dir(dst) | |
831 | })); | |
832 | } | |
833 | } | |
834 | ||
835 | symlink_dir(src, dst) | |
836 | } |