Skip to content

Commit 156c751

Browse files
committed
[component_macro] Add host_bindgen!() and guest_bindgen!()
This adds a proc-macro crate that exposes the bindings code generation from hyperlight_component_util as macros suitable for using WIT to define a hyperlight host<->guest interface. Signed-off-by: Lucy Menon <[email protected]>
1 parent c716af8 commit 156c751

File tree

4 files changed

+102
-0
lines changed

4 files changed

+102
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ members = [
1414
"fuzz",
1515
"src/hyperlight_guest_bin",
1616
"src/hyperlight_component_util",
17+
"src/hyperlight_component_macro",
1718
]
1819
# Guests have custom linker flags, so we need to exclude them from the workspace
1920
exclude = [
@@ -38,6 +39,7 @@ hyperlight-guest = { path = "src/hyperlight_guest", version = "0.5.1", default-f
3839
hyperlight-guest-bin = { path = "src/hyperlight_guest_bin", version = "0.5.1", default-features = false }
3940
hyperlight-testing = { path = "src/hyperlight_testing", default-features = false }
4041
hyperlight-component-util = { path = "src/hyperlight_component_util" }
42+
hyperlight-component-macro = { path = "src/hyperlight_component_macro" }
4143

4244
[workspace.lints.rust]
4345
unsafe_op_in_unsafe_fn = "deny"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[package]
2+
name = "hyperlight-component-macro"
3+
version.workspace = true
4+
edition.workspace = true
5+
rust-version.workspace = true
6+
license.workspace = true
7+
homepage.workspace = true
8+
repository.workspace = true
9+
readme.workspace = true
10+
description = """
11+
Procedural macros to generate Hyperlight host and guest bindings from component types
12+
"""
13+
14+
[lib]
15+
name = "hyperlight_component_macro"
16+
proc-macro = true
17+
18+
[dependencies]
19+
wasmparser = { version = "0.224.0" }
20+
quote = { version = "1.0.38" }
21+
proc-macro2 = { version = "1.0.93" }
22+
syn = { version = "2.0.96" }
23+
itertools = { version = "0.14.0" }
24+
prettyplease = { version = "0.2.31" }
25+
hyperlight-component-util = { workspace = true }
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
Copyright 2024 The Hyperlight Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
extern crate proc_macro;
18+
19+
use hyperlight_component_util::*;
20+
21+
/// Create host bindings for the wasm component type in the file
22+
/// passed in (or `$WIT_WORLD`, if nothing is passed in). This will
23+
/// produce all relevant types and trait implementations for the
24+
/// component type, as well as functions allowing the component to be
25+
/// instantiated inside a sandbox.
26+
///
27+
/// This includes both a primitive `register_host_functions`, which can
28+
/// be used to directly register the host functions on any sandbox
29+
/// (and which can easily be used with Hyperlight-Wasm), as well as an
30+
/// `instantiate()` method on the component trait that makes
31+
/// instantiating the sandbox particularly ergonomic in core
32+
/// Hyperlight.
33+
#[proc_macro]
34+
pub fn host_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
35+
let path: Option<syn::LitStr> = syn::parse_macro_input!(input as Option<syn::LitStr>);
36+
let path = path
37+
.map(|x| x.value().into())
38+
.unwrap_or_else(|| std::env::var_os("WIT_WORLD").unwrap());
39+
util::read_wit_type_from_file(path, |kebab_name, ct| {
40+
let decls = emit::run_state(false, false, |s| {
41+
rtypes::emit_toplevel(s, &kebab_name, ct);
42+
host::emit_toplevel(s, &kebab_name, ct);
43+
});
44+
util::emit_decls(decls).into()
45+
})
46+
}
47+
48+
/// Create the hyperlight_guest_init() function (which should be
49+
/// called in hyperlight_main()) for the wasm component type in the
50+
/// file passed in (or `$WIT_WORLD`, if nothing is passed in). This
51+
/// function registers Hyperlight functions for component exports
52+
/// (which are implemented by calling into the trait provided) and
53+
/// implements the relevant traits for a trivial Host type (by calling
54+
/// into the Hyperlight host).
55+
#[proc_macro]
56+
pub fn guest_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
57+
let path: Option<syn::LitStr> = syn::parse_macro_input!(input as Option<syn::LitStr>);
58+
let path = path
59+
.map(|x| x.value().into())
60+
.unwrap_or_else(|| std::env::var_os("WIT_WORLD").unwrap());
61+
util::read_wit_type_from_file(path, |kebab_name, ct| {
62+
let decls = emit::run_state(true, false, |s| {
63+
// Emit type/trait definitions for all instances in the world
64+
rtypes::emit_toplevel(s, &kebab_name, ct);
65+
// Emit the host/guest function registrations
66+
guest::emit_toplevel(s, &kebab_name, ct);
67+
});
68+
// Use util::emit_decls() to choose between emitting the token
69+
// stream directly and emitting an include!() pointing at a
70+
// temporary file, depending on whether the user has requested
71+
// a debug temporary file be created.
72+
util::emit_decls(decls).into()
73+
})
74+
}

src/hyperlight_host/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ metrics-util = "0.19.1"
102102
metrics-exporter-prometheus = "0.17.0"
103103
tracing-tracy = "0.11.4"
104104
serde_json = "1.0"
105+
hyperlight-component-macro = { workspace = true }
105106

106107
[target.'cfg(windows)'.dev-dependencies]
107108
windows = { version = "0.61", features = [

0 commit comments

Comments
 (0)