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

  • 43
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

今朝、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用にビルドされてサンドボックス内で動作しているらしい。
こんな感じの用途になら、現状でもなんとなく使えます。(やっぱまだ用途が微妙だな〜)

参考