初次使用SpiderMonkey

初次使用SpiderMonkey,对它了解并不多,所以它是什么,请自行去搜索。本文只讲述我们用SpiderMonkey能做什么,我们可以用c/c++调用SpiderMonkey的接口,去执行JavaScript代码。这听起来是不是很酷,现在一起开始吧。

安装

我在linux下,安装很简单,去http://ftp.mozilla.org/pub/mozilla.org/js/下载源码包js-1.7.0.tar.gz,解压后在src/下执行make -f Makefile.ref即可,完成后会生成一个新的目录Linux_All_DBG.OBJ,其中包含静态链接库 libjs.a 和动态链接库 libjs.so 等。

详细请访问基于 C 语言的 JavaScript 引擎探索,本文也是参考此文写的,其中大部分代码来自此文。


SpiderMonkey的api这里不赘述,感兴趣的可以访问 SpiderMonkey官方网站。下面直接附上代码。

代码

.
├── fun.js    --JavaScript代码,为求简单,里面只有2个函数
├── lib        --Linux_All_DBG.OBJ目录的拷贝,里面的.o文件已被我删除,剩余2个.h文件,libjs.a,libjs.so
├── m         --本人比较懒,把gcc命令写到了这个文件,当shell执行
├── src        --src目录的拷贝
└── testjs.cc  --源代码

fun.js

function add(x, y) {
  return x + y;
}

function mul(x, y) {
  return x * y;
}
代码简单到不能在简单。

testjs.cc

定义了一个类JSCaller,将js文件加载封装了起来,只调用一次。js中函数可调用多次。

#include <string>

#include "jsapi.h"

/* The class of the global object. */
static JSClass global_class = {
    "global", 
    JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub, 
    JS_PropertyStub, 
    JS_PropertyStub, 
    JS_PropertyStub,
    JS_EnumerateStub, 
    JS_ResolveStub, 
    JS_ConvertStub, 
    JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};

class JSCaller {
 public:
  JSCaller();
  ~JSCaller();
  bool Build(const std::string& file);
  void Run();

 private:
  JSBool EvalScriptFromFile(JSContext *context, const char *file);

  JSRuntime *runtime_;
  JSContext *context_;
  JSObject *global_;
};

int main() {
  JSCaller caller;
  if (!caller.Build("fun.js")) { // 加载js文件,只调用一次
    return -1;
  }
  caller.Run();  // 执行js中的函数,里面执行了多次函数

  return 0;
}

JSCaller::JSCaller() {
  runtime_ = NULL;
  context_ = NULL;
  global_ = NULL;
}

JSCaller::~JSCaller() {
  if (context_ != NULL) {
    JS_DestroyContext(context_);
  }
  if (runtime_ != NULL) {
    JS_DestroyRuntime(runtime_);
  }
  JS_ShutDown();
}

/* The error reporter callback. */
void ReportError(JSContext *cx, const char *message, JSErrorReport *report) {
  if (report->filename == NULL) {
    fprintf(stderr, "%s\n", message);
  } else {
    fprintf(stderr, "%s:%d:%s\n", report->filename, report->lineno, message);
  }
}

bool JSCaller::Build(const std::string& file) {
  runtime_ = JS_NewRuntime(8L * 1024L * 1024L);
  if (runtime_ == NULL) {
    return false;
  }

  context_ = JS_NewContext(runtime_, 512 * 1024);
  if (context_ == NULL) {
    return false;
  }

  JS_SetOptions(context_, JSOPTION_VAROBJFIX);
  JS_SetErrorReporter(context_, ReportError);

  global_ = JS_NewObject(context_, &global_class, NULL, NULL);
  if (global_ == NULL) {
    return false;
  }

  if (!JS_InitStandardClasses(context_, global_)) {
    return false;
  }

  JSBool status = EvalScriptFromFile(context_, file.c_str());
  if (status == JS_FALSE){
    fprintf(stderr, "error while evaluate the script\n");
    return false;
  }

  return true;
}

JSBool JSCaller::EvalScriptFromFile(JSContext *context, const char *file) {
  JSScript *script;
  // JSString *jss;
  JSBool status;
  jsval value;
  
  //get the global object
  JSObject *global = JS_GetGlobalObject(context);
  
  //compile the script for further using
  script = JS_CompileFile(context, global, file);
  
  if (script == NULL) {
    return JS_FALSE;
  }
  
  //execute it once
  status = JS_ExecuteScript(context, global, script, &value);
  /*
  jss = JS_ValueToString(context, value);
  printf("eval script result is : %s\n", JS_GetStringBytes(jss));
  */

  //destory the script object
  JS_DestroyScript(context, script);

  return status;
}

void JSCaller::Run() {
  // 调用1000次add和mul函数
 for (int i = 0; i < 1000; ++i) {
    jsval res;
    JSObject *global = JS_GetGlobalObject(context_);
    jsval argv[2];

    // 构造函数的参数
    JS_NewNumberValue(context_, i, &res);
    argv[0] = res;
    JS_NewNumberValue(context_, i+10, &res);
    argv[1] = res;
    
    const char *p = "add";
    if (i % 2 == 0) {
      p = "mul";
    }
    // 调用函数
    JS_CallFunctionName(context_, global, p, 2, argv, &res);

    //convert the result to jsdouble
    jsdouble d;
    JS_ValueToNumber(context_, res, &d);
    printf("%s result = %f\n", p, d);
  }
}

编译命令

g++ -I./lib -I./src -DXP_UNIX -L./lib -ljs -g -Wall -o jstest testjs.cc

-I./lib,是因为lib/中也有2个.h文件,不然找不到会报很多错。


本打算使用静态库编译,使用-Wl,-Bstatic -ljs -Wl,-Bdynamic后总是报错,最后放弃了。

所以编译出的二进制执行前,别忘了export LD_LIBRARY_PATH=lib/。


猜你喜欢

转载自blog.csdn.net/hbuxiaoshe/article/details/44345497
今日推荐