Go bindings for V8 that use purego to call a C ABI shim.
The V8 API is C++, so the Go package does not call V8 symbols directly. Instead it dynamically loads
libgov8.so, a small C-compatible shim in native/, and keeps the public API idiomatic Go.
This repository is being scaffolded from design.md. The current implementation provides the loading
and handle model plus isolates, contexts, eval, compiled scripts, values, object property helpers,
arrays, functions, callbacks, and JSON helpers. On linux/amd64 the loader prefers the packaged
native/prebuilt/linux-amd64/libgov8.so
binary so module users do not compile V8.
*.go: public Go API and purego loader.native/: C ABI shim that links against V8 plus packaged native binaries.deps/v8: V8 submodule target.deps/depot_tools: Chromium dependency tooling used to sync and build V8.docker/: isolated build image definitions for producing packaged binaries.
Linux amd64 is the first supported runtime target. Other platforms are isolated behind platform files so their library names and build details can be added without changing the public API.
Normal users should not need to build V8. The package loader checks, in order:
GOV8_LIBRARY, when set.native/prebuilt/linux-amd64/libgov8.sofrom the Go module checkout.- Common local development paths such as
./libgov8.soand./build/libgov8.so.
Maintainers can rebuild the packaged binary without installing Chromium tooling on the host:
./tools/build-prebuilt-linux-amd64.shThe Docker build initializes/syncs the deps/v8 and deps/depot_tools submodules inside the
container and writes:
native/prebuilt/linux-amd64/libgov8.sonative/prebuilt/linux-amd64/libgov8.so.sha256
Commit both files directly. Do not store the shared object as a Git LFS pointer if consumers should
receive it through go get.
package main
import (
"fmt"
v8 "github.com/Dorbmon/go-v8"
)
func main() {
iso, err := v8.NewIsolate()
if err != nil {
panic(err)
}
defer iso.Close()
ctx, err := iso.NewContext()
if err != nil {
panic(err)
}
defer ctx.Close()
value, err := ctx.Eval("({answer: 40 + 2}).answer")
if err != nil {
panic(err)
}
defer value.Close()
n, _ := value.Float64()
fmt.Println(n)
fnValue, err := ctx.Eval("function add(a, b) { return a + b } add")
if err != nil {
panic(err)
}
defer fnValue.Close()
fn, err := ctx.AsFunction(fnValue)
if err != nil {
panic(err)
}
sum, err := fn.Call(20, 22)
if err != nil {
panic(err)
}
defer sum.Close()
n, _ = sum.Float64()
fmt.Println(n)
fromGo, err := ctx.Function(func(_ *v8.Context, args []*v8.Value) (any, error) {
left, err := args[0].Float64()
if err != nil {
return nil, err
}
right, err := args[1].Float64()
if err != nil {
return nil, err
}
return left + right, nil
})
if err != nil {
panic(err)
}
defer fromGo.Close()
global, err := ctx.Global()
if err != nil {
panic(err)
}
defer global.Close()
if err := global.Set("fromGo", fromGo); err != nil {
panic(err)
}
callbackValue, err := ctx.Eval("fromGo(19, 23)")
if err != nil {
panic(err)
}
defer callbackValue.Close()
n, _ = callbackValue.Float64()
fmt.Println(n)
}