Skip to content

Commit 4720f35

Browse files
committed
wasm: add //go:wasmexport support
This adds support for the `//go:wasmexport` pragma as proposed here: golang/go#65199 It is currently implemented only for wasip1 and wasm-unknown, but it is certainly possible to extend it to other targets like GOOS=js and wasip2.
1 parent 52788e5 commit 4720f35

22 files changed

+763
-68
lines changed

builder/build.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
197197
ABI: config.ABI(),
198198
GOOS: config.GOOS(),
199199
GOARCH: config.GOARCH(),
200+
BuildMode: config.BuildMode(),
200201
CodeModel: config.CodeModel(),
201202
RelocationModel: config.RelocationModel(),
202203
SizeLevel: sizeLevel,
@@ -649,6 +650,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
649650
result.Binary = result.Executable // final file
650651
ldflags := append(config.LDFlags(), "-o", result.Executable)
651652

653+
if config.Options.BuildMode == "c-shared" {
654+
if !strings.HasPrefix(config.Triple(), "wasm32-") {
655+
return result, fmt.Errorf("buildmode c-shared is only supported on wasm at the moment")
656+
}
657+
ldflags = append(ldflags, "--no-entry")
658+
}
659+
652660
// Add compiler-rt dependency if needed. Usually this is a simple load from
653661
// a cache.
654662
if config.Target.RTLib == "compiler-rt" {
@@ -884,7 +892,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
884892

885893
err := cmd.Run()
886894
if err != nil {
887-
return fmt.Errorf("wasm-tools failed: %w", err)
895+
return fmt.Errorf("`wasm-tools component embed` failed: %w", err)
888896
}
889897

890898
// wasm-tools component new embedded.wasm -o component.wasm
@@ -904,7 +912,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
904912

905913
err = cmd.Run()
906914
if err != nil {
907-
return fmt.Errorf("wasm-tools failed: %w", err)
915+
return fmt.Errorf("`wasm-tools component new` failed: %w", err)
908916
}
909917
}
910918

compileopts/config.go

+11
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ func (c *Config) CPU() string {
3333
return c.Target.CPU
3434
}
3535

36+
// The current build mode (like the `-buildmode` command line flag).
37+
func (c *Config) BuildMode() string {
38+
if c.Options.BuildMode != "" {
39+
return c.Options.BuildMode
40+
}
41+
if c.Target.BuildMode != "" {
42+
return c.Target.BuildMode
43+
}
44+
return "default"
45+
}
46+
3647
// Features returns a list of features this CPU supports. For example, for a
3748
// RISC-V processor, that could be "+a,+c,+m". For many targets, an empty list
3849
// will be returned.

compileopts/options.go

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
)
99

1010
var (
11+
validBuildModeOptions = []string{"default", "c-shared"}
1112
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
1213
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
1314
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
@@ -26,6 +27,7 @@ type Options struct {
2627
GOMIPS string // environment variable (only used with GOARCH=mips and GOARCH=mipsle)
2728
Directory string // working dir, leave it unset to use the current working dir
2829
Target string
30+
BuildMode string // -buildmode flag
2931
Opt string
3032
GC string
3133
PanicStrategy string
@@ -61,6 +63,14 @@ type Options struct {
6163

6264
// Verify performs a validation on the given options, raising an error if options are not valid.
6365
func (o *Options) Verify() error {
66+
if o.BuildMode != "" {
67+
valid := isInArray(validBuildModeOptions, o.BuildMode)
68+
if !valid {
69+
return fmt.Errorf(`invalid buildmode option '%s': valid values are %s`,
70+
o.BuildMode,
71+
strings.Join(validBuildModeOptions, ", "))
72+
}
73+
}
6474
if o.GC != "" {
6575
valid := isInArray(validGCOptions, o.GC)
6676
if !valid {

compileopts/target.go

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type TargetSpec struct {
3232
GOARCH string `json:"goarch,omitempty"`
3333
SoftFloat bool // used for non-baremetal systems (GOMIPS=softfloat etc)
3434
BuildTags []string `json:"build-tags,omitempty"`
35+
BuildMode string `json:"buildmode,omitempty"` // default build mode (if nothing specified)
3536
GC string `json:"gc,omitempty"`
3637
Scheduler string `json:"scheduler,omitempty"`
3738
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)

compiler/compiler.go

+6
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Config struct {
4444
ABI string
4545
GOOS string
4646
GOARCH string
47+
BuildMode string
4748
CodeModel string
4849
RelocationModel string
4950
SizeLevel int
@@ -1384,6 +1385,11 @@ func (b *builder) createFunction() {
13841385
b.llvmFn.SetLinkage(llvm.InternalLinkage)
13851386
b.createFunction()
13861387
}
1388+
1389+
// Create wrapper function that can be called externally.
1390+
if b.info.wasmExport != "" {
1391+
b.createWasmExport()
1392+
}
13871393
}
13881394

13891395
// posser is an interface that's implemented by both ssa.Value and

0 commit comments

Comments
 (0)