Edited at

go1.3でNative Client(NaCl)アプリをビルドする #golang

More than 5 years have passed since last update.

今朝、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)には対応していません。こちらは対応に向けての確固たる計画もないそうです。まぁ、成り立ちを考えれば難しいでしょうしね。


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についているサンドボックスを使ってなんとなく動かしてみます。


test.go

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」でも付けてエラー出力を無視するといい感じになります。

一応、サンドボックス内で動いていることを確認しておきましょう。


test2.go

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用にビルドされてサンドボックス内で動作しているらしい。

こんな感じの用途になら、現状でもなんとなく使えます。(やっぱまだ用途が微妙だな〜)


参考