Skip to content

Commit 7908030

Browse files
committed
Create mdbook-rustc preprocessor
1 parent 8aa6fec commit 7908030

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

src/doc/rustc/book.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ use-boolean-and = true
1010

1111
[output.html.playground]
1212
runnable = false
13+
14+
[preprocessor.rustc-gen-target-tables]
15+
command = "cargo run --release --manifest-path ../../tools/mdbook-rustc/Cargo.toml"
16+
17+
[build]
18+
extra-watch-dirs = ["../../tools/mdbook-rustc"]

src/tools/mdbook-rustc/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "mdbook-rustc"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
mdbook-preprocessor = "0.5.1"
8+
rustc_target = {path = "../../../compiler/rustc_target"}

src/tools/mdbook-rustc/src/main.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
use std::io;
2+
3+
use mdbook_preprocessor::{errors::Error, parse_input};
4+
use rustc_target::spec::{TARGETS, Target, TargetMetadata, TargetTuple};
5+
6+
7+
const TIER_1_HOST_MARKER: &str = "{{TIER_1_HOST_TABLE}}";
8+
const TIER_1_NOHOST_MARKER: &str = "{{TIER_1_NOHOST_TABLE}}";
9+
const TIER_2_HOST_MARKER: &str = "{{TIER_2_HOST_TABLE}}";
10+
const TIER_2_NOHOST_MARKER: &str = "{{TIER_2_NOHOST_TABLE}}";
11+
const TIER_3_MARKER: &str = "{{TIER_3_TABLE}}";
12+
13+
const EMPTY_TIER_1_NOHOST_MSG: &str = "At this time, all Tier 1 targets are [Tier 1 with Host Tools](#tier-1-with-host-tools).\n";
14+
const EMPTY_TIER_2_NOHOST_MSG: &str = "At this time, all Tier 2 targets are [Tier 2 with Host Tools](#tier-2-with-host-tools).\n";
15+
16+
struct AllTargetsInfo {
17+
tier1_host: Vec<TargetInfo>,
18+
tier1_nohost: Vec<TargetInfo>,
19+
tier2_host: Vec<TargetInfo>,
20+
tier2_nohost: Vec<TargetInfo>,
21+
tier3: Vec<TargetInfo>,
22+
}
23+
24+
struct TargetInfo {
25+
tuple: &'static str,
26+
meta: TargetMetadata,
27+
}
28+
29+
fn main() -> Result<(), Error> {
30+
let mut args = std::env::args().skip(1);
31+
match args.next().as_deref() {
32+
Some("supports") => {
33+
// Supports all renderers.
34+
return;
35+
}
36+
Some(arg) => {
37+
return Err(Error::msg("unknown argument: {arg}"));
38+
}
39+
None => {}
40+
}
41+
42+
let (ctx, book) = mdbook_preprocessor::parse_input(io::stdin().lock())?;
43+
let targets = AllTargetsInfo::load();
44+
45+
book.for_each_chapter_mut(|chapter| {
46+
if chapter.source_path.as_deref() != Some("platform-support.md") {
47+
return;
48+
}
49+
50+
let mut new_content = String::new();
51+
52+
for line in chapter.content.lines() {
53+
match line.trim() {
54+
TIER_1_HOST_MARKER => write_host_table(&mut new_content, &targets.tier1_host),
55+
TIER_1_NOHOST_MARKER => write_nohost_table(&mut new_content, &targets.tier1_nohost, EMPTY_TIER_1_NOHOST_MSG),
56+
TIER_2_HOST_MARKER => write_host_table(&mut new_content, &targets.tier2_host),
57+
TIER_2_NOHOST_MARKER => write_nohost_table(&mut new_content, &targets.tier2_nohost, EMPTY_TIER_2_NOHOST_MSG),
58+
TIER_3_MARKER => write_tier3_table(&mut new_content, &targets.tier3),
59+
_ => {
60+
new_content.push(line);
61+
new_content.push("\n");
62+
},
63+
}
64+
}
65+
66+
chapter.content = new_content;
67+
})
68+
69+
serde_json::to_writer(io::stdout().lock(), &book)?;
70+
Ok(())
71+
}
72+
73+
fn write_host_table(out: &mut String, targets: &[TargetInfo]) {
74+
out.push("target | notes\n-------|-------\n");
75+
for target in targets {
76+
_ = writeln!(out, "`{}` | {}",
77+
target.tuple,
78+
target.meta.description.unwrap_or("")
79+
);
80+
}
81+
}
82+
83+
fn write_nohost_table(out: &mut String, targets: &[TargetInfo], empty_msg: &str) {
84+
if targets.is_empty() {
85+
out.push(empty_msg);
86+
return;
87+
}
88+
89+
out.push("target | std | notes\n-------|:---:|-------\n");
90+
for target in targets {
91+
_ = writeln!(out, "`{}` | {} | {}",
92+
target.tuple,
93+
support_symbol(target.meta.std),
94+
target.meta.description.unwrap_or("")
95+
);
96+
}
97+
}
98+
99+
fn write_tier3_table(out: &mut String, targets: &[TargetInfo]) {
100+
out.push("target | std | host | notes\n-------|:---:|:----:|-------\n");
101+
for (target, meta) in targets {
102+
_ = writeln!(out, "`{}` | {} | {} | {}",
103+
target.tuple,
104+
support_symbol(target.meta.std),
105+
support_symbol(target.meta.host_tools),
106+
target.meta.description.unwrap_or("")
107+
);
108+
}
109+
}
110+
111+
fn support_symbol(support: Option<bool>) -> &'static str {
112+
match support {
113+
Some(true) => "✓",
114+
Some(false) => "*",
115+
None => "?",
116+
}
117+
}
118+
119+
impl AllTargetsInfo {
120+
fn load() -> Self {
121+
let mut tier1_host = Vec::new();
122+
let mut tier1_nohost = Vec::new();
123+
let mut tier2_host = Vec::new();
124+
let mut tier2_nohost = Vec::new();
125+
let mut tier3 = Vec::new();
126+
127+
for tuple in TARGETS {
128+
let target = TargetInfo {
129+
tuple,
130+
meta: Target::expect_builtin(TargetTuple::from_tuple(target)).metadata,
131+
}
132+
let host_tools = target.meta.host_tools.unwrap_or(false);
133+
134+
match target.meta.tier {
135+
Some(1) if host_tools => tier1_host.push(target),
136+
Some(1) => tier1_nohost.push(target),
137+
Some(2) if host_tools => tier2_host.push(target),
138+
Some(2) => tier2_nohost.push(target),
139+
Some(3) => tier3.push(target),
140+
tier => panic!("unknown target tier: {tier}"),
141+
}
142+
}
143+
144+
tier1_host.sort_by_key(|t| t.tuple);
145+
tier1_nohost.sort_by_key(|t| t.tuple);
146+
tier2_host.sort_by_key(|t| t.tuple);
147+
tier2_nohost.sort_by_key(|t| t.tuple);
148+
tier3.sort_by_key(|t| t.tuple);
149+
150+
Self {
151+
tier1_host,
152+
tier1_nohost,
153+
tier2_host,
154+
tier2_nohost,
155+
tier3,
156+
}
157+
}
158+
}

0 commit comments

Comments
 (0)