我们可以在Go中写一个本地的Node.js扩展,而不是C ++吗?

这就是我的问题,真的,但我认为这是一个有趣的事情来回答。

通过增加对共享库的支持,现在可以实现这一点。

file:calculator.go

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

file: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) } 

文件:test.cc

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

文件:binding.gyp

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

build立:

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

输出:

 #> node test.js 4+5= 9 

本地模块node.js必须深入与V8过程,其中包含了很多V8的概念,如gc,JavaScript上下文,…

而且我不认为V8已经公开了兼容和稳定的API来与其他语言进行交互。 这就是为什么Node.js本地插件应该用C ++构build,并且总是导入V8 C ++头文件的原因。


但是你可以使用GO来编写node.js本地插件,方法是用C ++包装GO代码:

file: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函数”:

从C调用Go函数


编辑:

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

Quote: 这可能是简单的事情,如添加(即不生成垃圾或要求运行时),但它不被任何编译器支持(据我所知)。 部分工作是为Linux完成的(请参阅golang.org/issue/256),但是有一些开放的问题(当您加载两个共享对象时会发生什么?等等)

只是重新发布这个答案,而不是评论…

我跟进了golang-nuts邮件列表,关于在Go中为其他语言编写扩展的支持。 响应的来源可以在这里find 。

就像我所知的那样,对于简单的东西比如add(不会产生垃圾或者需要运行时),它可能是可行的,但是任何一个编译器都不支持它。 部分工作是为Linux完成的(请参阅golang.org/issue/256 ),但是有一些开放的问题(当您加载两个共享对象时会发生什么?等等)

所以,在Go中写一个扩展名似乎没有多大意义,但是由于大多数语言function都不可用,并且您已经在C / C ++中,因此无论如何都要为入口点添加包装。