28

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

4

3 回答 3

17

随着在 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
于 2016-09-01T04:16:40.537 回答
11

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
}

文件:模块.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 函数”的更多信息:

从 C 调用 Go 函数


编辑:

请参阅@jdi 评论和链接:https ://groups.google.com/forum/#!msg/golang-nuts/FzPbOwbTlPs/dAJVWQHx6m4J

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

于 2013-12-22T11:27:58.500 回答
3

只是将其重新发布为答案而不是评论...

我跟进了 golang-nuts 邮件列表,了解支持用 Go 为其他语言编写扩展。可以在此处找到响应的来源。

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

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

于 2014-01-04T03:04:51.773 回答