Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion compiler/rustc_target/src/spec/targets/i586_unknown_redox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ pub(crate) fn target() -> Target {

Target {
llvm_target: "i586-unknown-redox".into(),
metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
metadata: TargetMetadata {
description: Some("32-bit x86 Redox OS (PentiumPro)".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(true),
},
pointer_width: 32,
data_layout:
"e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ pub(crate) fn target() -> Target {
Target {
llvm_target: "x86_64-unknown-linux-none".into(),
metadata: TargetMetadata {
description: None,
tier: None,
host_tools: None,
description: Some("64-bit Linux with no libc".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(false),
},
pointer_width: 64,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
arch: Arch::Xtensa,
metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
metadata: TargetMetadata {
description: Some("Xtensa ESP32".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(true),
},

options: TargetOptions {
endian: Endian::Little,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
arch: Arch::Xtensa,
metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
metadata: TargetMetadata {
description: Some("Xtensa ESP32-S2".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(true),
},

options: TargetOptions {
endian: Endian::Little,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ pub(crate) fn target() -> Target {
pointer_width: 32,
data_layout: "e-m:e-p:32:32-v1:8:8-i64:64-i128:128-n32".into(),
arch: Arch::Xtensa,
metadata: TargetMetadata { description: None, tier: None, host_tools: None, std: None },
metadata: TargetMetadata {
description: Some("Xtensa ESP32-S3".into()),
tier: Some(3),
host_tools: Some(false),
std: Some(true),
},

options: TargetOptions {
endian: Endian::Little,
Expand Down
6 changes: 6 additions & 0 deletions src/doc/rustc/book.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,9 @@ use-boolean-and = true

[output.html.playground]
runnable = false

[preprocessor.rustc-gen-target-tables]
command = "cargo run --manifest-path ../../../../src/tools/mdbook-rustc/Cargo.toml"

[build]
extra-watch-dirs = ["../../tools/mdbook-rustc"]
323 changes: 5 additions & 318 deletions src/doc/rustc/src/platform-support.md

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/tools/mdbook-rustc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "mdbook-rustc"
version = "0.0.0"
edition = "2024"
workspace = "../rustbook"

[dependencies]
mdbook-preprocessor = "0.5.1"
serde = { version = "1.0.228", features = ["serde_derive"] }
serde_json = "1"
156 changes: 156 additions & 0 deletions src/tools/mdbook-rustc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
use std::collections::HashMap;
use std::fmt::Write;
use std::path::{Path, PathBuf};
use std::{env, fs};

use mdbook_preprocessor::book::Chapter;

use crate::target::{ByTier, Target};

pub mod target;

const TIER_1_HOST_MARKER: &str = "{{TIER_1_HOST_TABLE}}";
const TIER_1_NOHOST_MARKER: &str = "{{TIER_1_NOHOST_TABLE}}";
const TIER_2_HOST_MARKER: &str = "{{TIER_2_HOST_TABLE}}";
const TIER_2_NOHOST_MARKER: &str = "{{TIER_2_NOHOST_TABLE}}";
const TIER_3_MARKER: &str = "{{TIER_3_TABLE}}";

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";
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";

pub fn process_main_chapter(
chapter: &mut Chapter,
rustc_targets: &[Target],
target_chapters: &HashMap<String, Chapter>,
) {
let targets = ByTier::from(rustc_targets);
let mut new_content = String::new();

for line in chapter.content.lines() {
match line.trim() {
TIER_1_HOST_MARKER => {
write_host_table(&mut new_content, &targets.tier1_host, &target_chapters)
}
TIER_1_NOHOST_MARKER => write_nohost_table(
&mut new_content,
&targets.tier1_nohost,
&target_chapters,
EMPTY_TIER_1_NOHOST_MSG,
),
TIER_2_HOST_MARKER => {
write_host_table(&mut new_content, &targets.tier2_host, &target_chapters)
}
TIER_2_NOHOST_MARKER => write_nohost_table(
&mut new_content,
&targets.tier2_nohost,
&target_chapters,
EMPTY_TIER_2_NOHOST_MSG,
),
TIER_3_MARKER => write_tier3_table(&mut new_content, &targets.tier3, &target_chapters),
_ => {
new_content.push_str(line);
new_content.push_str("\n");
}
}
}

debug_dump("platform-support.md", &new_content);

chapter.content = new_content;
}

fn write_host_table(
out: &mut String,
targets: &[&Target],
target_chapters: &HashMap<String, Chapter>,
) {
out.push_str("target | notes\n-------|-------\n");
for target in targets {
write_target_tuple(out, target, target_chapters);
_ = writeln!(out, " | {}", target.metadata.description.as_deref().unwrap_or(""));
}
}

fn write_nohost_table(
out: &mut String,
targets: &[&Target],
target_chapters: &HashMap<String, Chapter>,
empty_msg: &str,
) {
if targets.is_empty() {
out.push_str(empty_msg);
return;
}

out.push_str("target | std | notes\n-------|:---:|-------\n");
for target in targets {
write_target_tuple(out, target, target_chapters);
_ = writeln!(
out,
" | {} | {}",
std_support_symbol(target.metadata.std),
target.metadata.description.as_deref().unwrap_or("")
);
}
}

fn write_tier3_table(
out: &mut String,
targets: &[&Target],
target_chapters: &HashMap<String, Chapter>,
) {
out.push_str("target | std | host | notes\n-------|:---:|:----:|-------\n");
for target in targets {
write_target_tuple(out, target, target_chapters);
_ = writeln!(
out,
" | {} | {} | {}",
std_support_symbol(target.metadata.std),
host_support_symbol(target.metadata.host_tools),
target.metadata.description.as_deref().unwrap_or("")
);
}
}

fn write_target_tuple(
out: &mut String,
target: &Target,
target_chapters: &HashMap<String, Chapter>,
) {
let doc_chapter = target.metadata.doc_chapter.as_deref().unwrap_or(&*target.tuple);

if target_chapters.contains_key(doc_chapter) {
_ = write!(out, "[`{}`](platform-support/{}.md)", target.tuple, doc_chapter);
} else {
_ = write!(out, "`{}`", target.tuple);
}
}

pub fn std_support_symbol(support: Option<bool>) -> &'static str {
match support {
Some(true) => "✓",
Some(false) => "*",
None => "?",
}
}

pub fn host_support_symbol(support: Option<bool>) -> &'static str {
match support {
Some(true) => "✓",
Some(false) => "",
None => "?",
}
}

pub fn debug_dump<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
if let Some(dir) = env::var_os("MDBOOK_RUSTC_DEBUG_DUMP_DIR")
&& !dir.is_empty()
{
let mut dump_path = PathBuf::from(dir);
dump_path.push(path.as_ref());
fs::create_dir_all(dump_path.parent().unwrap()).unwrap();
fs::write(dump_path, contents).unwrap();
}
}
70 changes: 70 additions & 0 deletions src/tools/mdbook-rustc/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, io};

use mdbook_preprocessor::errors::Error;
use mdbook_rustc::process_main_chapter;
use mdbook_rustc::target::{Target, all_from_rustc_json};

fn main() -> Result<(), Error> {
let mut args = std::env::args().skip(1);
match args.next().as_deref() {
Some("supports") => {
// Supports all renderers.
return Ok(());
}
Some(arg) => {
return Err(Error::msg(format!("unknown argument: {arg}")));
}
None => {}
}

let (_ctx, mut book) = mdbook_preprocessor::parse_input(io::stdin().lock())?;
let rustc_targets = load_rustc_targets()?;
let target_chapters = book
.chapters()
.filter_map(|chapter| {
Some((
chapter
.source_path
.as_ref()
.map(|p| p.strip_prefix("platform-support/").ok()?.file_stem()?.to_str())
.flatten()?
.to_owned(),
chapter.clone(),
))
})
.collect::<HashMap<_, _>>();

book.for_each_chapter_mut(|chapter| {
if chapter.path.as_deref() == Some("platform-support.md".as_ref()) {
process_main_chapter(chapter, &rustc_targets, &target_chapters);
}
});

serde_json::to_writer(io::stdout().lock(), &book)?;
Ok(())
}

fn load_rustc_targets() -> Result<Vec<Target>, Error> {
let rustc = PathBuf::from(
env::var("RUSTC").map_err(|_| Error::msg("must pass RUSTC env var pointing to rustc"))?,
);
all_from_rustc_json(serde_json::from_str(&rustc_stdout(
&rustc,
&["-Z", "unstable-options", "--print", "all-target-specs-json"],
))?)
}

fn rustc_stdout(rustc: &Path, args: &[&str]) -> String {
let output = Command::new(rustc).args(args).env("RUSTC_BOOTSTRAP", "1").output().unwrap();
if !output.status.success() {
panic!(
"rustc failed: {}, {}",
output.status,
String::from_utf8(output.stderr).unwrap_or_default()
)
}
String::from_utf8(output.stdout).unwrap()
}
Loading
Loading