Skip to content

Commit 2359a60

Browse files
committed
wit, cmd/wit-bindgen-go: WIT tree shaking
This enables WIT tree-shaking by world or interface, as a precursor for Go package-level component metadata. wit/bindgen: oops wit/bindgen: add WIT generation for each WIT interface (Go package) Currently disabled. wit/bindgen: cgo + linker tricks WIP wit: fix typo wit/bindgen: typo wit: type aliases force transitive dependency on the dependencies of their parent interface wit: prepare for filtering interface contents wit: remove ConstrainTo internal/wasm: stub linking section wit/bindgen: generate .wasm.syso files in each Go package Currently stubbed out (if false). Depends on tinygo-org/tinygo#4593 wit: revise package sorting algorithm This enables wasi:http to sort before wasi:cli. wit/bindgen: more cleanup (path -> pkgPath) wit/bindgen: optionally generate WIT files for each Go package cmd/wit-bindgen-go: --generate-wit option to generate WIT files for each Go package wit/bindgen: generate synthetic worlds in the go:bindgen package namespace
1 parent c0548c3 commit 2359a60

32 files changed

+2075
-2402
lines changed

cmd/wit-bindgen-go/cmd/generate/generate.go

+22-15
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var Command = &cli.Command{
2828
Value: "",
2929
OnlyOnce: true,
3030
Config: cli.StringConfig{TrimSpace: true},
31-
Usage: "WIT world to generate, otherwise generate all worlds",
31+
Usage: "WIT world to generate, otherwise generate the first world",
3232
},
3333
&cli.StringFlag{
3434
Name: "out",
@@ -52,11 +52,15 @@ var Command = &cli.Command{
5252
Value: "",
5353
OnlyOnce: true,
5454
Config: cli.StringConfig{TrimSpace: true},
55-
Usage: "Import path for the Component Model utility package, e.g. go.bytecodealliance.org/cm",
55+
Usage: "import path for the Component Model utility package, e.g. go.bytecodealliance.org/cm",
5656
},
5757
&cli.BoolFlag{
5858
Name: "versioned",
59-
Usage: "emit versioned Go package(s) for each WIT version",
59+
Usage: "emit versioned Go package(s) corresponding to WIT package version",
60+
},
61+
&cli.BoolFlag{
62+
Name: "generate-wit",
63+
Usage: "generate a WIT file for each generated Go package corresponding to each WIT world or interface",
6064
},
6165
&cli.BoolFlag{
6266
Name: "dry-run",
@@ -68,16 +72,17 @@ var Command = &cli.Command{
6872

6973
// Config is the configuration for the `generate` command.
7074
type config struct {
71-
logger logging.Logger
72-
dryRun bool
73-
out string
74-
outPerm os.FileMode
75-
pkgRoot string
76-
world string
77-
cm string
78-
versioned bool
79-
forceWIT bool
80-
path string
75+
logger logging.Logger
76+
dryRun bool
77+
out string
78+
outPerm os.FileMode
79+
pkgRoot string
80+
world string
81+
cm string
82+
versioned bool
83+
generateWIT bool
84+
forceWIT bool
85+
path string
8186
}
8287

8388
func action(ctx context.Context, cmd *cli.Command) error {
@@ -94,10 +99,11 @@ func action(ctx context.Context, cmd *cli.Command) error {
9499
packages, err := bindgen.Go(res,
95100
bindgen.GeneratedBy(cmd.Root().Name),
96101
bindgen.Logger(cfg.logger),
97-
bindgen.World(cfg.world),
98102
bindgen.PackageRoot(cfg.pkgRoot),
99-
bindgen.Versioned(cfg.versioned),
103+
bindgen.World(cfg.world),
100104
bindgen.CMPackage(cfg.cm),
105+
bindgen.Versioned(cfg.versioned),
106+
bindgen.WIT(cfg.generateWIT),
101107
)
102108
if err != nil {
103109
return err
@@ -141,6 +147,7 @@ func parseFlags(_ context.Context, cmd *cli.Command) (*config, error) {
141147
cmd.String("world"),
142148
cmd.String("cm"),
143149
cmd.Bool("versioned"),
150+
cmd.Bool("generate-wit"),
144151
cmd.Bool("force-wit"),
145152
path,
146153
}, nil

cmd/wit-bindgen-go/cmd/wit/wit.go

+32-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ var Command = &cli.Command{
2121
Value: "",
2222
OnlyOnce: true,
2323
Config: cli.StringConfig{TrimSpace: true},
24-
Usage: "WIT world to generate, otherwise generate all worlds",
24+
Usage: "WIT world to emit, otherwise emit all worlds",
25+
},
26+
&cli.StringFlag{
27+
Name: "interface",
28+
Aliases: []string{"i"},
29+
Value: "",
30+
OnlyOnce: true,
31+
Config: cli.StringConfig{TrimSpace: true},
32+
Usage: "WIT interface to emit, otherwise emit all interfaces",
2533
},
2634
},
2735
Action: action,
@@ -32,19 +40,30 @@ func action(ctx context.Context, cmd *cli.Command) error {
3240
if err != nil {
3341
return err
3442
}
43+
3544
res, err := witcli.LoadWIT(ctx, path, cmd.Reader, cmd.Bool("force-wit"))
3645
if err != nil {
3746
return err
3847
}
48+
3949
var w *wit.World
40-
world := cmd.String("world")
41-
if world != "" {
50+
if world := cmd.String("world"); world != "" {
4251
w = findWorld(res, world)
4352
if w == nil {
4453
return fmt.Errorf("world %s not found", world)
4554
}
4655
}
47-
fmt.Print(res.WIT(w, ""))
56+
57+
var i *wit.Interface
58+
if face := cmd.String("interface"); face != "" {
59+
i = findInterface(res, face)
60+
if i == nil {
61+
return fmt.Errorf("interface %s not found", face)
62+
}
63+
}
64+
65+
filter := wit.Filter(w, i)
66+
fmt.Print(res.WIT(filter, ""))
4867
return nil
4968
}
5069

@@ -56,3 +75,12 @@ func findWorld(r *wit.Resolve, pattern string) *wit.World {
5675
}
5776
return nil
5877
}
78+
79+
func findInterface(r *wit.Resolve, pattern string) *wit.Interface {
80+
for _, i := range r.Interfaces {
81+
if i.Match(pattern) {
82+
return i
83+
}
84+
}
85+
return nil
86+
}

internal/memoize/memoize.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package memoize
2+
3+
// Function memoizes f, caching unique values of k.
4+
// Initial calls to the resulting function will call f(k), then cache and return v.
5+
// Subsequent calls will return the cached value for k.
6+
func Function[F func(K) V, K comparable, V any](f F) F {
7+
m := make(map[K]V)
8+
return func(k K) V {
9+
if v, ok := m[k]; ok {
10+
return v
11+
}
12+
v := f(k)
13+
m[k] = v
14+
return v
15+
}
16+
}

internal/wasm/section.go

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package wasm
22

3+
import (
4+
"bytes"
5+
6+
"go.bytecodealliance.org/internal/wasm/uleb128"
7+
)
8+
39
// SectionID represents a WebAssembly [section SectionID].
410
//
511
// [section SectionID]: https://webassembly.github.io/spec/core/binary/modules.html#sections
@@ -47,6 +53,34 @@ func (*CustomSection) SectionID() SectionID {
4753

4854
// SectionContents implements the [Section] interface.
4955
func (s *CustomSection) SectionContents() ([]byte, error) {
50-
// TODO: encode name correctly
51-
return append([]byte(s.Name), s.Contents...), nil
56+
var buf bytes.Buffer
57+
_, err := WriteString(&buf, s.Name)
58+
if err != nil {
59+
return nil, err
60+
}
61+
_, err = buf.Write(s.Contents)
62+
return buf.Bytes(), err
63+
}
64+
65+
type LinkingSection struct{}
66+
67+
// SectionID implements the [Section] interface.
68+
func (*LinkingSection) SectionID() SectionID {
69+
return SectionCustom
70+
}
71+
72+
// SectionContents implements the [Section] interface.
73+
func (s *LinkingSection) SectionContents() ([]byte, error) {
74+
var buf bytes.Buffer
75+
custom := &CustomSection{Name: "linking"}
76+
contents, err := custom.SectionContents()
77+
if err != nil {
78+
return nil, err
79+
}
80+
_, err = buf.Write(contents)
81+
if err != nil {
82+
return nil, err
83+
}
84+
_, err = uleb128.Write(&buf, 2) // linking section version 2
85+
return buf.Bytes(), err
5286
}

0 commit comments

Comments
 (0)