@@ -82,7 +82,98 @@ def _generate_wrapper_impl(ctx):
8282 )
8383 )
8484
85- wrapper_content = """// Generated wrapper for WIT bindings
85+ # Different wrapper content based on mode
86+ if ctx .attr .mode == "native-guest" :
87+ wrapper_content = """// Generated wrapper for WIT bindings (native-guest mode)
88+ //
89+ // COMPATIBILITY: wit-bindgen CLI 0.44.0 - 0.46.0
90+ // This wrapper provides a wit_bindgen::rt module compatible with the CLI-generated code.
91+ // The runtime provides allocation helpers and cleanup guards expected by generated bindings.
92+ //
93+ // For native-guest mode, we also provide a no-op export! macro since native applications
94+ // don't need to export WASM functions.
95+ //
96+ // API provided:
97+ // - Cleanup::new(layout) -> (*mut u8, Option<CleanupGuard>)
98+ // - CleanupGuard (with Drop impl for deallocation)
99+ // - run_ctors_once() - no-op for native applications
100+ // - maybe_link_cabi_realloc() - no-op for native applications
101+ // - export! - no-op macro for native applications (does nothing)
102+
103+ // Suppress clippy warnings for generated code
104+ #![allow(clippy::all)]
105+ #![allow(unused_imports)]
106+ #![allow(dead_code)]
107+
108+ // Minimal wit_bindgen::rt runtime compatible with CLI-generated code
109+ pub mod wit_bindgen {
110+ pub mod rt {
111+ use core::alloc::Layout;
112+
113+ #[inline]
114+ pub fn run_ctors_once() {
115+ // No-op - native applications don't need constructor calls
116+ }
117+
118+ #[inline]
119+ pub fn maybe_link_cabi_realloc() {
120+ // No-op - native applications don't need cabi_realloc
121+ }
122+
123+ pub struct Cleanup;
124+
125+ impl Cleanup {
126+ #[inline]
127+ #[allow(clippy::new_ret_no_self)]
128+ pub fn new(layout: Layout) -> (*mut u8, Option<CleanupGuard>) {
129+ // Use the global allocator to allocate memory
130+ // SAFETY: We're allocating with a valid layout
131+ let ptr = unsafe { std::alloc::alloc(layout) };
132+
133+ // Return the pointer and a cleanup guard
134+ // If allocation fails, alloc() will panic (as per std::alloc behavior)
135+ (ptr, Some(CleanupGuard { ptr, layout }))
136+ }
137+ }
138+
139+ pub struct CleanupGuard {
140+ ptr: *mut u8,
141+ layout: Layout,
142+ }
143+
144+ impl CleanupGuard {
145+ #[inline]
146+ pub fn forget(self) {
147+ // Prevent the Drop from running
148+ core::mem::forget(self);
149+ }
150+ }
151+
152+ impl Drop for CleanupGuard {
153+ fn drop(&mut self) {
154+ // SAFETY: ptr was allocated with layout in Cleanup::new
155+ unsafe {
156+ std::alloc::dealloc(self.ptr, self.layout);
157+ }
158+ }
159+ }
160+ }
161+ }
162+
163+ // No-op export macro for native-guest mode
164+ // Native applications don't export WASM functions, so this does nothing
165+ #[allow(unused_macros)]
166+ #[macro_export]
167+ macro_rules! export {
168+ ($($t:tt)*) => {
169+ // No-op: native applications don't export WASM functions
170+ };
171+ }
172+
173+ // Generated bindings follow:
174+ """
175+ else :
176+ wrapper_content = """// Generated wrapper for WIT bindings (guest mode)
86177//
87178// COMPATIBILITY: wit-bindgen CLI 0.44.0 - 0.46.0
88179// This wrapper provides a wit_bindgen::rt module compatible with the CLI-generated code.
@@ -167,9 +258,10 @@ pub mod wit_bindgen {
167258 content = wrapper_content + "\n " ,
168259 )
169260
170- # Create filtered content based on mode
261+ # For native-guest mode, filter out the conflicting pub(crate) use export line
262+ # For guest mode, just concatenate directly
171263 if ctx .attr .mode == "native-guest" :
172- # Read bindgen file and filter out conflicting exports
264+ # Use Python to filter out conflicting export line
173265 filter_script = ctx .actions .declare_file (ctx .label .name + "_filter.py" )
174266 filter_content = """#!/usr/bin/env python3
175267import sys
@@ -182,11 +274,12 @@ with open(sys.argv[1], 'r') as f:
182274with open(sys.argv[2], 'r') as f:
183275 bindgen_content = f.read()
184276
185- # Filter out conflicting export statements for native-guest mode
277+ # Filter out conflicting pub(crate) use export line
278+ # The wrapper provides a public export! macro, so we don't need the crate-private one
186279filtered_lines = []
187280for line in bindgen_content.split('\\ n'):
188- # Skip lines that start with pub(crate) use __export_ and end with _impl as export;
189- if not (line.strip().startswith('pub(crate) use __export_ ') and line.strip().endswith('_impl as export;')):
281+ # Skip lines that re-export as 'export' (conflicts with our macro)
282+ if not (line.strip().startswith('pub(crate) use') and line.strip().endswith(' as export;')):
190283 filtered_lines.append(line)
191284
192285# Write combined content
@@ -206,10 +299,10 @@ with open(sys.argv[3], 'w') as f:
206299 inputs = [temp_wrapper , ctx .file .bindgen , filter_script ],
207300 outputs = [out_file ],
208301 mnemonic = "FilterWitWrapper" ,
209- progress_message = "Filtering wrapper for {}" .format (ctx .label ),
302+ progress_message = "Filtering native-guest wrapper for {}" .format (ctx .label ),
210303 )
211304 else :
212- # For guest mode, use file_ops component for cross-platform concatenation
305+ # Use file_ops component for cross-platform concatenation
213306 # Build JSON config for file_ops concatenate-files operation
214307 config_file = ctx .actions .declare_file (ctx .label .name + "_concat_config.json" )
215308 ctx .actions .write (
@@ -397,22 +490,16 @@ def rust_wasm_component_bindgen(
397490 bindings_lib = name + "_bindings"
398491 bindings_lib_host = bindings_lib + "_host"
399492
400- # TODO: Re-enable host bindings once we fix the export macro issue
401- # The native-guest bindings correctly remove the export! macro (by design),
402- # but user code unconditionally uses export!(). We need to either:
403- # 1. Add cfg guards in user code: #[cfg(target_arch = "wasm32")]
404- # 2. Keep the export macro in native-guest mode (but make it a no-op)
405- # 3. Use conditional compilation in the wrapper
406- # For now, disabled to unblock CI (WASM builds work fine)
407-
408- # DISABLED: Create the bindings library for native platform (host) using native-guest wrapper
409- # rust_library(
410- # name = bindings_lib_host,
411- # srcs = [":" + wrapper_native_guest_target],
412- # crate_name = name.replace("-", "_") + "_bindings",
413- # edition = "2021",
414- # visibility = visibility, # Make native bindings publicly available
415- # )
493+ # Create the bindings library for native platform (host) using native-guest wrapper
494+ # The native-guest wrapper includes a no-op export! macro that does nothing,
495+ # since native applications don't export WASM functions
496+ rust_library (
497+ name = bindings_lib_host ,
498+ srcs = [":" + wrapper_native_guest_target ],
499+ crate_name = name .replace ("-" , "_" ) + "_bindings" ,
500+ edition = "2021" ,
501+ visibility = visibility , # Make native bindings publicly available
502+ )
416503
417504 # Create a separate WASM bindings library using guest wrapper
418505 bindings_lib_wasm_base = bindings_lib + "_wasm_base"
0 commit comments