我用的是QuickJS的分叉项目:https://github.com/quickjs-ng/quickjs,关于这个项目,详见我之前的介绍:推荐:QuickJS的分叉:QuickJS-NG
我直接用CMake-gui编译此项目,编译不能用MSVC的编译器,我用的是LLVM的CLang编译器,如下图所示:
详见:https://github.com/quickjs-ng/quickjs/issues/1 编译成功之后,你会得到qjs.lib,具体怎么在项目中用这个库,我就不多介绍了,下面介绍一下怎么在C++项目中使用QuickJS。
初始化QuickJS运行时:
JSContext* rt = JS_NewRuntime();
if (!rt) return;
JSRuntime* ctx = JS_NewContext(rt);
if (!ctx) {
JS_FreeRuntime(rt);
return;
}
JSContext是JavaScript脚本的运行上下文对象,它负责管理脚本执行相关的所有状态及作用域,
JSRuntime是JavaScript脚本的运行环境,它负责内存分配和垃圾回收。
多个 JSContext 可以共享同一个 JSRuntime,但它们之间是隔离的,不能直接访问对方的状态
加载JS脚本:
std::ifstream file("main.js");
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
JSValue val = JS_Eval(ctx, content.c_str(),
content.size(),
mainFilePath,
JS_EVAL_TYPE_MODULE);
if (JS_IsException(val)) {
Console::Err(val);
return;
}
JS_FreeValue(ctx, val);
这段代码的主要作用就是读main.js文件内的js脚本,并把脚本字符串交给QuickJS运行。
注意qjs.lib中是不包含console.log和setInterval这样的API的。所以你的在脚本中最好也不要有用这些API,不然会报错。
注册一个模块:
我们知道JavaScript在浏览器或Node.js里运行时,都有一些全局对象,比如:window,console等。
接下来我们就为QuickJS注册一个app对象,让这个对象公开一个openUrlByDefaultBrowser方法,预期可以通过这样的JavaScript脚本来打开一个浏览器网页:
app.openUrlByDefaultBrowser("https://www.baidu.com");
这是给QuickJS注册app对象的C++代码
auto app = JS_NewObject(ctx);
auto func = JS_NewCFunction(ctx,
&openUrlByDefaultBrowser,
"openUrlByDefaultBrowser",
1);
JS_SetPropertyStr(ctx,
app,
"openUrlByDefaultBrowser",
func);
JSValue globalObj = JS_GetGlobalObject(ctx);
JS_SetPropertyStr(ctx, globalObj, "app", app);
JS_FreeValue(ctx, globalObj);
C++接收并处理JavaScript的请求:
上述代码中&openUrlByDefaultBrowser就是我们的打开浏览器的C++方法,代码如下:
JSValue openUrlByDefaultBrowser(JSContext* ctx,
JSValueConst thisVal,
int argc,
JSValueConst* argv)
{
const char* url = JS_ToCString(ctx, argv[0]);
HINSTANCE result = ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
JS_FreeCString(ctx, url);
return JS::MakeVal(0, JS_TAG_UNDEFINED);
}
这个方法的第一个参数是这个JS方法的运行上下文,第二个参数是执行当前方法的JS对象,第三个参数是这个JS方法的参数数量,第四个参数是这个JS方法的参数数组。
我们这个方法返回了一个undefined对象,如果你想返回别的类型,比如字符串,可以通过这样的方法:
return JS_NewString(ctx, "abc123");