Skip to content

Add wit-bindgen procedural macro support as alternative to separate crate approachΒ #46

@avrabe

Description

@avrabe

Add wit-bindgen Procedural Macro Support

Overview

Add support for using wit-bindgen's generate!() procedural macro directly in Rust source code as an alternative to the current separate crate approach used by rust_wasm_component_bindgen.

Current vs Proposed Approach

Current Approach βœ… (Keep as Default)

// Generated in separate crate
use my_component_bindings::exports::calculator::Guest;

impl Guest for Component {
    fn add(a: f64, b: f64) -> f64 { a + b }
}

Proposed Approach πŸ†• (Add as Option)

// Inline generation with macro
use wit_bindgen::generate;

generate!({
    world: "calculator-world",
    path: "../wit",
});

impl Guest for Component {
    fn add(a: f64, b: f64) -> f64 { a + b }
}

Motivation

  1. Developer preference: Some developers prefer inline code generation
  2. Simpler project structure: No separate binding crate targets
  3. Full macro features: Access to all wit-bindgen macro capabilities
  4. Industry standard: Matches how other Rust projects use wit-bindgen

Technical Challenges

Bazel Integration Issues

  • Issue: wit-bindgen macros need WIT files at compile time
  • Problem: Bazel's sandboxing prevents easy file access from procedural macros
  • Solution: Use compile_data + rustc_env to provide file paths

Implementation Strategy

rust_wasm_component_macro(
    name = "my_component",
    srcs = ["src/lib.rs"],  # Contains wit_bindgen::generate!() calls
    wit = ":my_interfaces",
    deps = ["@crate_index//:wit-bindgen"],
)

How it works:

  1. compile_data makes WIT files available during compilation
  2. rustc_env provides CARGO_MANIFEST_DIR pointing to WIT files
  3. wit-bindgen macro resolves path: "../wit" relative to that directory

Proposed API

New Rule: rust_wasm_component_macro

load("//rust:rust_wasm_component_macro.bzl", "rust_wasm_component_macro")

rust_wasm_component_macro(
    name = "calculator",
    srcs = ["src/lib.rs"],
    wit = "//wit:calculator_interfaces",
    generation_mode = "guest",  # or "native-guest"
    profiles = ["debug", "release"],
)

Generated Targets

  • {name}_host: Host-platform rust_library for native applications
  • {name}: Final WASM component
  • Automatic wit-bindgen dependency and environment setup

Implementation Plan

Phase 1: Proof of Concept (2-3 weeks) βœ…

  • Basic rust_wasm_component_macro rule implementation
  • Environment variable setup (CARGO_MANIFEST_DIR, WIT_ROOT_DIR)
  • Simple example demonstrating usage pattern
  • Testing with actual wit-bindgen macro (validate file resolution)
  • Verify Bazel sandboxing compatibility

Phase 2: Core Implementation (3-4 weeks)

  • Robust path handling for complex WIT structures
  • Support for WIT dependencies and imports
  • Error handling and debugging improvements
  • Integration with existing toolchain infrastructure
  • Comprehensive test suite with multiple scenarios

Phase 3: Advanced Features (2-3 weeks)

  • Symmetric mode support (requires cpetig's fork integration)
  • Multiple world support in single component
  • Custom wit-bindgen crate versions
  • Performance optimizations (incremental compilation)

Phase 4: Production Ready (1-2 weeks)

  • Complete documentation and examples
  • Migration guide from separate crate approach
  • Performance benchmarking vs current approach
  • CI/CD integration and automated testing

Risk Assessment

⚠️ High Risk

  • Bazel sandboxing: Procedural macros may fail to access files correctly
  • Path resolution: Environment variable approach may not work in all scenarios
  • IDE support: Generated code may not be visible to rust-analyzer

⚠️ Medium Risk

  • Compile performance: Macro expansion may slow incremental builds
  • Debugging complexity: Harder to debug generated code
  • Maintenance overhead: More complex than current approach

βœ… Low Risk

  • Feature compatibility: wit-bindgen macro supports all needed features
  • Ecosystem alignment: Standard Rust procedural macro patterns

Comparison Matrix

Aspect Current (Separate) Proposed (Macro)
Developer Experience Import external crate Inline generation
File Organization Clear separation Everything in one file
Build Complexity Medium High (env setup)
IDE Support Good Variable
Debugging Easy Harder
Bazel Integration Native Workarounds
Flexibility Limited by CLI Full macro features

Recommendation: Hybrid Approach

  1. Keep current as default: Stable, proven, good DX
  2. Add macro as opt-in: For teams that prefer inline generation
  3. Provide easy migration: Allow switching between approaches
  4. Document trade-offs: Help users choose the right approach

Success Criteria

  • βœ… wit-bindgen macros work with Bazel-provided WIT files
  • βœ… Compile times within 20% of current approach
  • βœ… Intuitive API with clear error messages
  • βœ… Comprehensive documentation and examples
  • βœ… All existing functionality available via macro approach

Files Created

Initial implementation available in:

  • rust/rust_wasm_component_macro.bzl - Main rule implementation
  • examples/macro_example/ - Working example
  • docs/wit_bindgen_macro_analysis.md - Detailed technical analysis

Next Steps

  1. Validate POC: Test with real wit-bindgen macro
  2. Performance evaluation: Compare build times
  3. Stakeholder feedback: Get input from potential users
  4. Go/no-go decision: Proceed based on POC results

Estimated Effort: 8-12 weeks (risk-adjusted: 10-16 weeks)
Priority: Medium (enhancement, not critical path)
Dependencies: Requires wit-bindgen crate integration testing

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions