Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jviksne committed Mar 7, 2020
0 parents commit 6b4ccc3
Show file tree
Hide file tree
Showing 32 changed files with 5,743 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe
*.test
*.prof
include
libv8
v8/build/.gclient
v8/build/.gclient_entries
26 changes: 26 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# The default build environment is Ubuntu 12.04 (very old!) which doesn't
# support c++11, which we need for our bindings. Instead, use the newer trusty
# (14.04) distribution.
sudo: required
dist: trusty

language: go
go:
- "1.10.x"
- "1.9"

# Indicate which versions of v8 to run the test suite against.
env:
- V8_VERSION=6.3.292.48.1
# Anything before 6.3 will break because of new ldflags definitions.
# - V8_VERSION=6.2.414.42.1
# - V8_VERSION=6.0.286.54.3

go_import_path: github.com/augustoroman/v8

# Need to download & compile v8 libraries before running the tests.
install: ./travis-install-linux.sh

notifications:
email:
on_failure: change
42 changes: 42 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
ARG V8_VERSION
ARG V8_SOURCE_IMAGE=augustoroman/v8-lib

# ------------ Import the v8 libraries --------------------------------------
# The v8 library & include files are taken from a pre-built docker image that
# is expected to be called v8-lib. You can build that locally using:
# docker build --build-arg V8_VERSION=6.7.77 --tag augustoroman/v8-lib:6.7.77 docker-v8-lib/
# or you can use a previously built image from:
# https://hub.docker.com/r/augustoroman/v8-lib/
#
# Once that is available, build this docker image using:
# docker build --build-arg V8_VERSION=6.7.77 -t v8-runjs .
# and then run the interactive js using:
# docker run -it --rm v8-runjs
FROM ${V8_SOURCE_IMAGE}:${V8_VERSION} as v8

# ------------ Build go v8 library and run tests ----------------------------
FROM golang as builder
# Copy the v8 code from the local disk, similar to:
# RUN go get github.com/augustoroman/v8 ||:
# but this allows using any local modifications.
ARG GO_V8_DIR=/go/src/github.com/augustoroman/v8/
ADD *.go *.h *.cc $GO_V8_DIR
ADD cmd $GO_V8_DIR/cmd/
ADD v8console $GO_V8_DIR/v8console/

# Copy the pre-compiled library & include files for the desired v8 version.
COPY --from=v8 /v8/lib $GO_V8_DIR/libv8/
COPY --from=v8 /v8/include $GO_V8_DIR/include/

# Install the go code and run tests.
WORKDIR $GO_V8_DIR
RUN go get ./...
RUN go test ./...

# ------------ Build the final container for v8-runjs -----------------------
# TODO(aroman) find a smaller container for the executable! For some reason,
# scratch, alpine, and busybox don't work. I wonder if it has something to do
# with cgo?
FROM ubuntu:16.04
COPY --from=builder /go/bin/v8-runjs /v8-runjs
CMD /v8-runjs
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 jviksne

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
152 changes: 152 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# V8 Bindings for Go [![Build Status](https://travis-ci.org/augustoroman/v8.svg?branch=master)](https://travis-ci.org/augustoroman/v8) [![Go Report Card](https://goreportcard.com/badge/github.com/augustoroman/v8)](https://goreportcard.com/report/github.com/augustoroman/v8) [![GoDoc](https://godoc.org/github.com/augustoroman/v8?status.svg)](https://godoc.org/github.com/augustoroman/v8)

The v8 bindings allow a user to execute javascript from within a go executable.

The bindings are tested to work with several recent v8 builds matching the
Chrome builds 54 - 60 (see the .travis.yml file for specific versions). For
example, Chrome 59 (dev branch) uses v8 5.9.211.4 when this was written.

Note that v8 releases match the Chrome release timeline:
Chrome 48 corresponds to v8 4.8.\*, Chrome 49 matches v8 4.9.\*. You can see
the table of current chrome and the associated v8 releases at:

http://omahaproxy.appspot.com/

# Using a pre-compiled v8

v8 is very slow to compile, it's a large project. If you want to go that route, there are building instructions below.

Fortunately, there's a project that pre-builds v8 for various platforms. It's packaged as a ruby gem called [libv8](https://rubygems.org/gems/libv8).

```bash
# Find the appropriate gem version for your OS,
# visit: https://rubygems.org/gems/libv8/versions

# Download the gem
# MacOS Sierra is darwin-16, for v8 6.3.292.48.1 it looks like:
curl https://rubygems.org/downloads/libv8-6.3.292.48.1-x86_64-darwin-16.gem > libv8.gem

# Extract the gem (it's a tarball)
tar -xf libv8.gem

# Extract the `data.tar.gz` within
cd libv8-6.3.292.48.1-x86_64-darwin-16
tar -xzf data.tar.gz

# Symlink the compiled libraries and includes
ln -s $(pwd)/data/vendor/v8/include $GOPATH/src/github.com/augustoroman/v8/include
ln -s $(pwd)/data/vendor/v8/out/x64.release $GOPATH/src/github.com/augustoroman/v8/libv8

# Run the tests to make sure everything works
cd $GOPATH/src/github.com/augustoroman/v8
go test
```

# Using docker (linux only)

For linux builds, you can use pre-built libraries or build your own.

## Pre-built versions

To use a pre-built library, select the desired v8 version from https://hub.docker.com/r/augustoroman/v8-lib/tags/ and then run:

```bash
# Select the v8 version to use:
export V8_VERSION=6.7.77
docker pull augustoroman/v8-lib:$V8_VERSION # Download the image, updating if necessary.
docker rm v8 ||: # Cleanup from before if necessary.
docker run --name v8 augustoroman/v8-lib:$V8_VERSION # Run the image to provide access to the files.
docker cp v8:/v8/include include/ # Copy the include files.
docker cp v8:/v8/lib libv8/ # Copy the library fiels.
```

## Build your own via docker

This takes a lot longer, but is still easy:

```bash
export V8_VERSION=6.7.77
docker build --build-arg V8_VERSION=$V8_VERSION --tag augustoroman/v8-lib:$V8_VERSION docker-v8-lib/
```

and then extract the files as above:

```bash
docker rm v8 ||: # Cleanup from before if necessary.
docker run --name v8 augustoroman/v8-lib:$V8_VERSION # Run the image to provide access to the files.
docker cp v8:/v8/include include/ # Copy the include files.
docker cp v8:/v8/lib libv8/ # Copy the library fiels.
```

# Building v8

## Prep

You need to build v8 statically and place it in a location cgo knows about. This requires special tooling and a build directory. Using the [official instructions](https://github.com/v8/v8/wiki/Building-from-Source) as a guide, the general steps of this process are:

1. `go get` the binding library (this library)
1. Create a v8 build directory
1. [Install depot tools](http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up)
1. Configure environment
1. Download v8
1. Build v8
1. Copy or symlink files to the go library path
1. Build the bindings

```
go get github.com/augustoroman/v8
export V8_GO=$GOPATH/src/github.com/augustoroman/v8
export V8_BUILD=$V8_GO/v8/build #or wherever you like
mkdir -p $V8_BUILD
cd $V8_BUILD
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH=$PATH:$V8_BUILD/depot_tools
fetch v8 #pull down v8 (this will take some time)
cd v8
git checkout 6.7.77
gclient sync
```

## Linux

```
./build/install-build-deps.sh #only needed once
gn gen out.gn/golib --args="strip_debug_info=true v8_use_external_startup_data=false v8_enable_i18n_support=false v8_enable_gdbjit=false v8_static_library=true symbol_level=0 v8_experimental_extra_library_files=[] v8_extra_library_files=[]"
ninja -C out.gn/golib
# go get some coffee
```

## OSX

```
gn gen out.gn/golib --args="is_official_build=true strip_debug_info=true v8_use_external_startup_data=false v8_enable_i18n_support=false v8_enable_gdbjit=false v8_static_library=true symbol_level=0 v8_experimental_extra_library_files=[] v8_extra_library_files=[]"
ninja -C out.gn/golib
# go get some coffee
```

## Symlinking

Now you can create symlinks so that cgo can associate the v8 binaries with the go library.

```
cd $V8_GO
./symlink.sh $V8_BUILD/v8
```

## Verifying

You should be done! Try running `go test`

# Reference

Also relevant is the v8 API release changes doc:

https://docs.google.com/document/d/1g8JFi8T_oAE_7uAri7Njtig7fKaPDfotU6huOa1alds/edit

# Credits

This work is based off of several existing libraries:

* https://github.com/fluxio/go-v8
* https://github.com/kingland/go-v8
* https://github.com/mattn/go-v8
79 changes: 79 additions & 0 deletions benchmarks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package v8

import "testing"

func BenchmarkGetValue(b *testing.B) {
ctx := NewIsolate().NewContext()

_, err := ctx.Eval(`var hello = "test"`, "bench.js")
if err != nil {
b.Fatal(err)
}

glob := ctx.Global()

b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, err := glob.Get("hello"); err != nil {
b.Fatal(err)
}
}
}

func BenchmarkGetNumberValue(b *testing.B) {
ctx := NewIsolate().NewContext()
val, err := ctx.Eval(`(157)`, "bench.js")
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for n := 0; n < b.N; n += 2 {
if res := val.Int64(); res != 157 {
b.Fatal("Wrong value: ", res)
}
if res := val.Float64(); res != 157 {
b.Fatal("Wrong value: ", res)
}
}
}

func BenchmarkContextCreate(b *testing.B) {
ctx := NewIsolate().NewContext()

b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, err := ctx.Create(map[string]interface{}{}); err != nil {
b.Fatal(err)
}
}
}

func BenchmarkEval(b *testing.B) {
iso := NewIsolate()
ctx := iso.NewContext()

script := `"hello"`

b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, err := ctx.Eval(script, "bench-eval.js"); err != nil {
b.Fatal(err)
}
}
}

func BenchmarkCallback(b *testing.B) {
ctx := NewIsolate().NewContext()
ctx.Global().Set("cb", ctx.Bind("cb", func(in CallbackArgs) (*Value, error) {
return nil, nil
}))

script := `cb()`

b.ResetTimer()
for n := 0; n < b.N; n++ {
if _, err := ctx.Eval(script, "bench-cb.js"); err != nil {
b.Fatal(err)
}
}
}
Loading

0 comments on commit 6b4ccc3

Please sign in to comment.