ry/denoをビルドする (Node.jsの産みの親が作ったTypeScript+V8処理系)

[ry/deno: A secure TypeScript runtime on V8](https://github.com/ry/deno)はNode.jsの産みの親が、Node.jsでの反省点を元に新しい考え方に基づいて作ったTypeScript処理系です。TypeScript + V8で、Golangで書かれています。

[Node.js における設計ミス By Ryan Dahl - from scratch](http://yosuke-furukawa.hatenablog.com/entry/2018/06/07/080335)というブログで、Node.jsの産みの親が作ったプロダクトだったことと、Node.jsの設計上の問題について挙げられていて、その問題点というのがとても同感でずっと引っかかってた事ばかりなので、これはもうdenoやるしかないのではという気持ちになったのでとりあえずビルドしてみました。

## Golangのセットアップ

denoはGolangで書かれているのでGolangをセットアップしておいてください。

anyenv + goenvを使っている場合、goenvのバージョンが古かったりすると色々問題が出るので、僕の手元ではこのような作業が必要になりました。

```
$ anyenv update
$ anyenv uninstall goenv
$ anyenv install goenv
$ exec $SHELL -l
$ goenv install 1.10.2
$ go version
```

Golangのインストールはどのやり方でも大丈夫だと思いますが、GOPATHの設定はちゃんとしておきましょう。

```
$ go env GOPATH
/Path/to/go
```

`go env`コマンドはGoがどういう風にパスを認識しているかなどを確認できる便利なものです。

## 必要なものをインストールしておく

[deno/README.md](https://github.com/ry/deno/blob/master/README.md)にインストール手順が書かれていますが、[google/protobuf: Protocol Buffers - Google's data interchange format](https://github.com/google/protobuf)とGolangで必要となるライブラリを入れる必要があります。

```
$ brew install protobuf
$ go get -u github.com/golang/protobuf/protoc-gen-go
$ go get -u github.com/jteeuwen/go-bindata/...
```

Macの場合はHomeBrewでインストールするといいです。

## まずv8worker2をビルドしてみる

deno自体にはV8を叩く部分は実装されていません。同じ作者の[ry/v8worker2: Minimal golang binding to V8](https://github.com/ry/v8worker2)でV8とGolangの世界をつないでいます。denoのビルドに躓くとしたらおそらくv8worker2です。まずはv8worker2をビルドしてみましょう。

インストール方法は[v8worker2/README.md](https://github.com/ry/v8worker2/blob/master/README.md)に書かれているとおりです。こちらは、ビルドシステムがPythonを使っている都合上、Pythonが必要です。Python2系でも3系でも動くとは思いますが、動かなかったら適当に格闘してみてください（僕はPythonはよく知らない）。

```
go get github.com/ry/v8worker2
cd `go env GOPATH`/src/github.com/ry/v8worker2
./build.py # Will take ~30 minutes to compile.
go test
```

ただし、`./build.py`は処理系によってコンパイル難易度がまったく変わるものです。具体的にはV8をコンパイルする時に、macOSであれば、Xcodeが必須になります。Command Line Tools for Xcodeではビルドできません。

```
$ ./build.py
out_path None
Rebuilding V8

...

ERROR at //build/config/mac/mac_sdk.gni:55:5: Script returned non-zero exit code.
    exec_script("//build/mac/find_sdk.py", find_sdk_args, "list lines")
    ^----------
Current dir: .../go/src/github.com/ry/v8worker2/out/v8build/
Command: python -- .../go/src/github.com/ry/v8worker2/v8/build/mac/find_sdk.py --print_sdk_path 10.12
Returned 1.
stderr:

Traceback (most recent call last):
  File ".../go/src/github.com/ry/v8worker2/v8/build/mac/find_sdk.py", line 104, in <module>
    print main()
  File ".../go/src/github.com/ry/v8worker2/v8/build/mac/find_sdk.py", line 71, in main
    'to continue.')
__main__.SdkError: 'Install Xcode, launch it, accept the license agreement, and run `sudo xcode-select -s /path/to/Xcode.app` to continue.'

....
```

このようなエラーがでる時は、Xcodeがインストールされているか、そしてXcodeのlicense agreementをしたかチェックしてみてください。具体的には`xcodebuild`が走る必要があります。

1. AppStoreでXcodeをインストールする
2. CLIで `sudo xcodebuild -license` を叩いてlicense agreementを行う

ちなみに、

```
$ ./build.py 
out_path None
Rebuilding V8
Fetching dependencies.
Traceback (most recent call last):
  File "./build.py", line 149, in <module>
    main()
  File "./build.py", line 85, in main
    lib_fn = Rebuild()
  File "./build.py", line 97, in Rebuild
    EnsureDeps(v8_path)
  File "./build.py", line 146, in EnsureDeps
    env=env)
  File "/usr/local/Cellar/python@2/2.7.15/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 185, in check_call
    retcode = call(*popenargs, **kwargs)
  File "/usr/local/Cellar/python@2/2.7.15/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 172, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/usr/local/Cellar/python@2/2.7.15/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 394, in __init__
    errread, errwrite)
  File "/usr/local/Cellar/python@2/2.7.15/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1047, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory
```

このようなエラーが出る時は、git submoduleの問題です。`git submodule update --init`を行いましょう。

もし、`go get`を使わずに自前でcloneしてくる場合は、`git clone --recursive git@github.com:ry/v8worker2.git`のように`--recursive`をオプションに付けると楽です。

## denoをビルドする

denoは苦労する事は特にないでしょう。

```
$ go get -u github.com/ry/deno/...
$ cd `go env GOPATH`/src/github.com/ry/deno
$ make
$ ./deno testdata/001_hello.js
Hello World
```

これで、denoが動作するはずです。

もし以下の様なエラーが出る場合は

```
os.go:7:2: cannot find package "github.com/spf13/afero" in any of:
	/Users/erukiti/.anyenv/envs/goenv/versions/1.10.2/src/github.com/spf13/afero (from $GOROOT)
	/Users/erukiti/work/go/src/github.com/spf13/afero (from $GOPATH)
```

```
$ go get -u github.com/spf13/afero
```

で、必要なものをインストールしておきましょう。

## 感想

先日公開されたときにはてブでブックマークだけはしていたんですが、何かのtoy projectかなー、時間的に余裕が出来たらチェックしてみるかーと思ってたんですが、これ面白いですね。ソースコードも読みやすいし、設計も綺麗で、これこそが本当に欲しかったJavaScript処理系なんだなーということで、次の技術書典ではry/deno本を出そうと思います。