今朝、golang 1.3がリリースされました。
このバージョンからPlan9などの新しい環境に対応しましたが、特にNative Client(NaCl)が気になりましたので、バージョンアップのついでに試してみました。
Native Client
Native Client、通称NaClはブラウザ上でx86ネイティブコードが実行出来る仕組みであって、JavaScriptの諸問題の一部を解消できると期待されています。バイナリはNaClのサンドボックスに閉じ込めて実行されるため、周りに影響を与えないという特徴もあります。
類似の技術にMozillaのasm.jsがありますが、asm.jsがJavaScriptを単純にしたサブセットで実行速度を改善しているのに対し、Native Clientはコンパイル済みのマジで本気なバイナリがゴリゴリ動くので、大変に萌え度が高いです。
とは言ったものの、go1.3ではNativeClientをブラウザで動かすためのPepperPluginAPIに対応していないため、普通にサンドボックス内でバイナリを動かすことしかできません。(Go1.4かそれ以降でPPAPIにも対応する予定)
また、go1.3で対応したのはx86/x64のバイトコードを用いたNaClのみで、LLVM版のPNaCl(Portable Native Client)には対応していません。こちらは対応に向けての確固たる計画もないそうです。まぁ、成り立ちを考えれば難しいでしょうしね。
- Google Native Client
go1.3で環境を作る
NaCl SDKをダウンロードする
go1.3だけでなく、NaCl SDKが必要になるので、ダウンロードします。
このページ(Download the Native Client SDK)中の「Download and install the SDK」から「nacl_sdk.zip」を落としてきて、適当にunzipして、「/opt」にmvします。
最後に、中に居る「naclsdk」のスクリプトを蹴ります。
$ unzip nacl_sdk.zip
$ mv nack_sdk /opt
$ cd /opt/nacl_sdk
$ ./nacksdk install
つぎに、必要なスクリプトをパスの通ったディレクトリへ移します。("pepper_35"の数字部分は、インストールしたnaclsdkのバージョンで変わるので要確認)
$ ln -nfs /opt/nacl_sdk/pepper_35/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
$ ln -nfs /opt/nacl_sdk/pepper_35/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
サポートスクリプトを準備する
go/misc/nacl以下にサポートスクリプト達が居ますので、これらをパスの通ったディレクトリへ移します。
$ ln -nfs $GOROOT/misc/nacl/go_nacl_amd64p32_exec $GOPATH/bin/go_nacl_amd64p32_exec
$ ln -nfs $GOROOT/misc/nacl/go_nacl_386_exec $GOPATH/bin/go_nacl_386_exec
環境をビルド&テスト
仕上げに、例えばx86のnaclなら386をサポートしたサポートスクリプトを叩いてから、nacl用go環境をビルド&テストします。
$ go_nacl_386_exec
$ cd $GOROOT/src
$ env GOARCH=amd64p32 ./nacltest.bash
NaClアプリをビルドしてみる
環境はできたので、NaClアプリをビルドします。
先に書いたとおり、go1.3の時点ではブラウザで動かすことはできませんので、Native ClientのSDKについているサンドボックスを使ってなんとなく動かしてみます。
package main
import (
"fmt"
)
func main() {
fmt.Println("hello")
}
$ env GOOS=nacl GOARCH=amd64p32 go build test.go
$ sel_ldr_x86_64 test
[28083,2572449600:13:50:19.491746] Native Client module will be loaded at base address 0x00004a0c00000000
runtime: nacl_exception_stack: error 38
runtime: nacl_exception_handler: error 38
runtime: nacl_exception_stack: error 38
runtime: nacl_exception_handler: error 38
runtime: nacl_exception_stack: error 38
runtime: nacl_exception_handler: error 38
runtime: nacl_exception_stack: error 38
runtime: nacl_exception_handler: error 38
hello
[28083,2572236544:13:50:20.140744] NaClRuntimeHostInterfaceReportExitStatus(0x7f9a9a0a9f50, 0x0)
nacl_exception_stackってのがたくさん出ていていますが、ふわっと検索した感じ、そういうものらしい。ウザければ「2>/dev/null」でも付けてエラー出力を無視するといい感じになります。
一応、サンドボックス内で動いていることを確認しておきましょう。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("test2.go")
if err != nil {
fmt.Println(err)
}
fmt.Println(f)
return
}
$ env GOOS=nacl GOARCH=amd64p32 go build test2.go
$ sel_ldr_x86_64 test2
open /home/umisama/main.go: No such file or directory
<nil>
予定通り、ファイルを開くことが出来ませんでした。
とりあえず満足したので、ここまで。
実用例
go playgroundでユーザが書いたコードは、NaCl用にビルドされてサンドボックス内で動作しているらしい。
こんな感じの用途になら、現状でもなんとなく使えます。(やっぱまだ用途が微妙だな〜)