Skip to content

Commit 2abf0b0

Browse files
committed
Initial commit of go-protoc-gen-grpc
0 parents  commit 2abf0b0

File tree

37 files changed

+783
-0
lines changed

37 files changed

+783
-0
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/workflows/ci.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: CI
2+
on:
3+
push:
4+
branches:
5+
- main
6+
tags:
7+
- "*"
8+
pull_request:
9+
workflow_dispatch:
10+
11+
jobs:
12+
build:
13+
runs-on: ${{ matrix.os }}
14+
strategy:
15+
fail-fast: false
16+
matrix:
17+
mode:
18+
- cgo
19+
- wazero
20+
os:
21+
- macos-12
22+
- ubuntu-22.04
23+
- windows-2022
24+
steps:
25+
- uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- uses: actions/setup-go@v4
30+
with:
31+
go-version: '^1.21'
32+
33+
- name: run checks
34+
run: go run mage check

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea
2+
.vscode
3+
build

README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# go-protoc-gen-grpc
2+
3+
go-protoc-gen-grpc is a distribution of the official gRPC protoc generation plugins from [grpc/grpc][1]
4+
(this is not to be confused with protoc-gen-grpc-go, the compiler for generating Go gRPC stubs, which also
5+
happens to be written in Go). It does not actually reimplement any functionality of gRPC in Go, instead compiling
6+
the original source code to WebAssembly, and executing with the pure Go Wasm runtime [wazero][2].
7+
This means that `go install` or `go run` can be used to execute it, with no need to rely on external
8+
package managers such as Homebrew, on any platform that Go supports.
9+
10+
## Installation
11+
12+
Install the plugin you want using `go install`.
13+
14+
```bash
15+
$ go install github.com/wasilibs/go-protoc-gen-grpc/cmd/protoc-gen-grpc_python@latest
16+
```
17+
18+
As long as `$GOPATH/bin`, e.g. `~/go/bin` is on the `PATH`, you can use it with protoc as normal.
19+
20+
```bash
21+
$ protoc --grpc_python_out=out/python -Iprotos protos/helloworld.proto
22+
```
23+
24+
Note that the filenames of binaries in this repository match protoc conventions so `--plugin` is not needed.
25+
26+
For [buf][3] users, it can be convenient to use `go run` in `buf.gen.yaml`.
27+
28+
```yaml
29+
version: v1
30+
plugins:
31+
- plugin: grpc_python
32+
out: out/python
33+
path: ["go", "run", "github.com/wasilibs/go-protoc-gen-grpc/cmd/protoc-gen-grpc_python@latest"]
34+
```
35+
36+
If also using [go-protoc][4] for `protoc_path` when generating the non-gRPC protobuf stubs, and invoking
37+
`buf` with `go run`, it is possible to have full protobuf/gRPC generation with no installation of tools,
38+
besides Go itself, on any platform that Go supports. The above examples use `@latest`, but it is
39+
recommended to specify a version, in which case all of the developers on your codebase will use the
40+
same version of the tool with no special steps.
41+
42+
[1]: https://github.com/grpc/grpc
43+
[2]: https://wazero.io/
44+
[3]: https://buf.build/
45+
[4]: https://github.com/wasilibs/go-protoc

buildtools/wasm/Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM ghcr.io/wasilibs/wasix-sdk:sha-fc94d60
2+
3+
RUN apt-get update && apt-get install -y binaryen git patch
4+
5+
RUN git clone --recursive https://github.com/grpc/grpc.git --branch v1.60.0 /workspace
6+
7+
ENV CXXFLAGS "${CXXFLAGS} -O3 -pthread -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_PROCESS_CLOCKS"
8+
ENV LDFLAGS $LDFLAGS -lwasi-emulated-process-clocks -lwasi-emulated-mman -Wl,--max-memory=4294967296
9+
10+
WORKDIR /workspace
11+
RUN cmake -S . -B build
12+
RUN cmake --build build --target plugins
13+
14+
RUN for f in build/*_plugin; do wasm-opt -o "$f".wasm --low-memory-unused --flatten --rereloop --converge -O3 "$f"; done
15+
16+
CMD ["bash", "-c", "cp build/*_plugin.wasm /out/"]

cmd/protoc-gen-grpc_cpp/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_cpp", wasm.GRPCCPPPlugin)
10+
}

cmd/protoc-gen-grpc_csharp/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_csharp", wasm.GRPCCSharpPlugin)
10+
}

cmd/protoc-gen-grpc_node/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_node", wasm.GRPCNodePlugin)
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_objective_c", wasm.GRPCObjectiveCPlugin)
10+
}

cmd/protoc-gen-grpc_php/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_php", wasm.GRPCPHPPlugin)
10+
}

cmd/protoc-gen-grpc_python/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_python", wasm.GRPCPythonPlugin)
10+
}

cmd/protoc-gen-grpc_ruby/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/wasilibs/go-protoc-gen-grpc/internal/runner"
5+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasm"
6+
)
7+
8+
func main() {
9+
runner.Run("protoc-gen-grpc_ruby", wasm.GRPCRubyPlugin)
10+
}

go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module github.com/wasilibs/go-protoc-gen-grpc
2+
3+
go 1.19
4+
5+
require github.com/wasilibs/wazerox v0.0.0-20231215071156-a88739a1af2a

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/wasilibs/wazerox v0.0.0-20231215071156-a88739a1af2a h1:qzlH+wVfxU42OCFyJf4n+9K02Uceg1mf+e9wXpa+DLA=
2+
github.com/wasilibs/wazerox v0.0.0-20231215071156-a88739a1af2a/go.mod h1:IQNVyA4d1hWIe23mlMMuqXjyWMdndgSlNx6FqBkwPsM=

go.work

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
go 1.19
2+
3+
use (
4+
.
5+
./mage
6+
./magefiles
7+
)

go.work.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/wasilibs/wazerox v0.0.0-20231215071156-a88739a1af2a h1:qzlH+wVfxU42OCFyJf4n+9K02Uceg1mf+e9wXpa+DLA=
2+
github.com/wasilibs/wazerox v0.0.0-20231215071156-a88739a1af2a/go.mod h1:IQNVyA4d1hWIe23mlMMuqXjyWMdndgSlNx6FqBkwPsM=

internal/runner/runner.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package runner
2+
3+
import (
4+
"context"
5+
"crypto/rand"
6+
"io/fs"
7+
"log"
8+
"os"
9+
"strings"
10+
11+
"github.com/wasilibs/go-protoc-gen-grpc/internal/wasix_32v1"
12+
wazero "github.com/wasilibs/wazerox"
13+
"github.com/wasilibs/wazerox/api"
14+
"github.com/wasilibs/wazerox/experimental"
15+
"github.com/wasilibs/wazerox/experimental/sys"
16+
"github.com/wasilibs/wazerox/experimental/sysfs"
17+
"github.com/wasilibs/wazerox/imports/wasi_snapshot_preview1"
18+
wzsys "github.com/wasilibs/wazerox/sys"
19+
)
20+
21+
func Run(name string, wasm []byte) {
22+
ctx := context.Background()
23+
24+
rt := wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfig().WithCoreFeatures(api.CoreFeaturesV2|experimental.CoreFeaturesThreads))
25+
26+
wasi_snapshot_preview1.MustInstantiate(ctx, rt)
27+
wasix_32v1.MustInstantiate(ctx, rt)
28+
29+
args := []string{name}
30+
args = append(args, os.Args[1:]...)
31+
32+
fsCfg := wazero.NewFSConfig().(sysfs.FSConfig).WithSysFSMount(cmdFS{cwd: sysfs.DirFS("."), root: sysfs.DirFS("/")}, "/")
33+
fsCfg = fsCfg.(sysfs.FSConfig).WithRawPaths()
34+
35+
cfg := wazero.NewModuleConfig().
36+
WithSysNanosleep().
37+
WithSysNanotime().
38+
WithSysWalltime().
39+
WithStderr(os.Stderr).
40+
WithStdout(os.Stdout).
41+
WithStdin(os.Stdin).
42+
WithRandSource(rand.Reader).
43+
WithArgs(args...).
44+
WithFSConfig(fsCfg)
45+
for _, env := range os.Environ() {
46+
k, v, _ := strings.Cut(env, "=")
47+
cfg = cfg.WithEnv(k, v)
48+
}
49+
50+
_, err := rt.InstantiateWithConfig(ctx, wasm, cfg)
51+
if err != nil {
52+
if sErr, ok := err.(*wzsys.ExitError); ok {
53+
os.Exit(int(sErr.ExitCode()))
54+
}
55+
log.Fatal(err)
56+
}
57+
}
58+
59+
type cmdFS struct {
60+
cwd sys.FS
61+
root sys.FS
62+
}
63+
64+
func (fs cmdFS) OpenFile(path string, flag sys.Oflag, perm fs.FileMode) (sys.File, sys.Errno) {
65+
return fs.fs(path).OpenFile(path, flag, perm)
66+
}
67+
68+
func (fs cmdFS) Lstat(path string) (wzsys.Stat_t, sys.Errno) {
69+
return fs.fs(path).Lstat(path)
70+
}
71+
72+
func (fs cmdFS) Stat(path string) (wzsys.Stat_t, sys.Errno) {
73+
return fs.fs(path).Stat(path)
74+
}
75+
76+
func (fs cmdFS) Mkdir(path string, perm fs.FileMode) sys.Errno {
77+
return fs.fs(path).Mkdir(path, perm)
78+
}
79+
80+
func (fs cmdFS) Chmod(path string, perm fs.FileMode) sys.Errno {
81+
return fs.fs(path).Chmod(path, perm)
82+
}
83+
84+
func (fs cmdFS) Rename(from string, to string) sys.Errno {
85+
return fs.fs(from).Rename(from, to)
86+
}
87+
88+
func (fs cmdFS) Rmdir(path string) sys.Errno {
89+
return fs.fs(path).Rmdir(path)
90+
}
91+
92+
func (fs cmdFS) Unlink(path string) sys.Errno {
93+
return fs.fs(path).Unlink(path)
94+
}
95+
96+
func (fs cmdFS) Link(oldPath string, newPath string) sys.Errno {
97+
return fs.fs(oldPath).Link(oldPath, newPath)
98+
}
99+
100+
func (fs cmdFS) Symlink(oldPath string, linkName string) sys.Errno {
101+
return fs.fs(oldPath).Symlink(oldPath, linkName)
102+
}
103+
104+
func (fs cmdFS) Readlink(path string) (string, sys.Errno) {
105+
return fs.fs(path).Readlink(path)
106+
}
107+
108+
func (fs cmdFS) Utimens(path string, atim int64, mtim int64) sys.Errno {
109+
return fs.fs(path).Utimens(path, atim, mtim)
110+
}
111+
112+
func (fs cmdFS) fs(path string) sys.FS {
113+
if len(path) > 0 && path[0] != '/' {
114+
return fs.cwd
115+
}
116+
return fs.root
117+
}

0 commit comments

Comments
 (0)