diff --git a/.vscode/settings.json b/.vscode/settings.json index f23ee99..d3e0359 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,5 +20,6 @@ "[jsonc]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true - } + }, + "ecl.launchConfiguration": "no selection" } diff --git a/package.json b/package.json index 1f71420..d75d3fa 100644 --- a/package.json +++ b/package.json @@ -161,6 +161,11 @@ "title": "Generate C Bindings", "category": "WIT" }, + { + "command": "wit-idl.generateBindingsCpp", + "title": "Generate C++ Bindings", + "category": "WIT" + }, { "command": "wit-idl.generateBindingsCSharp", "title": "Generate C# Bindings", @@ -255,6 +260,9 @@ { "command": "wit-idl.generateBindingsC" }, + { + "command": "wit-idl.generateBindingsCpp" + }, { "command": "wit-idl.generateBindingsCSharp" }, @@ -284,6 +292,10 @@ "command": "wit-idl.generateBindingsC", "when": "editorLangId == wit || witIdl.isWasmComponent" }, + { + "command": "wit-idl.generateBindingsCpp", + "when": "editorLangId == wit || witIdl.isWasmComponent" + }, { "command": "wit-idl.generateBindingsCSharp", "when": "editorLangId == wit || witIdl.isWasmComponent" diff --git a/src/extension.ts b/src/extension.ts index 2a070ee..1a3c470 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -666,6 +666,7 @@ export function activate(context: vscode.ExtensionContext) { // Create individual language binding commands const generateRustBindingsCommand = createGenerateBindingsCommand("rust", "Rust"); const generateCBindingsCommand = createGenerateBindingsCommand("c", "C"); + const generateCppBindingsCommand = createGenerateBindingsCommand("cpp", "Cpp"); const generateCSharpBindingsCommand = createGenerateBindingsCommand("csharp", "CSharp"); const generateGoBindingsCommand = createGenerateBindingsCommand("go", "Go"); const generateMoonBitBindingsCommand = createGenerateBindingsCommand("moonbit", "MoonBit"); @@ -716,6 +717,7 @@ export function activate(context: vscode.ExtensionContext) { extractCoreWasmCommand, generateRustBindingsCommand, generateCBindingsCommand, + generateCppBindingsCommand, generateCSharpBindingsCommand, generateGoBindingsCommand, generateMoonBitBindingsCommand, diff --git a/wit-bindgen-wasm/Cargo.lock b/wit-bindgen-wasm/Cargo.lock index bc5e71a..757e364 100644 --- a/wit-bindgen-wasm/Cargo.lock +++ b/wit-bindgen-wasm/Cargo.lock @@ -461,6 +461,21 @@ dependencies = [ "wit-parser", ] +[[package]] +name = "wit-bindgen-cpp" +version = "0.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ea8b16791f62bf956d8735df7afed701e97b91a9e6b8496d406bb9bdccabd7" +dependencies = [ + "anyhow", + "heck", + "wasm-encoder", + "wasm-metadata", + "wit-bindgen-c", + "wit-bindgen-core", + "wit-component", +] + [[package]] name = "wit-bindgen-csharp" version = "0.49.0" @@ -517,6 +532,7 @@ dependencies = [ "wee_alloc", "wit-bindgen-c", "wit-bindgen-core", + "wit-bindgen-cpp", "wit-bindgen-csharp", "wit-bindgen-moonbit", "wit-bindgen-rust", diff --git a/wit-bindgen-wasm/Cargo.toml b/wit-bindgen-wasm/Cargo.toml index b8ba3f6..9fa82fa 100644 --- a/wit-bindgen-wasm/Cargo.toml +++ b/wit-bindgen-wasm/Cargo.toml @@ -22,6 +22,7 @@ wasmparser = { version = "0.243", features = ["component-model"] } wit-parser = "0.243" wit-bindgen-core = "0.49" wit-bindgen-c = "0.49" +wit-bindgen-cpp = "0.49" wit-bindgen-rust = "0.49" wit-bindgen-csharp = "0.49" wit-bindgen-moonbit = "0.49" diff --git a/wit-bindgen-wasm/README.md b/wit-bindgen-wasm/README.md index 6b0afa7..b4b62de 100644 --- a/wit-bindgen-wasm/README.md +++ b/wit-bindgen-wasm/README.md @@ -62,6 +62,7 @@ main(); - `has_world_definition(content: string): boolean` - Check for world definitions - `version(): string` - Get package version - `generate_bindings(content: string, language: string, world_name?: string): string` - Generate language bindings (returns JSON with file map) + - Supported languages: `rust`, `c`, `cpp` (or `c++`), `csharp` (or `c#`), `go`, `moonbit` ### Binary Safety Contract diff --git a/wit-bindgen-wasm/src/lib.rs b/wit-bindgen-wasm/src/lib.rs index 30e364a..e5aca2a 100644 --- a/wit-bindgen-wasm/src/lib.rs +++ b/wit-bindgen-wasm/src/lib.rs @@ -10,6 +10,7 @@ use wasmparser::{Parser, Payload}; use wit_bindgen_core::Files; use wit_bindgen_rust as rust; use wit_bindgen_c as c; +use wit_bindgen_cpp as cpp; use wit_bindgen_csharp as csharp; use wit_bindgen_moonbit as moonbit; @@ -226,6 +227,7 @@ impl WitBindgen { let files = match language.to_lowercase().as_str() { "rust" => self.generate_rust_bindings(content, world_name), "c" => self.generate_c_bindings(content, world_name), + "cpp" | "c++" => self.generate_cpp_bindings(content, world_name), "csharp" | "c#" => self.generate_csharp_bindings(content, world_name), "go" => self.generate_go_bindings(content, world_name), "moonbit" => self.generate_moonbit_bindings(content, world_name), @@ -233,7 +235,7 @@ impl WitBindgen { let mut error_files = HashMap::new(); error_files.insert( "error.txt".to_string(), - format!("// Unsupported language: {}\n// Supported languages: rust, c, csharp, go, moonbit", language) + format!("// Unsupported language: {}\n// Supported languages: rust, c, cpp, csharp, go, moonbit", language) ); error_files }, @@ -285,6 +287,49 @@ impl WitBindgen { Ok(result) } + /// Generate C++ bindings using wit-bindgen-cpp library + fn generate_cpp_bindings(&self, content: &str, world_name: Option) -> HashMap { + match self.generate_cpp_with_wit_bindgen(content, world_name.as_deref()) { + Ok(files) => files, + Err(e) => { + console_error(&format!("wit-bindgen-cpp failed: {}", e)); + let mut error_files = HashMap::new(); + error_files.insert( + "error.txt".to_string(), + format!("C++ binding generation failed: {}", e) + ); + error_files + } + } + } + + /// Generate C++ bindings using wit-bindgen-cpp library + fn generate_cpp_with_wit_bindgen(&self, content: &str, world_name: Option<&str>) -> Result, anyhow::Error> { + let inline_path = Path::new("inline.wit"); + let mut resolve = Resolve::default(); + let package_id = resolve.push_str(inline_path, content) + .with_context(|| "Failed to parse WIT content for C++ binding generation")?; + + let world_id = if let Some(world_name) = world_name { + resolve.select_world(&[package_id], Some(world_name))? + } else { + resolve.select_world(&[package_id], None)? + }; + + let opts = cpp::Opts::default(); + let mut generator = opts.build(None); + let mut files = Files::default(); + + generator.generate(&resolve, world_id, &mut files)?; + + let mut result = HashMap::new(); + for (filename, content) in files.iter() { + result.insert(filename.to_string(), bytes_to_latin1_string(content)); + } + + Ok(result) + } + /// Generate Rust bindings using wit-bindgen-rust library fn generate_rust_bindings(&self, content: &str, world_name: Option) -> HashMap { match self.generate_rust_with_wit_bindgen(content, world_name.as_deref()) {