Native Client(NaCl)をやってみる

2012-07-15T00:00:00+09:00 C JavaScript Native Client

Native Clientを使ってC(又はC++)で書いたコードをChromeブラウザ上で動かしてみた

環境構築

https://developers.google.com/native-clientから辿ってSDKをダウンロード。んでその後、zipを展開したディレクトリをどっかに配置(今回は/opt/nacl)

んで.bashrc辺りにPATHを設定しておく。設定する場所はNaCL SDKのルートディレクトリ(naclsdkってコマンドがある所)。で.bashrcを読みなおした後に

naclsdk update

を実行する。するとpepper_20っていうのがダウンロードされてインストールされる。これChromeのバージョンによって変わると思われるのですが、Chromeのバージョンが20ならpepper_20でChromeが19だとpepper_19っていうように変わるんだと思われる。んまぁ今提供されているのはChrome-20.0なので。とりあえずはこれで環境は完了。あとChromiumでは出来ませんでしたので(なんでかは知らない。多分Developer Buildだからなのか

あとChromeでabout:flagsでNative Clientを動かせれるようにしておく

Makefileを作る

っていうか$NACL_SDK_ROOT/pepper_[d{2}]/examples/hello_world_newlibからMakefile取ってきた方が早いかも。とりあえずコピってちょっと修正

# Copyright (c) 2012 The Native Client Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

#
# GNU Make based build file.  For details on GNU Make see:
#   http://www.gnu.org/software/make/manual/make.html
#


#
# Get pepper directory for toolchain and includes.
#
# If NACL_SDK_ROOT is not set, then assume it can be found a two directories up,
# from the default example directory location.
#
THIS_MAKEFILE:=$(abspath $(lastword $(MAKEFILE_LIST)))
NACL_SDK_ROOT?=/opt/nacl/pepper_20


#
# Project Build flags
#
# Turns on warnings (-Wxxx), builds with zero optimization (-O0) and adds debug
# information (-g) for correctness and ease of debugging.
WARNINGS:=-Wno-long-long -Wall -Wswitch-enum -Werror -pedantic
CFLAGS:=-pthread -O0 -g $(WARNINGS)


#
# Compute path to compiler
#
OSNAME:=$(shell python $(NACL_SDK_ROOT)/tools/getos.py)
TC_PATH:=$(abspath $(NACL_SDK_ROOT)/toolchain/$(OSNAME)_x86_newlib)


# Alias for C compiler
CC:=$(TC_PATH)/bin/i686-nacl-gcc


#
# Disable DOS PATH warning when using Cygwin based tools Windows
#
CYGWIN ?= nodosfilewarning
export CYGWIN

# Default target is everything
all : x86_32.nexe x86_64.nexe

# Define compile and link rule for 32 bit (-m32) nexe
x86_32.nexe : hoge.c $(THIS_MAKE)
    $(CC) -o hoge_x86_32.nexe $< -m32 -O0 -g $(CFLAGS) -lppapi

# Define compile and link rule for 64 bit (-m64) nexe
x86_64.nexe : hoge.c $(THIS_MAKE)
    $(CC) -o hoge_x86_64.nexe $< -m64 -O0 -g $(CFLAGS) -lppapi

な感じで。あとはオプションとかちらほら変えるとか

hoge.c

#include <stdlib.h>
#include <string.h>

#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_module.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb.h"
#include "ppapi/c/ppb_instance.h"
#include "ppapi/c/ppb_messaging.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppp_messaging.h"

static PPB_Messaging* ppb_messaging_interface = NULL;
static PPB_Var* ppb_var_interface = NULL;

static struct PP_Var StrToVar(const char* str) {
    if (ppb_var_interface != NULL) {
        return ppb_var_interface->VarFromUtf8(str, strlen(str));
    }

    return PP_MakeUndefined();
}

static PP_Bool Instance_DidCreate(PP_Instance instance, uint32_t argc, const char* argn[], const char* argv[]) {
    if (ppb_var_interface != NULL) {
        ppb_messaging_interface->PostMessage(instance, StrToVar("hoge fuga foobar"));

        return PP_TRUE;
    }

    return PP_FALSE;
}

static void Instance_DidDestroy(PP_Instance instance) {
}

static void Instance_DidChangeView(PP_Instance instance, PP_Resource view_resource) {
}

static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {
}

static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, PP_Resource url_loader) {
    return PP_FALSE;
}

PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, PPB_GetInterface get_browser) {
    ppb_messaging_interface = (PPB_Messaging*)(get_browser(PPB_MESSAGING_INTERFACE));
    ppb_var_interface = (PPB_Var*)(get_browser(PPB_VAR_INTERFACE));

    return PP_OK;
}

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
    if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
        static PPP_Instance instance_interface = {
            &Instance_DidCreate,
            &Instance_DidDestroy,
            &Instance_DidChangeView,
            &Instance_DidChangeFocus,
            &Instance_HandleDocumentLoad
        };

        return &instance_interface;
    }

    return NULL;
}

PP_EXPORT void PPP_ShutdownModule() {
}

んまぁほぼまるコピペですけどww 今回は動かす事前提なので(ry

hoge.nmf

.nmfっていう定義ファイルを書かないといけないので

{
  "program": {
    "x86-32": { "url": "hoge_x86_32.nexe" }
  }
}

x86_64なのは省略してます。多分archtype自体がx86_32なので

んまぁ見ての通りJSONファイルで定義する。でここまでやったら、もうHTMLを書くだけです

index.html

<html>
  <body>
    <div id="message"></div>
    <script type="text/javascript">
(function(undefined) {
  window.addEventListener("message", function(e) {
    var h2 = document.createElement("h2");
    h2.innerText = e.data;

    document.getElementById("message").appendChild(h2);
  }, true);
})();
    </script>

    <embed name="nacl_module" id="module" width="0" height="0" src="/hoge.nmf" type="application/x-nacl" />
  </body>
</html>

あとはサーバー上において云々するのですが

plackup -MPlack::App::Directory -e "Plack::App::Directory->new(root => ".")->to_app"

plackup使ってさくっと。あとはChromeでindex.htmlな所にアクセスすると

っていう感じで。とりあえず使ってみようネタだったので微妙ですけど、今後ちょっと勉強する事の対象にしてがっつりやってみたい所だなとは思います

Native Client(NaCl)をやってみる (2) - NativeClient側でメッセージ受信 - Chrome Extension開発を勉強してみる (8) - ominibox -