V8 Embedding - C++ 函数暴露给 Javascript 环境
发表于 2018-08-05
作者: 灼灼团队
本文字数: 2538
阅读时长 ≈ 8.5 分钟

# 目标

上一篇我们把 C++ 环境中的对象暴露到 Javascript 环境中,这篇我们要将 C++ 环境中的 函数 暴露到 Javascript 环境中,写一个简单 console.log 函数传给 js 环境,使以下代码可运行:

// app.js
console.log('Hi, 老根!')
1
2

# 代码 & 说明

// expose-func.cc

#include <iostream>
#include <cstring>
#include <fstream>
#include <sstream>
#include <string>

#include "include/libplatform/libplatform.h"
#include "include/v8.h"

using namespace v8;
using std::cout;
using std::endl;
using std::ifstream;
using std::string;
using std::stringstream;
using std::strcpy;

// 定义一个函数,用来读取 js 代码
char* ReadSourceCodeFile(const char* path) {
  ifstream f(path);
  stringstream buffer;
  buffer << f.rdbuf();
  const string str = buffer.str();
  char* cstr = new char[str.length() + 1];
  strcpy(cstr, str.c_str());
  return cstr;
}

// 这个函数会被暴露给 js 执行环境
void ConsoleLog(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<String> str = Local<String>::Cast(args[0]);
  String::Utf8Value utf8(isolate, str);
  cout << *utf8 << endl;
  args.GetReturnValue().SetUndefined();
}

int main(int argc, char* argv[]) {
  // 初始化 V8
  V8::InitializeICUDefaultLocation(argv[0]);
  V8::InitializeExternalStartupData(argv[0]);
  std::unique_ptr<Platform> platform = platform::NewDefaultPlatform();
  V8::InitializePlatform(platform.get());
  V8::Initialize();

  // 创建 Isolate 实例
  Isolate::CreateParams create_params;
  create_params.array_buffer_allocator =
      ArrayBuffer::Allocator::NewDefaultAllocator();
  Isolate* isolate = Isolate::New(create_params);
  {
    Isolate::Scope isolate_scope(isolate);

    // 创建一个 HandleScope,用于管理 Handle 的生命周期
    HandleScope handle_scope(isolate);

    // 创建一个 v8 对象模板 `console_tpl`
    Local<ObjectTemplate> console_tpl = ObjectTemplate::New(isolate);

    // 将 `ConsoleLog` 函数设置为 `console_tpl` 的 `log` 方法
    console_tpl->Set(String::NewFromUtf8(isolate, "log"), FunctionTemplate::New(isolate, ConsoleLog));

    // 创建 v8 对象模板 `global_template`
    // 将上面的 `console_tpl` 设为其 `console` 属性
    Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
    global_template->Set(String::NewFromUtf8(isolate, "console"), console_tpl);

    // 创建 v8 Context,将 `global_template` 做为它的 global 对象模板
    Local<Context> context = Context::New(isolate, NULL, global_template);

    //  进入 or 使用 context
    Context::Scope context_scope(context);

    {

      // js 文件通过命令行第一个参数传递进来,读取 js 文件代码
      const char* js_code = ReadSourceCodeFile(argv[1]);
      Local<String> source = String::NewFromUtf8(isolate, js_code);

      // 编译
      Local<Script> script = Script::Compile(context, source).ToLocalChecked();

      // 执行
      Local<Value> result = script->Run(context).ToLocalChecked();

      delete js_code;
    }
  }

  // 释放 V8 相关资源
  isolate->Dispose();
  V8::Dispose();
  V8::ShutdownPlatform();
  delete create_params.array_buffer_allocator;
  return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

# 编译

v8 编译相关请查看 {% post_link v8/compile-v8 Javascript Engine V8 Embedding - 编译 %}

g++ -I. -Iinclude expose-func.cc -lv8_monolith -Lout.gn/x64.release.sample/obj/ -pthread -std=c++0x -o inode
1

# 执行

./inode app.js   # output: `Hi, 老根!`
1

# 说明

和上一篇同理,将函数暴露给 js 和 将变量暴露给 js 是类似的。都是将 C++ 对象绑定到 Context Global 对象上,通过这种方式,我们就可以扩展 js 的能力了。

# 相关链接

  • Getting started with embedding V8: https://v8.dev/docs/embed#advanced-guide
  • Node.js C++ Addons: https://nodejs.org/dist/latest-v10.x/docs/api/addons.html
联系我们
联系电话:17681177133
联系邮箱:admin@zhuo-zhuo.com
公司地址:合肥市高新区习友路2666号 (习友路和石莲南路交叉口西北角)二期304室
官网
博客
皖ICP备20009670号-2
合肥灼灼信息技术有限公司 | Copyright © 2020-present zhuo-zhuo.com