从 C++ 调用 v8 中的 JS 函数
Call JS functions in v8 from c++
我想做的是从 c++ 调用 JS/v8 中已经编译的函数。我正在为我正在编写的游戏引擎执行此操作,该引擎使用 V8 作为脚本后端。
这是为我的引擎格式化脚本的方式:
function init(){ //this gets called at the startup of the game
print("wambo");
}
var time = 0;
function tick(delta){ //this gets called every frame
time += delta;
print("pop");
}
我已经尝试通过此编译文档 https://v8docs.nodesource.com/node-16.13/df/d69/classv8_1_1_context.html 查找 v8::Local->Global 中的函数,该函数通过name,来自已编译的 JS,但我无法理解按键系统。
我已尝试通读 Calling a v8 javascript function from c++ with an argument,但这些示例对于 2022 年最新版本的 v8 似乎已经过时。
我确实将示例从其他答案移植到最新的 V8 版本 - 10.1.72
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libplatform/libplatform.h"
#include "v8.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char jsCode[] = "var foo = function(arg) {"
"if (Math.random() > 0.5) throw new Error('er');"
"return arg + ' with foo from JS';"
"}";
int main(int argc, char *argv[]) {
// Initialize V8.
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate *isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
// Create a context and load the JS code into V8
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, jsCode, v8::NewStringType::kNormal).ToLocalChecked();
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
v8::String::Utf8Value utf8(isolate, result);
// This is the result of the evaluation of the code (probably undefined)
printf("%s\n", *utf8);
// Take a reference to the created JS function and call it with a single string argument
v8::Local<v8::Value> foo_value = context->Global()->Get(context, v8::String::NewFromUtf8(isolate, "foo").ToLocalChecked()).ToLocalChecked();
if (foo_value->IsFunction()) {
// argument (string)
v8::Local<v8::Value> foo_arg = v8::String::NewFromUtf8(isolate, "arg from C++").ToLocalChecked();
{
// Method 1
v8::TryCatch trycatch(isolate);
v8::MaybeLocal<v8::Value> foo_ret = foo_value.As<v8::Object>()->CallAsFunction(context, context->Global(), 1, &foo_arg);
if (!foo_ret.IsEmpty()) {
v8::String::Utf8Value utf8Value(isolate, foo_ret.ToLocalChecked());
std::cout << "CallAsFunction result: " << *utf8Value << std::endl;
} else {
v8::String::Utf8Value utf8Value(isolate, trycatch.Message()->Get());
std::cout << "CallAsFunction didn't return a value, exception: " << *utf8Value << std::endl;
}
}
{
// Method 2
v8::TryCatch trycatch(isolate);
v8::Local<v8::Object> foo_object = foo_value.As<v8::Object>();
v8::MaybeLocal<v8::Value> foo_result = v8::Function::Cast(*foo_object)->Call(context, context->Global(), 1, &foo_arg);
if (!foo_result.IsEmpty()) {
std::cout << "Call result: " << *(v8::String::Utf8Value(isolate, foo_result.ToLocalChecked())) << std::endl;
} else {
v8::String::Utf8Value utf8Value(isolate, trycatch.Message()->Get());
std::cout << "CallAsFunction didn't return a value, exception: " << *utf8Value << std::endl;
}
}
} else {
std::cerr << "foo is not a function" << std::endl;
}
}
// Dispose the isolate and tear down V8.
isolate->Dispose();
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
return 0;
}
我想做的是从 c++ 调用 JS/v8 中已经编译的函数。我正在为我正在编写的游戏引擎执行此操作,该引擎使用 V8 作为脚本后端。
这是为我的引擎格式化脚本的方式:
function init(){ //this gets called at the startup of the game
print("wambo");
}
var time = 0;
function tick(delta){ //this gets called every frame
time += delta;
print("pop");
}
我已经尝试通过此编译文档 https://v8docs.nodesource.com/node-16.13/df/d69/classv8_1_1_context.html 查找 v8::Local
我已尝试通读 Calling a v8 javascript function from c++ with an argument,但这些示例对于 2022 年最新版本的 v8 似乎已经过时。
我确实将示例从其他答案移植到最新的 V8 版本 - 10.1.72
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libplatform/libplatform.h"
#include "v8.h"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char jsCode[] = "var foo = function(arg) {"
"if (Math.random() > 0.5) throw new Error('er');"
"return arg + ' with foo from JS';"
"}";
int main(int argc, char *argv[]) {
// Initialize V8.
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new Isolate and make it the current one.
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate *isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
// Create a context and load the JS code into V8
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, jsCode, v8::NewStringType::kNormal).ToLocalChecked();
v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();
v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();
v8::String::Utf8Value utf8(isolate, result);
// This is the result of the evaluation of the code (probably undefined)
printf("%s\n", *utf8);
// Take a reference to the created JS function and call it with a single string argument
v8::Local<v8::Value> foo_value = context->Global()->Get(context, v8::String::NewFromUtf8(isolate, "foo").ToLocalChecked()).ToLocalChecked();
if (foo_value->IsFunction()) {
// argument (string)
v8::Local<v8::Value> foo_arg = v8::String::NewFromUtf8(isolate, "arg from C++").ToLocalChecked();
{
// Method 1
v8::TryCatch trycatch(isolate);
v8::MaybeLocal<v8::Value> foo_ret = foo_value.As<v8::Object>()->CallAsFunction(context, context->Global(), 1, &foo_arg);
if (!foo_ret.IsEmpty()) {
v8::String::Utf8Value utf8Value(isolate, foo_ret.ToLocalChecked());
std::cout << "CallAsFunction result: " << *utf8Value << std::endl;
} else {
v8::String::Utf8Value utf8Value(isolate, trycatch.Message()->Get());
std::cout << "CallAsFunction didn't return a value, exception: " << *utf8Value << std::endl;
}
}
{
// Method 2
v8::TryCatch trycatch(isolate);
v8::Local<v8::Object> foo_object = foo_value.As<v8::Object>();
v8::MaybeLocal<v8::Value> foo_result = v8::Function::Cast(*foo_object)->Call(context, context->Global(), 1, &foo_arg);
if (!foo_result.IsEmpty()) {
std::cout << "Call result: " << *(v8::String::Utf8Value(isolate, foo_result.ToLocalChecked())) << std::endl;
} else {
v8::String::Utf8Value utf8Value(isolate, trycatch.Message()->Get());
std::cout << "CallAsFunction didn't return a value, exception: " << *utf8Value << std::endl;
}
}
} else {
std::cerr << "foo is not a function" << std::endl;
}
}
// Dispose the isolate and tear down V8.
isolate->Dispose();
v8::V8::Dispose();
v8::V8::ShutdownPlatform();
delete create_params.array_buffer_allocator;
return 0;
}