Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
- [#306](https://github.com/bytecodealliance/go-modules/issues/306): do not emit incompatible version feature gates when serializing WIT. For example, if a world with version `0.1.0` *includes* a world from another package with a `@since(version = 0.2.0)` feature gate, then strip that feature gate when serializing to WIT if the version is greater than the world’s package version.
- [#350](https://github.com/bytecodealliance/go-modules/issues/350): correctly align `record` size to the highest alignment of its fields, per [specification](https://github.com/WebAssembly/component-model/blob/main/design/mvp/CanonicalABI.md#element-size).
- [#352](https://github.com/bytecodealliance/go-modules/issues/352): do not use `tuple` types as data shape for `variant` or `result` types, as they may contain a `bool` or not be packed.
- [#356](https://github.com/bytecodealliance/go-modules/issues/356): sort WIT packages topologically by dependency before matching WIT world when generating Go bindings. Warn if there is an ambiguous match.

## [v0.6.2] — 2025-03-16

Expand Down
37 changes: 32 additions & 5 deletions wit/bindgen/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,39 @@ func newGenerator(res *wit.Resolve, opts ...Option) (*generator, error) {
g.opts.cmPackage = cmPackage
}
g.res = res
for _, g.world = range res.Worlds {
if g.world.Match(g.opts.world) {
break
}
// otherwise choose the last world

// Sort WIT packages topologically
packages := slices.Clone(res.Packages)
slices.SortFunc(packages, wit.ComparePackages)
slices.Reverse(packages)

// Select WIT world
var first *wit.World
for _, pkg := range packages {
pkg.Worlds.All()(func(_ string, w *wit.World) bool {
if first == nil {
first = w
}
if w.Match(g.opts.world) {
name := w.Package.Name
name.Extension = w.Name
if g.world == nil {
g.opts.logger.Infof("WIT world: %s", name.String())
g.world = w
} else {
g.opts.logger.Warnf("Warning: ambiguous WIT world: %s", name.String())
}
}
return true
})
}

// Fall back to first world
if g.world == nil {
g.world = first
}

// Instantiate a wasm-tools instance.
g.wasmTools, err = wasmtools.New(context.Background())
if err != nil {
return nil, err
Expand Down
8 changes: 7 additions & 1 deletion wit/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,13 @@ func (p *Package) dependsOn(dep Node) bool {
return done
}

func comparePackages(a, b *Package) int {
// ComparePackages compares two WIT packages, based on dependence.
// When used with [slices.SortFunc], this function will sort packages
// based on their mutual dependence. Packages with fewer or no dependencies will sort last.
// If package a depends on package b, this function returns 1.
// If package b depends on package a, this function returns -1.
// If package a == package b, this function returns 0.
func ComparePackages(a, b *Package) int {
// fmt.Fprintln(os.Stderr, "comparing "+b.Name.String()+" to "+a.Name.String())
switch {
case a == b:
Expand Down
2 changes: 1 addition & 1 deletion wit/wit.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (*Resolve) WITKind() string { return "resolve" }
func (r *Resolve) WIT(ctx Node, _ string) string {
// Sort packages topologically by dependency
packages := slices.Clone(r.Packages)
slices.SortFunc(packages, comparePackages)
slices.SortFunc(packages, ComparePackages)
slices.Reverse(packages)

var b strings.Builder
Expand Down