繁体   English   中英

如何将 Node.js 解释器嵌入到 C/C++ 中?

[英]How to embed Node.js interpreter into C/C++?

我想在我的 C/C++ 应用程序中使用 Node.js 脚本。 有人建议我从 v8、libev 和 libeio 开始; 但这意味着从头开始重写 Node.js。

那么,是否可以将 Node.js 嵌入到 C 或 C++ 中?

Node.JS fork JXcore 现在正式支持嵌入 Node.JS。 可从此链接获得嵌入文档。

您应该首先考虑将您的应用程序实现为 Node 的 C++ 模块是否足够,然后将主要部分粘合为 Node 脚本

否则,您可能希望“重新实现 Node” ,以核心代码为例,删除您不需要的部分(例如 HTTP 模块),然后将您的组件放入其中。 最不痛苦的方法是进行子树合并并删除构建系统,然后在构建脚本中添加前缀以指向它所在的目录。 然后,您可以停止构建某些部分。 然而,Node 的构建系统包含几个部分,这可能是一项非常困难的工作。

您还可以尝试使用默认加载的内容重新打包 Node 并更改可执行文件的名称。 但是,这只是采用我所描述的第一种方法的一种更复杂的方法,您只需在/usr/bin/安装一个脚本,该脚本将如下所示:

  #!/usr/bin/node
  var myAppMain = require('libmyApp');
  myAppMain.withConfig(filename,
  function(err, cnf) {
     if (err) throw err; // parser or file access error
     cnf.evalMe();
  });

您可以使用 JSlint 作为解析器,然后使用 grep 进行危险调用,然后使用eval(conf_script)或仅使用require(config.js) ,尽管您需要添加exports.someMethod = function (...) {...} . 但一般来说require()更安全,但是您可能希望为您的配置实现一个预处理器,它将替换exports.someMethod = function (...) {...}而不是您的函数,并将附加require('OnlyCallMySafeMethods')并拒绝任何对require('fs')或您可能害怕让某人使用的其他库的尝试。 这种安全性只是您可能希望拥有的一种可选的东西,这完全取决于您。 虽然我想你可能想用exports.someMethod = ....替换做一点,并在顶部添加一个require('myAppConfigLib) ,这样用户就可以使用你的API以及他们可能希望放入脚本的任何内容/配置!

更新:src/node.js第 66 行有一条非常有用的评论:

  // To allow people to extend Node in different ways, this hook allows
  // one to drop a file lib/_third_party_main.js into the build
  // directory which will be executed instead of Node's normal loading.

另请注意src/的内容在构建时被编译为字节码。

我已经建立了一些接近我认为你正在寻找的东西:

https://github.com/ZECTBynmo/tacnode

它是一个允许 node.js 静态链接到 C++ 应用程序的库。 它绝对没有经过打磨,但我已经用它来启动简单的节点脚本。

它可能是,V8是用C ++,node.js中可以在V8上运行,但除非你有一个非常好的理由,你为什么会到C ++,你可能是服务要好得多找到一个适当的C ++库,并直接实现所需的功能运行JavaScript在 C++ 中。 集成脚本语言和本机代码的任务通常并不简单。 例如V8 文档 Qt 在 c++ 和 javascript 之间提供了相当不错的集成,并且在脚本和代码之间来回移动对象仍然不是微不足道的。

我刚刚查看了为 Node.js 制作的js-git ,并且还依赖于其他一些 Node.js 模块。

然而,同一个开发人员编写了一个工具tim-task来包装一些常见的 Node.js 功能,最重要的是require ,并将一些 Node.js 模块打包在一起,使其不再依赖于 Node.js。 他用它来制作git-web-platform ,即 js-git 打包成一个可以在浏览器中使用的 JS 文件。 生成的打包文件如下所示 这可能也可以在纯 V8 中稍作修改后使用。

这可能对你有用。 但是请注意,这种方法将受到限制。

嵌入 node 有很多很好的理由,包括利用 npm 的能力。

不幸的是,JXCore 正在消亡。 这篇文章给出了一些替代方案。 http://www.goland.org/nodeapps/

官方文档有一个页面解释了如何将 Node.js 嵌入到 C++ 中 这从Node 12.x 开始就存在了

Node repo 中有一个完整的示例 为方便起见转载如下:


#include "node.h"
#include "uv.h"
#include <assert.h>

// Note: This file is being referred to from doc/api/embedding.md, and excerpts
// from it are included in the documentation. Try to keep these in sync.

using node::CommonEnvironmentSetup;
using node::Environment;
using node::MultiIsolatePlatform;
using v8::Context;
using v8::HandleScope;
using v8::Isolate;
using v8::Locker;
using v8::MaybeLocal;
using v8::V8;
using v8::Value;

static int RunNodeInstance(MultiIsolatePlatform* platform,
                           const std::vector<std::string>& args,
                           const std::vector<std::string>& exec_args);

int main(int argc, char** argv) {
  argv = uv_setup_args(argc, argv);
  std::vector<std::string> args(argv, argv + argc);
  std::vector<std::string> exec_args;
  std::vector<std::string> errors;
  int exit_code = node::InitializeNodeWithArgs(&args, &exec_args, &errors);
  for (const std::string& error : errors)
    fprintf(stderr, "%s: %s\n", args[0].c_str(), error.c_str());
  if (exit_code != 0) {
    return exit_code;
  }

  std::unique_ptr<MultiIsolatePlatform> platform =
      MultiIsolatePlatform::Create(4);
  V8::InitializePlatform(platform.get());
  V8::Initialize();

  int ret = RunNodeInstance(platform.get(), args, exec_args);

  V8::Dispose();
  V8::ShutdownPlatform();
  return ret;
}

int RunNodeInstance(MultiIsolatePlatform* platform,
                    const std::vector<std::string>& args,
                    const std::vector<std::string>& exec_args) {
  int exit_code = 0;

  std::vector<std::string> errors;
  std::unique_ptr<CommonEnvironmentSetup> setup =
      CommonEnvironmentSetup::Create(platform, &errors, args, exec_args);
  if (!setup) {
    for (const std::string& err : errors)
      fprintf(stderr, "%s: %s\n", args[0].c_str(), err.c_str());
    return 1;
  }

  Isolate* isolate = setup->isolate();
  Environment* env = setup->env();

  {
    Locker locker(isolate);
    Isolate::Scope isolate_scope(isolate);
    HandleScope handle_scope(isolate);
    Context::Scope context_scope(setup->context());

    MaybeLocal<Value> loadenv_ret = node::LoadEnvironment(
        env,
        "const publicRequire ="
        "  require('module').createRequire(process.cwd() + '/');"
        "globalThis.require = publicRequire;"
        "globalThis.embedVars = { nön_ascıı: '🏳️‍🌈' };"
        "require('vm').runInThisContext(process.argv[1]);");

    if (loadenv_ret.IsEmpty())  // There has been a JS exception.
      return 1;

    exit_code = node::SpinEventLoop(env).FromMaybe(1);

    node::Stop(env);
  }

  return exit_code;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM