Skip to content

Commit ec86d4d

Browse files
author
Pat Hickey
authored
Improvements to wasi-headers tool (#160)
* wasi-headers: update WASI submodule, handle changes to witx ast * wasi-headers: restructure lib and exe to be more flexible just factor out some of the hard-coded stuff
1 parent 1fad338 commit ec86d4d

6 files changed

Lines changed: 148 additions & 25 deletions

File tree

tools/wasi-headers/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "wasi-headers"
3-
version = "0.0.0"
4-
authors = ["Dan Gohman <sunfish@mozilla.com>"]
3+
version = "0.0.1"
4+
authors = ["Dan Gohman <sunfish@mozilla.com>", "Pat Hickey <phickey@fastly.com>"]
55
license = "Apache-2.0"
66
edition = "2018"
77
publish = false
@@ -10,6 +10,7 @@ publish = false
1010
heck = "0.3.1"
1111
witx = { path = "WASI/tools/witx" }
1212
anyhow = "1.0.22"
13+
clap = "2.23"
1314

1415
[dev-dependencies]
1516
diff = "0.1.11"

tools/wasi-headers/src/c_header.rs

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,19 +78,20 @@ fn print_datatype(ret: &mut String, nt: &NamedType) {
7878
ret.push_str(" */\n");
7979
}
8080

81-
match &nt.dt {
81+
match &nt.tref {
8282
TypeRef::Value(v) => match &**v {
8383
Type::Enum(e) => print_enum(ret, &nt.name, e),
84+
Type::Int(i) => print_int(ret, &nt.name, i),
8485
Type::Flags(f) => print_flags(ret, &nt.name, f),
8586
Type::Struct(s) => print_struct(ret, &nt.name, s),
8687
Type::Union(u) => print_union(ret, &nt.name, u),
8788
Type::Handle(h) => print_handle(ret, &nt.name, h),
8889
Type::Builtin { .. }
8990
| Type::Array { .. }
9091
| Type::Pointer { .. }
91-
| Type::ConstPointer { .. } => print_alias(ret, &nt.name, &nt.dt),
92+
| Type::ConstPointer { .. } => print_alias(ret, &nt.name, &nt.tref),
9293
},
93-
TypeRef::Name(_) => print_alias(ret, &nt.name, &nt.dt),
94+
TypeRef::Name(_) => print_alias(ret, &nt.name, &nt.tref),
9495
}
9596
}
9697

@@ -147,6 +148,46 @@ fn print_enum(ret: &mut String, name: &Id, e: &EnumDatatype) {
147148
}
148149
}
149150

151+
fn print_int(ret: &mut String, name: &Id, i: &IntDatatype) {
152+
ret.push_str(&format!(
153+
"typedef {} __wasi_{}_t;\n",
154+
intrepr_name(i.repr),
155+
ident_name(name)
156+
));
157+
ret.push_str("\n");
158+
159+
for (index, const_) in i.consts.iter().enumerate() {
160+
if !const_.docs.is_empty() {
161+
ret.push_str("/**\n");
162+
for line in const_.docs.lines() {
163+
ret.push_str(&format!(" * {}\n", line));
164+
}
165+
ret.push_str(" */\n");
166+
}
167+
ret.push_str(&format!(
168+
"#define __WASI_{}_{} ({}({}))\n",
169+
ident_name(&name).to_shouty_snake_case(),
170+
ident_name(&const_.name).to_shouty_snake_case(),
171+
intrepr_const(i.repr),
172+
index
173+
));
174+
ret.push_str("\n");
175+
}
176+
177+
ret.push_str(&format!(
178+
"_Static_assert(sizeof(__wasi_{}_t) == {}, \"witx calculated size\");\n",
179+
ident_name(name),
180+
i.repr.mem_size()
181+
));
182+
ret.push_str(&format!(
183+
"_Static_assert(_Alignof(__wasi_{}_t) == {}, \"witx calculated align\");\n",
184+
ident_name(name),
185+
i.repr.mem_align()
186+
));
187+
188+
ret.push_str("\n");
189+
}
190+
150191
fn print_flags(ret: &mut String, name: &Id, f: &FlagsDatatype) {
151192
ret.push_str(&format!(
152193
"typedef {} __wasi_{}_t;\n",
@@ -377,7 +418,10 @@ fn ident_name(i: &Id) -> String {
377418

378419
fn builtin_type_name(b: BuiltinType) -> &'static str {
379420
match b {
380-
BuiltinType::String => "string",
421+
BuiltinType::String | BuiltinType::Char8 => {
422+
panic!("no type name for string or char8 builtins")
423+
}
424+
BuiltinType::USize => "size_t",
381425
BuiltinType::U8 => "uint8_t",
382426
BuiltinType::U16 => "uint16_t",
383427
BuiltinType::U32 => "uint32_t",
@@ -392,13 +436,26 @@ fn builtin_type_name(b: BuiltinType) -> &'static str {
392436
}
393437

394438
fn typeref_name(tref: &TypeRef) -> String {
439+
match &*tref.type_() {
440+
Type::Builtin(BuiltinType::String) | Type::Builtin(BuiltinType::Char8) | Type::Array(_) => {
441+
panic!("unsupported grammar: cannot construct name of string or array",)
442+
}
443+
_ => {}
444+
}
445+
395446
match tref {
396-
TypeRef::Name(named_type) => format!("__wasi_{}_t", named_type.name.as_str()),
447+
TypeRef::Name(named_type) => match &*named_type.type_() {
448+
Type::Pointer(p) => format!("{} *", typeref_name(&*p)),
449+
Type::ConstPointer(p) => format!("const {} *", typeref_name(&*p)),
450+
Type::Array(_) => unreachable!("arrays excluded above"),
451+
_ => format!("__wasi_{}_t", named_type.name.as_str()),
452+
},
397453
TypeRef::Value(anon_type) => match &**anon_type {
454+
Type::Array(_) => unreachable!("arrays excluded above"),
398455
Type::Builtin(b) => builtin_type_name(*b).to_string(),
399-
Type::Array(_) => unreachable!("arrays should be special-cased"),
400456
Type::Pointer(p) => format!("{} *", typeref_name(&*p)),
401457
Type::ConstPointer(p) => format!("const {} *", typeref_name(&*p)),
458+
Type::Int(i) => format!("{}", intrepr_name(i.repr)),
402459
Type::Struct { .. }
403460
| Type::Union { .. }
404461
| Type::Enum { .. }

tools/wasi-headers/src/lib.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,12 @@ mod c_header;
22

33
use anyhow::{anyhow, Result};
44
use c_header::to_c_header;
5-
use std::fs::read_dir;
5+
use std::fs;
66
use std::io;
7+
use std::path::PathBuf;
78
use witx::load;
89

9-
pub fn generate() -> Result<String> {
10-
let mut inputs = read_dir("WASI/phases/snapshot/witx")?
11-
.map(|res| res.map(|e| e.path()))
12-
.collect::<Result<Vec<_>, io::Error>>()?;
13-
14-
inputs.sort();
15-
10+
pub fn generate(inputs: &[PathBuf]) -> Result<String> {
1611
// TODO: drop the anyhow! part once witx switches to anyhow.
1712
let doc = load(&inputs).map_err(|e| anyhow!(e.to_string()))?;
1813

@@ -24,3 +19,18 @@ pub fn generate() -> Result<String> {
2419

2520
Ok(to_c_header(&doc, &inputs_str))
2621
}
22+
23+
pub fn snapshot_witx_files() -> Result<Vec<PathBuf>> {
24+
let snapshot_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("WASI/phases/snapshot/witx");
25+
let mut inputs = fs::read_dir(snapshot_dir)?
26+
.map(|res| res.map(|e| e.path()))
27+
.collect::<Result<Vec<_>, io::Error>>()?;
28+
29+
inputs.sort();
30+
Ok(inputs)
31+
}
32+
33+
pub fn libc_wasi_api_header() -> PathBuf {
34+
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
35+
.join("../../libc-bottom-half/headers/public/wasi/api.h")
36+
}

tools/wasi-headers/src/main.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,60 @@
1+
#[macro_use]
2+
extern crate clap;
3+
14
use anyhow::Result;
5+
use clap::{Arg, SubCommand};
26
use std::fs::File;
37
use std::io::Write;
4-
use wasi_headers::generate;
8+
use std::path::PathBuf;
9+
use wasi_headers::{generate, libc_wasi_api_header, snapshot_witx_files};
10+
11+
struct GenerateCommand {
12+
/// Input witx file
13+
inputs: Vec<PathBuf>,
14+
/// Output header file
15+
output: PathBuf,
16+
}
17+
18+
impl GenerateCommand {
19+
pub fn execute(&self) -> Result<()> {
20+
let c_header = generate(&self.inputs)?;
21+
let mut file = File::create(&self.output)?;
22+
file.write_all(c_header.as_bytes())?;
23+
Ok(())
24+
}
25+
}
26+
27+
fn main() -> Result<()> {
28+
let matches = app_from_crate!()
29+
.arg(Arg::with_name("inputs").required(true).multiple(true))
30+
.arg(
31+
Arg::with_name("output")
32+
.short("o")
33+
.long("output")
34+
.takes_value(true)
35+
.required(true),
36+
)
37+
.subcommand(
38+
SubCommand::with_name("generate-libc")
39+
.about("generate libc api.h from current snapshot"),
40+
)
41+
.get_matches();
42+
43+
let cmd = if matches.subcommand_matches("generate-libc").is_some() {
44+
let inputs = snapshot_witx_files()?;
45+
let output = libc_wasi_api_header();
46+
GenerateCommand { inputs, output }
47+
} else {
48+
GenerateCommand {
49+
inputs: matches
50+
.values_of("inputs")
51+
.expect("inputs required")
52+
.map(PathBuf::from)
53+
.collect(),
54+
output: PathBuf::from(matches.value_of("output").expect("output required")),
55+
}
56+
};
557

6-
pub fn main() -> Result<()> {
7-
let c_header = generate()?;
8-
let mut file = File::create("../../libc-bottom-half/headers/public/wasi/api.h")?;
9-
file.write_all(c_header.as_bytes())?;
58+
cmd.execute()?;
1059
Ok(())
1160
}

tools/wasi-headers/tests/verify.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
use std::fs;
2+
13
#[test]
24
fn assert_same_as_src() {
3-
let actual = include_str!("../../../libc-bottom-half/headers/public/wasi/api.h");
4-
let expected = wasi_headers::generate().expect("header generation should succeed");
5+
let actual =
6+
fs::read_to_string(wasi_headers::libc_wasi_api_header()).expect("read libc wasi/api.h");
7+
let witx_files = wasi_headers::snapshot_witx_files().expect("parse snapshot witx files");
8+
let expected = wasi_headers::generate(&witx_files).expect("header generation");
59
if actual == expected {
610
return;
711
}
@@ -63,7 +67,9 @@ fn assert_same_as_src() {
6367
}
6468

6569
eprintln!();
66-
eprintln!("To regenerate the files, run `cd tools/wasi-headers && cargo run`.");
70+
eprintln!(
71+
"To regenerate the files, run `cd tools/wasi-headers && cargo run -- generate-libc`."
72+
);
6773
eprintln!();
6874
panic!();
6975
}

0 commit comments

Comments
 (0)