Skip to content

Commit

Permalink
wit, cmd/wit-bindgen-go: WIT tree shaking
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ydnar committed Dec 6, 2024
1 parent c0548c3 commit 2359a60
Show file tree
Hide file tree
Showing 32 changed files with 2,075 additions and 2,402 deletions.
37 changes: 22 additions & 15 deletions cmd/wit-bindgen-go/cmd/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var Command = &cli.Command{
Value: "",
OnlyOnce: true,
Config: cli.StringConfig{TrimSpace: true},
Usage: "WIT world to generate, otherwise generate all worlds",
Usage: "WIT world to generate, otherwise generate the first world",
},
&cli.StringFlag{
Name: "out",
Expand All @@ -52,11 +52,15 @@ var Command = &cli.Command{
Value: "",
OnlyOnce: true,
Config: cli.StringConfig{TrimSpace: true},
Usage: "Import path for the Component Model utility package, e.g. go.bytecodealliance.org/cm",
Usage: "import path for the Component Model utility package, e.g. go.bytecodealliance.org/cm",
},
&cli.BoolFlag{
Name: "versioned",
Usage: "emit versioned Go package(s) for each WIT version",
Usage: "emit versioned Go package(s) corresponding to WIT package version",
},
&cli.BoolFlag{
Name: "generate-wit",
Usage: "generate a WIT file for each generated Go package corresponding to each WIT world or interface",
},
&cli.BoolFlag{
Name: "dry-run",
Expand All @@ -68,16 +72,17 @@ var Command = &cli.Command{

// Config is the configuration for the `generate` command.
type config struct {
logger logging.Logger
dryRun bool
out string
outPerm os.FileMode
pkgRoot string
world string
cm string
versioned bool
forceWIT bool
path string
logger logging.Logger
dryRun bool
out string
outPerm os.FileMode
pkgRoot string
world string
cm string
versioned bool
generateWIT bool
forceWIT bool
path string
}

func action(ctx context.Context, cmd *cli.Command) error {
Expand All @@ -94,10 +99,11 @@ func action(ctx context.Context, cmd *cli.Command) error {
packages, err := bindgen.Go(res,
bindgen.GeneratedBy(cmd.Root().Name),
bindgen.Logger(cfg.logger),
bindgen.World(cfg.world),
bindgen.PackageRoot(cfg.pkgRoot),
bindgen.Versioned(cfg.versioned),
bindgen.World(cfg.world),
bindgen.CMPackage(cfg.cm),
bindgen.Versioned(cfg.versioned),
bindgen.WIT(cfg.generateWIT),
)
if err != nil {
return err
Expand Down Expand Up @@ -141,6 +147,7 @@ func parseFlags(_ context.Context, cmd *cli.Command) (*config, error) {
cmd.String("world"),
cmd.String("cm"),
cmd.Bool("versioned"),
cmd.Bool("generate-wit"),
cmd.Bool("force-wit"),
path,
}, nil
Expand Down
36 changes: 32 additions & 4 deletions cmd/wit-bindgen-go/cmd/wit/wit.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ var Command = &cli.Command{
Value: "",
OnlyOnce: true,
Config: cli.StringConfig{TrimSpace: true},
Usage: "WIT world to generate, otherwise generate all worlds",
Usage: "WIT world to emit, otherwise emit all worlds",
},
&cli.StringFlag{
Name: "interface",
Aliases: []string{"i"},
Value: "",
OnlyOnce: true,
Config: cli.StringConfig{TrimSpace: true},
Usage: "WIT interface to emit, otherwise emit all interfaces",
},
},
Action: action,
Expand All @@ -32,19 +40,30 @@ func action(ctx context.Context, cmd *cli.Command) error {
if err != nil {
return err
}

res, err := witcli.LoadWIT(ctx, path, cmd.Reader, cmd.Bool("force-wit"))
if err != nil {
return err
}

var w *wit.World
world := cmd.String("world")
if world != "" {
if world := cmd.String("world"); world != "" {
w = findWorld(res, world)
if w == nil {
return fmt.Errorf("world %s not found", world)
}
}
fmt.Print(res.WIT(w, ""))

var i *wit.Interface
if face := cmd.String("interface"); face != "" {
i = findInterface(res, face)
if i == nil {
return fmt.Errorf("interface %s not found", face)
}
}

filter := wit.Filter(w, i)
fmt.Print(res.WIT(filter, ""))
return nil
}

Expand All @@ -56,3 +75,12 @@ func findWorld(r *wit.Resolve, pattern string) *wit.World {
}
return nil
}

func findInterface(r *wit.Resolve, pattern string) *wit.Interface {
for _, i := range r.Interfaces {
if i.Match(pattern) {
return i
}
}
return nil
}
16 changes: 16 additions & 0 deletions internal/memoize/memoize.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package memoize

// Function memoizes f, caching unique values of k.
// Initial calls to the resulting function will call f(k), then cache and return v.
// Subsequent calls will return the cached value for k.
func Function[F func(K) V, K comparable, V any](f F) F {
m := make(map[K]V)
return func(k K) V {
if v, ok := m[k]; ok {
return v
}
v := f(k)
m[k] = v
return v
}
}
38 changes: 36 additions & 2 deletions internal/wasm/section.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package wasm

import (
"bytes"

"go.bytecodealliance.org/internal/wasm/uleb128"
)

// SectionID represents a WebAssembly [section SectionID].
//
// [section SectionID]: https://webassembly.github.io/spec/core/binary/modules.html#sections
Expand Down Expand Up @@ -47,6 +53,34 @@ func (*CustomSection) SectionID() SectionID {

// SectionContents implements the [Section] interface.
func (s *CustomSection) SectionContents() ([]byte, error) {
// TODO: encode name correctly
return append([]byte(s.Name), s.Contents...), nil
var buf bytes.Buffer
_, err := WriteString(&buf, s.Name)
if err != nil {
return nil, err
}
_, err = buf.Write(s.Contents)
return buf.Bytes(), err
}

type LinkingSection struct{}

// SectionID implements the [Section] interface.
func (*LinkingSection) SectionID() SectionID {
return SectionCustom
}

// SectionContents implements the [Section] interface.
func (s *LinkingSection) SectionContents() ([]byte, error) {
var buf bytes.Buffer
custom := &CustomSection{Name: "linking"}
contents, err := custom.SectionContents()
if err != nil {
return nil, err
}
_, err = buf.Write(contents)
if err != nil {
return nil, err
}
_, err = uleb128.Write(&buf, 2) // linking section version 2
return buf.Bytes(), err
}
Loading

0 comments on commit 2359a60

Please sign in to comment.