Skip to content

Commit d6dca05

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 7d5649b commit d6dca05

File tree

4 files changed

+105
-0
lines changed

4 files changed

+105
-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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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 }
26+
env_logger = { version = "0.11.8" }
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
Copyright 2025 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+
env_logger::init();
36+
let path: Option<syn::LitStr> = syn::parse_macro_input!(input as Option<syn::LitStr>);
37+
let path = path
38+
.map(|x| x.value().into())
39+
.unwrap_or_else(|| std::env::var_os("WIT_WORLD").unwrap());
40+
util::read_wit_type_from_file(path, |kebab_name, ct| {
41+
let decls = emit::run_state(false, false, |s| {
42+
rtypes::emit_toplevel(s, &kebab_name, ct);
43+
host::emit_toplevel(s, &kebab_name, ct);
44+
});
45+
util::emit_decls(decls).into()
46+
})
47+
}
48+
49+
/// Create the hyperlight_guest_init() function (which should be
50+
/// called in hyperlight_main()) for the wasm component type in the
51+
/// file passed in (or `$WIT_WORLD`, if nothing is passed in). This
52+
/// function registers Hyperlight functions for component exports
53+
/// (which are implemented by calling into the trait provided) and
54+
/// implements the relevant traits for a trivial Host type (by calling
55+
/// into the Hyperlight host).
56+
#[proc_macro]
57+
pub fn guest_bindgen(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
58+
env_logger::init();
59+
let path: Option<syn::LitStr> = syn::parse_macro_input!(input as Option<syn::LitStr>);
60+
let path = path
61+
.map(|x| x.value().into())
62+
.unwrap_or_else(|| std::env::var_os("WIT_WORLD").unwrap());
63+
util::read_wit_type_from_file(path, |kebab_name, ct| {
64+
let decls = emit::run_state(true, false, |s| {
65+
// Emit type/trait definitions for all instances in the world
66+
rtypes::emit_toplevel(s, &kebab_name, ct);
67+
// Emit the host/guest function registrations
68+
guest::emit_toplevel(s, &kebab_name, ct);
69+
});
70+
// Use util::emit_decls() to choose between emitting the token
71+
// stream directly and emitting an include!() pointing at a
72+
// temporary file, depending on whether the user has requested
73+
// a debug temporary file be created.
74+
util::emit_decls(decls).into()
75+
})
76+
}

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)