@@ -97,7 +97,7 @@ def _cpp_component_impl(ctx):
9797 dep_includes .extend (cc_info .compilation_context .includes .to_list ())
9898 dep_includes .extend (cc_info .compilation_context .system_includes .to_list ())
9999 dep_includes .extend (cc_info .compilation_context .quote_includes .to_list ())
100-
100+
101101 # CRITICAL FIX: Stage local CcInfo headers for cross-package dependencies
102102 # External libraries (path contains "external/") don't need staging - use original paths
103103 # Local libraries (same workspace) need staging for relative includes to work
@@ -107,6 +107,7 @@ def _cpp_component_impl(ctx):
107107 if "external/" not in hdr .path :
108108 # Local cross-package header - stage it for relative includes to work
109109 dep_headers .append (hdr )
110+
110111 # External headers are handled via include paths only (no staging needed)
111112
112113 # Generate bindings directory
@@ -171,6 +172,12 @@ def _cpp_component_impl(ctx):
171172 compile_args .add ("-D_WASI_EMULATED_MMAN" )
172173 compile_args .add ("-DCOMPONENT_MODEL_PREVIEW2" )
173174
175+ # Standard library control
176+ if ctx .attr .nostdlib :
177+ compile_args .add ("-nostdlib" )
178+ # When using nostdlib, we need to be more selective about what we link
179+ compile_args .add ("-Wl,--no-entry" ) # Don't expect a main function
180+
174181 # Optimization and language settings
175182 if ctx .attr .optimize :
176183 compile_args .add ("-O3" )
@@ -239,25 +246,88 @@ def _cpp_component_impl(ctx):
239246 # Output
240247 compile_args .add ("-o" , wasm_binary .path )
241248
249+ # Add external dependency headers to inputs (from CcInfo)
250+ external_headers = []
251+ for dep in ctx .attr .deps :
252+ if CcInfo in dep :
253+ cc_info = dep [CcInfo ]
254+ external_headers .extend (cc_info .compilation_context .headers .to_list ())
255+
242256 # Add source files from work directory
243257 for src in sources :
244258 compile_args .add (work_dir .path + "/" + src .basename )
245259
260+ # Compile generated WIT binding C file separately (without C++ flags)
261+ # wit-bindgen generates filenames by converting hyphens to underscores: http-service-world -> http_service_world.c
262+ world_name = ctx .attr .world or "component" # Default to "component" if no world specified
263+ file_safe_world_name = world_name .replace ("-" , "_" ) # Convert hyphens to underscores for filesystem
264+ binding_c_file = bindings_dir .path + "/" + file_safe_world_name + ".c"
265+ binding_h_file = bindings_dir .path + "/" + file_safe_world_name + ".h"
266+ binding_o_file = bindings_dir .path + "/" + file_safe_world_name + "_component_type.o"
267+
268+ # Add bindings header directory to include path
269+ compile_args .add ("-I" + bindings_dir .path )
270+
271+ # Compile the generated C binding file separately to avoid C++ flags
272+ binding_obj_file = ctx .actions .declare_file (ctx .attr .name + "_bindings.o" )
273+
274+ binding_compile_args = ctx .actions .args ()
275+ binding_compile_args .add ("--target=wasm32-wasip2" )
276+ binding_compile_args .add ("--sysroot=" + sysroot_path )
277+ binding_compile_args .add ("-c" ) # Compile only, don't link
278+
279+ # Component model definitions (same as main compilation)
280+ binding_compile_args .add ("-D_WASI_EMULATED_PROCESS_CLOCKS" )
281+ binding_compile_args .add ("-D_WASI_EMULATED_SIGNAL" )
282+ binding_compile_args .add ("-D_WASI_EMULATED_MMAN" )
283+ binding_compile_args .add ("-DCOMPONENT_MODEL_PREVIEW2" )
284+
285+ # Optimization settings
286+ if ctx .attr .optimize :
287+ binding_compile_args .add ("-O3" )
288+ binding_compile_args .add ("-flto" )
289+ else :
290+ binding_compile_args .add ("-O0" )
291+ binding_compile_args .add ("-g" )
292+
293+ # Include directories
294+ binding_compile_args .add ("-I" + work_dir .path )
295+ binding_compile_args .add ("-I" + bindings_dir .path )
296+
297+ # Add dependency include directories
298+ for include_dir in dep_includes :
299+ binding_compile_args .add ("-I" + include_dir )
300+
301+ # Output and input
302+ binding_compile_args .add ("-o" , binding_obj_file .path )
303+ binding_compile_args .add (binding_c_file )
304+
305+ ctx .actions .run (
306+ executable = clang ,
307+ arguments = [binding_compile_args ],
308+ inputs = [work_dir , bindings_dir ] + sysroot_files .files .to_list () + dep_headers + external_headers ,
309+ outputs = [binding_obj_file ],
310+ mnemonic = "CompileCppBindings" ,
311+ progress_message = "Compiling WIT bindings for %s" % ctx .label ,
312+ )
313+
314+ # Add compiled binding object file and pre-compiled component type object to linking
315+ compile_args .add (binding_obj_file .path )
316+ compile_args .add (binding_o_file )
317+
318+ # Add C++ standard library linking for C++ language (unless nostdlib is used)
319+ if ctx .attr .language == "cpp" and not ctx .attr .nostdlib :
320+ compile_args .add ("-lc++" )
321+ compile_args .add ("-lc++abi" )
322+
246323 # Add dependency libraries for linking
247324 for lib in dep_libraries :
248325 compile_args .add (lib .path )
249326
250- # Add external dependency headers to inputs (from CcInfo)
251- external_headers = []
252- for dep in ctx .attr .deps :
253- if CcInfo in dep :
254- cc_info = dep [CcInfo ]
255- external_headers .extend (cc_info .compilation_context .headers .to_list ())
256-
257327 ctx .actions .run (
258328 executable = clang ,
259329 arguments = [compile_args ],
260- inputs = [work_dir ] + sysroot_files .files .to_list () + dep_libraries + dep_headers + external_headers ,
330+ inputs = [work_dir , bindings_dir , binding_obj_file ] + sysroot_files .files .to_list () + dep_libraries + dep_headers + external_headers ,
261331 outputs = [wasm_binary ],
262332 mnemonic = "CompileCppWasm" ,
263333 progress_message = "Compiling C/C++ to WASM for %s" % ctx .label ,
@@ -369,6 +439,10 @@ cpp_component = rule(
369439 default = False ,
370440 doc = "Enable C++ exceptions (increases binary size)" ,
371441 ),
442+ "nostdlib" : attr .bool (
443+ default = False ,
444+ doc = "Disable standard library linking to create minimal components that match WIT specifications exactly" ,
445+ ),
372446 },
373447 toolchains = [
374448 "@rules_wasm_component//toolchains:cpp_component_toolchain_type" ,
@@ -485,7 +559,9 @@ def _cc_component_library_impl(ctx):
485559
486560 # Get C/C++ toolchain
487561 cpp_toolchain = ctx .toolchains ["@rules_wasm_component//toolchains:cpp_component_toolchain_type" ]
488- clang = cpp_toolchain .clang if ctx .attr .language == "c" else cpp_toolchain .clang_cpp
562+
563+ # Use clang for both C and C++ compilation to avoid clang_cpp preprocessor issues
564+ clang = cpp_toolchain .clang
489565 llvm_ar = cpp_toolchain .llvm_ar
490566 sysroot = cpp_toolchain .sysroot
491567 sysroot_files = cpp_toolchain .sysroot_files
@@ -513,6 +589,7 @@ def _cc_component_library_impl(ctx):
513589 if "external/" not in hdr .path :
514590 # Local cross-package header - stage it for relative includes to work
515591 dep_headers .append (hdr )
592+
516593 # External headers are handled via include paths only (no staging needed)
517594
518595 # Set up workspace with proper header staging (CRITICAL FIX for issue #38)
@@ -753,6 +830,10 @@ cc_component_library = rule(
753830 default = False ,
754831 doc = "Enable C++ exceptions (increases binary size)" ,
755832 ),
833+ "nostdlib" : attr .bool (
834+ default = False ,
835+ doc = "Disable standard library linking to create minimal components that match WIT specifications exactly" ,
836+ ),
756837 },
757838 toolchains = [
758839 "@rules_wasm_component//toolchains:cpp_component_toolchain_type" ,
0 commit comments