【问题标题】:Could one write a native Node.js extension in Go, as opposed to C++?可以在 Go 中编写原生 Node.js 扩展,而不是 C++ 吗?
【发布时间】:2014-01-10 18:28:28
【问题描述】:

这就是我的问题的全部内容,真的,但我认为回答这个问题很有趣。

【问题讨论】:

    标签: c++ node.js go node.js-addon


    【解决方案1】:

    node.js 的原生模块必须与 V8 进程深度交互,其中包含很多 v8 概念,例如 gc、javascript 上下文、...

    而且我认为 V8 没有公开兼容且稳定的 API 供其他语言与之交互。这就是为什么 node.js 原生插件应该使用 C++ 构建并始终导入 V8 C++ 标头。


    但是你可以通过用 C++ 包装 GO 代码来使用 GO 编写 node.js 原生插件:

    文件:module.go

    package main
    
    func Add(a, b int) int {
        return a + b
    }
    

    文件:module.c

    #include <node.h>
    #include <v8.h>
    
    using namespace v8;
    
    extern int go_add(int, int) __asm__ ("example.main.Add");
    
    void init(Handle<Object> exports) {
        // call go_add
    }
    
    NODE_MODULE(module, init)
    

    更多关于“如何从 C/C++ 调用 GO 函数”:

    Call Go functions from C


    编辑:

    请查看@jdi cmets 和链接:https://groups.google.com/forum/#!msg/golang-nuts/FzPbOwbTlPs/dAJVWQHx6m4J

    Quote: 它可能适用于简单的事情,比如 add (不产生垃圾或需要运行时),但据我所知,任何一个编译器都不支持(目前)。部分工作是针对 linux 完成的(参见 golang.org/issue/256),但还有许多悬而未决的问题(加载两个共享对象时会发生什么?等等)

    【讨论】:

    • 我认为 Go 需要成为入口点,即使你是从 C 调用它?据我了解,您无法为其他语言编写“扩展”。
    • 我现在正在安装 gccgo。你看过stackoverflow.com/a/15760986/813080的答案了吗,我看到他们可以用main条目编译一个c程序。
    • 我现在还没有。我想我只是没有在 golang-nuts 邮件列表上看到任何对此功能的确认。每当出现问题时,他们都会说您不能编写扩展来嵌入其他语言。不确定这种方法的局限性是什么。有兴趣知道。
    • 请参阅this answer from the golang-nuts mailing list。它尚未得到官方支持,并且功能非常有限。正如我所怀疑的,运行时不会被正确初始化,你必须做一些不产生垃圾或不需要运行时的事情。这似乎使它成为一个没有什么好处的选择。
    • @jdi 谢谢!我不知道这个限制,我认为你发布了这个问题的正确答案。
    【解决方案2】:

    只是为了重新发布这个作为答案而不是评论......

    我跟进了 golang-nuts 邮件列表,了解支持用 Go 为其他语言编写扩展。回复来源can be found here

    对于像 add (不生成 垃圾或需要运行时),但(尚)不支持 据我所知,无论是编译器。部分工作是为 linux 完成的 (请参阅golang.org/issue/256),但有许多未解决的问题 (当你加载两个共享对象时会发生什么?等等)

    所以说真的,用 Go 编写扩展似乎没有多大意义,然而,因为大多数语言功能都不可用,而且你已经在 C/C++ 领域添加包装器入口点。

    【讨论】:

      【解决方案3】:

      随着在 go 中添加对共享库的支持,这现在是可能的。

      calculator.go:

      // package name: calculator
      package main
      
      import "C"
      
      //export Sum
      func Sum(x, y float64) float64 {
          return x + y
      }
      
      func main() {
      }
      

      node-calculator.cc:

      #include "calculator.h"
      #include <node.h>
      
      namespace calc {
      
        using v8::FunctionCallbackInfo;
        using v8::Isolate;
        using v8::Local;
        using v8::Object;
        using v8::String;
        using v8::Value;
        using v8::Number;
        using v8::Exception;
      
        void add(const FunctionCallbackInfo<Value>& args) {
          Isolate* isolate = args.GetIsolate();
      
          // Check the number of arguments passed.
          if (args.Length() < 2) {
            // Throw an Error that is passed back to JavaScript
            isolate->ThrowException(Exception::TypeError(
                String::NewFromUtf8(isolate, "Wrong number of arguments")));
            return;
          }
      
          // Check the argument types
          if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
            isolate->ThrowException(Exception::TypeError(
                String::NewFromUtf8(isolate, "Wrong arguments")));
            return;
          }
      
          // Perform the operation
          Local<Number> num = Number::New(isolate, Sum(args[0]->NumberValue(), args[1]->NumberValue()));
      
          // Set the return value (using the passed in
          // FunctionCallbackInfo<Value>&)
          args.GetReturnValue().Set(num);
        }
      
        void init(Local<Object> exports) {
          NODE_SET_METHOD(exports, "add", add);
        }
      
        NODE_MODULE(calculator, init)
      }
      

      binding.gyp:

      {
        "targets": [
          {
            "target_name": "node-calculator",
            "sources": [
              "node-calculator.cc"
            ],
            "libraries": [
              "../calculator.a"
            ],
          },
        ],
      }
      

      test.js:

      const calculator = require('./build/Release/node-calculator');
      console.log('4+5=', calculator.add(4, 5));
      

      构建:

      go build -buildmode c-archive -o calculator.a calculator.go
      node-gyp configure
      node-gyp build
      

      输出:

      #> node test.js 
      4+5= 9
      

      【讨论】:

      • 我在使用 Go 1.9.3 时遇到错误:ld: warning: ignoring file ../calculator.a, file was built for archive which is not the architecture being linked (x86_64): ../calculator.a
      猜你喜欢
      • 2012-05-15
      • 1970-01-01
      • 2016-05-18
      • 2012-09-08
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多