Skip to content

Commit 4284ea8

Browse files
authored
reboot wit-bindgen-go (#1447)
* reboot `wit-bindgen-go` This re-introduces Go support, with a new implementation written from scratch. While the previous incarnation targeted TinyGo and reused the C generator for lifting and lowering, this one targets "big" Go and handles lifting and lowering itself. In addition, it supports idiomatic, goroutine-based concurrency on top of the component model async ABI, including streams and futures. This implementation is also distinct from the [go-modules](https://github.com/bytecodealliance/go-modules) project, which has a number of limitations (e.g. no async support, not safe for use with "big" Go) and is no longer being actively maintained. Note that the async support currently requires [a small patch](dicej/go@a1c8322) to the Go `runtime` library. I plan to work with the upstream project to make that patch unecessary in the future. Components that don't use async features should work with stock, unpatched Go. One of the tricky parts about lowering values and passing pointers to e.g. `{stream,future}.{read,write}` is that we must tell the Go garbage collector to pin the pointers (i.e. mark the pointee as both immovable and uncollectable) for as long as the host has access to them, but then unpin them promptly afterward to avoid leaks. We do this using `runtime.Pinner` instances, most of which are locally scoped and easy to reason about. However, we must use a couple of globally-scoped pinners as well: one for `cabi_realloc` allocations by the host when it lowers parameters (which we unpin after lifting those parameters) and another for returning values from sync-lifted exports (which we unpin in post-return functions). There are a couple of known missing features which I'll open GitHub issues for: 1. Resource handles are not being restored for unwritten items in the case of an incomplete stream or future write. 2. Importing and/or exporting multiple versions of the same package will cause name clashes. In addition, I plan to expand the test coverage beyond the basics covered in this commit. Signed-off-by: Joel Dice <joel.dice@fermyon.com> add ping-pong Go tests Signed-off-by: Joel Dice <joel.dice@fermyon.com> address review feedback Signed-off-by: Joel Dice <joel.dice@fermyon.com> add wit-bindgen-go to ci/publish.rs Signed-off-by: Joel Dice <joel.dice@fermyon.com> enable Go in test CI matrix I'm assuming the default version of Go on the GitHub worker image will be sufficient; if not, we can install a different one explicitly. I'm not enabling the async tests for Go yet, since that will require publishing and installing a build of Go with [this patch](dicej/go@a1c8322); I'll need to do some homework to find out the best way to do that. Signed-off-by: Joel Dice <joel.dice@fermyon.com> fix codegen tests Signed-off-by: Joel Dice <joel.dice@fermyon.com> update Go runtime tests to use `run` export Signed-off-by: Joel Dice <joel.dice@fermyon.com> run cargo fmt Signed-off-by: Joel Dice <joel.dice@fermyon.com> remove `publish = false` from crates/go/Cargo.toml Signed-off-by: Joel Dice <joel.dice@fermyon.com> temporarily skip async codegen tests for Go Signed-off-by: Joel Dice <joel.dice@fermyon.com> add `async = true` config directive to `async-trait-function.wit` Signed-off-by: Joel Dice <joel.dice@fermyon.com> indicate that `async-trait-function.wit-no-std` works for Rust Signed-off-by: Joel Dice <joel.dice@fermyon.com> add error contexts to `Go::compile` Signed-off-by: Joel Dice <joel.dice@fermyon.com> add `actions/setup-go` to workflow Signed-off-by: Joel Dice <joel.dice@fermyon.com> add finalizers where appropriate; tweak `StreamReader` API Signed-off-by: Joel Dice <joel.dice@fermyon.com> update workspace to 2024 edition Signed-off-by: Joel Dice <joel.dice@fermyon.com> * remove indirection in `wit_types.Option` Signed-off-by: Joel Dice <joel.dice@fermyon.com> * add crates/go/README.md Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent f1d72d4 commit 4284ea8

File tree

97 files changed

+6301
-646
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+6301
-646
lines changed

.github/workflows/main.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
matrix:
6060
os: [ubuntu-latest, macos-latest, windows-latest]
6161
# moonbit removed from language matrix for now - causing CI failures
62-
lang: [c, rust, csharp, cpp]
62+
lang: [c, rust, csharp, cpp, go]
6363
exclude:
6464
# For now csharp doesn't work on macos, so exclude it from testing.
6565
- os: macos-latest
@@ -85,6 +85,12 @@ jobs:
8585
dotnet-version: '9.x'
8686
if: matrix.lang == 'csharp'
8787

88+
- name: Setup Go
89+
uses: actions/setup-go@v5
90+
with:
91+
go-version: 1.25.4
92+
if: matrix.lang == 'go'
93+
8894
# Hacky work-around for https://github.com/dotnet/runtime/issues/80619
8995
- run: dotnet new console -o /tmp/foo
9096
if: matrix.os != 'windows-latest' && matrix.lang == 'csharp'

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ CLI tool to generate bindings for WIT documents and the component model.
1515
resolver = "2"
1616

1717
[workspace.package]
18-
edition = "2021"
18+
edition = "2024"
1919
version = "0.49.0"
2020
license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT"
2121
repository = "https://github.com/bytecodealliance/wit-bindgen"
22-
rust-version = "1.82.0"
22+
rust-version = "1.85.0"
2323

2424
[workspace.dependencies]
2525
anyhow = "1.0.72"
@@ -48,6 +48,7 @@ wit-bindgen-rust = { path = "crates/rust", version = "0.49.0" }
4848
wit-bindgen-csharp = { path = 'crates/csharp', version = '0.49.0' }
4949
wit-bindgen-markdown = { path = 'crates/markdown', version = '0.49.0' }
5050
wit-bindgen-moonbit = { path = 'crates/moonbit', version = '0.49.0' }
51+
wit-bindgen-go = { path = 'crates/go', version = '0.49.0' }
5152
wit-bindgen = { path = 'crates/guest-rust', version = '0.49.0', default-features = false }
5253
wit-bindgen-test = { path = 'crates/test', version = '0.49.0' }
5354

@@ -64,6 +65,7 @@ wit-bindgen-cpp = { workspace = true, features = ['clap'], optional = true }
6465
wit-bindgen-markdown = { workspace = true, features = ['clap'], optional = true }
6566
wit-bindgen-moonbit = { workspace = true, features = ['clap'], optional = true }
6667
wit-bindgen-csharp = { workspace = true, features = ['clap'], optional = true }
68+
wit-bindgen-go = { workspace = true, features = ['clap'], optional = true }
6769
wit-bindgen-test = { workspace = true }
6870
wit-component = { workspace = true }
6971
wasm-encoder = { workspace = true }
@@ -84,7 +86,7 @@ c = ['dep:wit-bindgen-c']
8486
cpp = ['dep:wit-bindgen-cpp']
8587
rust = ['dep:wit-bindgen-rust']
8688
markdown = ['dep:wit-bindgen-markdown']
87-
go = []
89+
go = ['dep:wit-bindgen-go']
8890
csharp = ['dep:wit-bindgen-csharp']
8991
csharp-mono = ['csharp']
9092
moonbit = ['dep:wit-bindgen-moonbit']

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,11 @@ Now you can build with:
362362
dotnet publish
363363
```
364364

365-
Checkout out [componentize-dotnet](https://github.com/bytecodealliance/componentize-dotnet) for a simplified experience.
365+
Check out [componentize-dotnet](https://github.com/bytecodealliance/componentize-dotnet) for a simplified experience.
366+
367+
### Guest: Go
368+
369+
See the [wit-bindgen-go README.md](crates/go/README.md) for details and generating and using Go bindings.
366370

367371
### Guest: Java
368372

ci/publish.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const CRATES_TO_PUBLISH: &[&str] = &[
2424
"wit-bindgen-csharp",
2525
"wit-bindgen-markdown",
2626
"wit-bindgen-moonbit",
27+
"wit-bindgen-go",
2728
"wit-bindgen-rust-macro",
2829
"wit-bindgen-rt",
2930
"wit-bindgen",
@@ -65,11 +66,13 @@ fn main() {
6566
bump_version(&krate, &crates, name == "bump-patch");
6667
}
6768
// update the lock file
68-
assert!(Command::new("cargo")
69-
.arg("fetch")
70-
.status()
71-
.unwrap()
72-
.success());
69+
assert!(
70+
Command::new("cargo")
71+
.arg("fetch")
72+
.status()
73+
.unwrap()
74+
.success()
75+
);
7376
}
7477

7578
"publish" => {

ci/rebuild-libwit-bindgen-cabi.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub unsafe extern "C" fn $realloc(
5656
align: usize,
5757
new_len: usize,
5858
) -> *mut u8 {
59-
crate::rt::cabi_realloc(old_ptr, old_len, align, new_len)
59+
unsafe { crate::rt::cabi_realloc(old_ptr, old_len, align, new_len) }
6060
}
6161
EOF
6262

crates/c/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use wit_bindgen_core::abi::{
1010
self, AbiVariant, Bindgen, Bitcast, Instruction, LiftLower, WasmSignature, WasmType,
1111
};
1212
use wit_bindgen_core::{
13-
dealias, uwrite, uwriteln, wit_parser::*, AnonymousTypeGenerator, AsyncFilterSet, Direction,
14-
Files, InterfaceGenerator as _, Ns, WorldGenerator,
13+
AnonymousTypeGenerator, AsyncFilterSet, Direction, Files, InterfaceGenerator as _, Ns,
14+
WorldGenerator, dealias, uwrite, uwriteln, wit_parser::*,
1515
};
1616
use wit_component::StringEncoding;
1717

crates/core/src/abi.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::iter;
33

44
pub use wit_parser::abi::{AbiVariant, FlatTypes, WasmSignature, WasmType};
55
use wit_parser::{
6-
align_to_arch, Alignment, ArchitectureSize, ElementInfo, Enum, Flags, FlagsRepr, Function,
7-
Handle, Int, Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDefKind, TypeId, Variant,
6+
Alignment, ArchitectureSize, ElementInfo, Enum, Flags, FlagsRepr, Function, Handle, Int,
7+
Record, Resolve, Result_, SizeAlign, Tuple, Type, TypeDefKind, TypeId, Variant, align_to_arch,
88
};
99

1010
// Helper macro for defining instructions without having to have tons of
@@ -806,6 +806,12 @@ pub fn guest_export_needs_post_return(resolve: &Resolve, func: &Function) -> boo
806806
.unwrap_or(false)
807807
}
808808

809+
pub fn guest_export_params_have_allocations(resolve: &Resolve, func: &Function) -> bool {
810+
func.params
811+
.iter()
812+
.any(|(_, t)| needs_deallocate(resolve, &t, Deallocate::Lists))
813+
}
814+
809815
fn needs_deallocate(resolve: &Resolve, ty: &Type, what: Deallocate) -> bool {
810816
match ty {
811817
Type::String => true,
@@ -1134,7 +1140,10 @@ impl<'a, B: Bindgen> Generator<'a, B> {
11341140
for (param_name, ty) in func.params.iter() {
11351141
let Some(types) = flat_types(self.resolve, ty, Some(max_flat_params))
11361142
else {
1137-
panic!("failed to flatten types during direct parameter lifting ('{param_name}' in func '{}')", func.name);
1143+
panic!(
1144+
"failed to flatten types during direct parameter lifting ('{param_name}' in func '{}')",
1145+
func.name
1146+
);
11381147
};
11391148
for _ in 0..types.len() {
11401149
self.emit(&Instruction::GetArg { nth: offset });

crates/core/src/async_.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{bail, Result};
1+
use anyhow::{Result, bail};
22
use std::collections::HashSet;
33
use std::fmt;
44
use wit_parser::{Function, FunctionKind, Resolve, WorldKey};

crates/core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ pub trait InterfaceGenerator<'a> {
148148
fn type_record(&mut self, id: TypeId, name: &str, record: &Record, docs: &Docs);
149149
fn type_resource(&mut self, id: TypeId, name: &str, docs: &Docs);
150150
fn type_flags(&mut self, id: TypeId, name: &str, flags: &Flags, docs: &Docs);
151-
fn type_tuple(&mut self, id: TypeId, name: &str, flags: &Tuple, docs: &Docs);
151+
fn type_tuple(&mut self, id: TypeId, name: &str, tuple: &Tuple, docs: &Docs);
152152
fn type_variant(&mut self, id: TypeId, name: &str, variant: &Variant, docs: &Docs);
153153
fn type_option(&mut self, id: TypeId, name: &str, payload: &Type, docs: &Docs);
154154
fn type_result(&mut self, id: TypeId, name: &str, result: &Result_, docs: &Docs);

0 commit comments

Comments
 (0)