从 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;
}