【问题标题】:How to embed Node.js interpreter into C/C++?如何将 Node.js 解释器嵌入到 C/C++ 中?
【发布时间】:2011-04-02 18:50:33
【问题描述】:

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

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

【问题讨论】:

  • node.js 实际上是嵌入在 Web 服务器中的 V8。由于您的应用程序可能不是 Web 服务器,因此您可以将 V8(或任何其他 javascript 引擎)嵌入其中。
  • 从技术上讲,node.js 不仅仅做网络服务器。它可以完成大量不同的角色,但它对 HTTP 服务器(文件服务器、网络服务器等)非常有用。无论哪种情况,您都可以使用 V8 代替。
  • @MAK node.js 不是网络服务器。它集成了一个 Web 服务器模块,但它肯定不是一个 Web 服务器。在 C++ 应用程序中,node.js 带来了大量仅 v8 不可用的模块。

标签: c++ c node.js


【解决方案1】:

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

https://github.com/ZECTBynmo/tacnode

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

【讨论】:

  • 试过了,但构建脚本“vcbuild.bat”中的语法错误严重到不能花更多时间在上面。
【解决方案2】:

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

【讨论】:

  • 这是一个很好的建议,应该是 imo 接受的答案,正是 OP 所追求的。
  • 似乎在 2016 年结束生命
【解决方案3】:

可能是,V8 是用 C++ 编写的,node.js 可以在 V8 上运行,但除非你有一个非常充分的理由让你通过 C++ 运行 javascript,否则你可能会更好地找到适当的 C++ 库并直接在 C++ 中实现所需的功能。集成脚本语言和本机代码的任务通常不是微不足道的。例如。 V8 documentation。 Qt 在 c++ 和 javascript 之间提供了相当不错的集成,并且在脚本和代码之间来回移动对象仍然不是一件容易的事。

【讨论】:

【解决方案4】:

您应该首先考虑将应用程序实现为 Node 的 C++ 模块是否足够,然后将主要部分粘贴为 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.jsline 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/ 的内容正在构建时被编译为字节码。

【讨论】:

    【解决方案5】:

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

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

    这可能对您有用。但请注意,这种方法会受到限制。

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

        官方文档有一个页面解释如何how to embed Node.js into C++。自 Node 12.x 以来一直存在。

        有一个full example in the 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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-05-26
          • 1970-01-01
          • 2012-03-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-10
          • 1970-01-01
          相关资源
          最近更新 更多