Native Client(NaCl)をやってみる (4) - dlopen(dlfcn.h)を使う -
Native Clientのデモにはdlopenっていうのが入ってるのですが、これを単純にやってみる。っていってもこれをそのまま動かすんじゃなくて、作ったtest.cをlibtest.soにして、それをNative Clientから使う(恐らくはNative Client環境のコンパイラを使わないと動かせれないんだと思われる。検証してないけど)
test.h
#ifndef TEST_H
#define TEST_H
char* say();
#endif
test.c
#include "test.h"
char* say() {
char* s;
s = "abcdef";
return s;
}
でこれをlibtest.soにする。方法は後述参考
hoge.c (Native Clientのモジュール)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <dlfcn.h>
#include <pthread.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"
#include "test.h"
static PPB_Messaging* ppb_messaging_interface = NULL;
static PPB_Var* ppb_var_interface = NULL;
void *handle;
pthread_t t_id;
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 void* LoadLibrary() {
handle = dlopen("libtest.so", RTLD_LAZY);
return NULL;
}
static PP_Bool Instance_DidCreate(PP_Instance instance, uint32_t argc, const char* argn[], const char* argv[]) {
if (ppb_var_interface != NULL) {
if (pthread_create(&t_id, NULL, LoadLibrary, NULL)) {
printf("pthread_create failedn");
}
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;
}
static void HandleMessage(PP_Instance instance, struct PP_Var message) {
if (ppb_messaging_interface != NULL) {
if (ppb_var_interface != NULL) {
if (handle == NULL) {
return;
}
char* (*say)();
*(void **)(&say) = dlsym(handle, "say");
char* s = (*say)();
ppb_messaging_interface->PostMessage(instance, StrToVar((const char*)s));
}
}
}
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) {
printf("Interface: %sn", 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;
}
if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
static PPP_Messaging messaging_interface = { &HandleMessage };
return &messaging_interface;
}
return NULL;
}
PP_EXPORT void PPP_ShutdownModule() {
}
でNative Clientでdlopenを使用する際にメインスレッドでdlopenしてもNULLしか返ってこない模様。という事でpthreadで別スレッド内でdlopenする必要があるみたい
コンパイル
rm -fr glibc
python /opt/nacl/pepper_21/tools/oshelpers.py mkdir glibc
/opt/nacl/pepper_21/toolchain/linux_x86_glibc/bin/i686-nacl-gcc
-c test.c
-o glibc/libtest_x86_32.o
-m32
-O0
-g
-pthread
-Wno-long-long
-Wall
-Wswitch-enum
-Werror
-pedantic
-fPIC
-DTCNAME=glibc
/opt/nacl/pepper_21/toolchain/linux_x86_glibc/bin/i686-nacl-gcc
-Wl,-as-needed
-o glibc/libtest_x86_32.so glibc/libtest_x86_32.o
-m32
-shared
-g
-ldl
/opt/nacl/pepper_21/toolchain/linux_x86_glibc/bin/i686-nacl-gcc
-c hoge.c
-o glibc/hoge_x86_32.o
-m32
-O0
-pthread
-Wno-long-long
-Wall
-Wswitch-enum
-Werror
-DTCNAME=glibc
/opt/nacl/pepper_21/toolchain/linux_x86_glibc/bin/i686-nacl-gcc
-Wl,-as-needed
-o glibc/hoge_x86_32.nexe glibc/hoge_x86_32.o
-m32
-g
-ldl
-lppapi
python /opt/nacl/pepper_21/tools/create_nmf.py
-D /opt/nacl/pepper_21/toolchain/linux_x86_glibc/x86_64-nacl/bin/objdump
-o glibc/hoge.nmf
-L /opt/nacl/pepper_21/toolchain/linux_x86_glibc/x86_64-nacl/lib32
-L /opt/nacl/pepper_21/toolchain/linux_x86_glibc/x86_64-nacl/lib
glibc/hoge_x86_32.nexe glibc/libtest_x86_32.so
-t glibc
-s glibc
-n libtest_x86_32.so,libtest.so
glibcディレクトリにもろもろなファイルが生成される。んでNative Clientを使う際に.nmfなファイルもglibcに入るのでHTML側からはapplication/x-naclでそれを参照する
index.html
<html>
<body>
<div id="message"></div>
<script type="text/javascript">
(function(undefined) {
window.addEventListener("message", function(e) {
console.log(e);
var h2 = document.createElement("h2");
h2.innerText = e.data;
document.getElementById("message").appendChild(h2);
}, true);
})();
function send() {
document.getElementById("module").postMessage(null);
}
</script>
<button onclick="send()">send</button>
<embed name="nacl_module" id="module" width="0" height="0" src="/glibc/hoge.nmf" type="application/x-nacl" />
</body>
</html>