node 调用 golang 开发动态链接库

853 阅读2分钟

背景

在开发electron项目中,很多依赖node 的方式效率比较低,为了提高效率需要Node C++ addon 插件 但是不会c++ 会点golang 于是自己尝试写个demo

技术方案

node 提供node-ffi调用动态链接库,因此golang程序需要最终编译成动态链接库

  • mac 环境下是.dylib文件
  • win环境是.dll文件
  • linux 环境下是.so文件

golang demo

直接上代码

// bridge.gopackage main// typedef void (*cb)(char* extra, char* data);// void callCb(cb callback, char* extra , char* arg) { // c的回调, go将通过这个函数回调c代码//    callback(extra,arg);// }import "C"

// gofun.gopackage main/*#cgo CFLAGS: -I .#include <unistd.h>#include <stdio.h>#include <string.h>#include <stdlib.h>typedef void (*cb)(char* extra, char* data);extern void callCb(cb callback, char* extra, char* arg);*/import "C" // C是一个虚包, 上面的注释是c代码, 可以在golang中加 `C.` 前缀访问, 具体参考上面给出的文档import "time"//export hellofunc hello(arg *C.char) *C.char { //name := gjson.Get(arg, "name") //return "hello" + name.String() return C.CString("hello peter:::" + C.GoString(arg))} // 通过export注解,把这个函数暴露到动态链接库里面//export helloPfunc helloP(arg *C.char, ccb C.cb, extra *C.char) *C.char { C.callCb(ccb, extra, C.CString("one")) time.Sleep(time.Second) C.callCb(ccb, extra, C.CString("two")) return C.CString("hello peter:::" + C.GoString(arg))}func main() { println("go main func")}

编译成动态链接库

我的操作系统是mac 

go build -o main.dylib -buildmode=c-shared main.go bridge.go

生成 main.dylib 文件

node部分

var ffi = require('ffi-napi');// 指定路径注册函数var libm = ffi.Library('main', {'helloP': [ 'string', [ 'string' ,ffi.Function("void",['string','string']),'string'] ]});console.log(libm.helloP("1111",function (a,b){console.log(a,b)},"222"))

到此demo 中能完整的演示 go语言生成动态链接库为node 提供扩展

总结:

go语言取代了c++作为node 扩展的可能性,使得node 的性能有了一定的提升,也降低了开发难度,go语言的上手难度比c++低很多。

不足之处:

1.数据类型转换问题,由于对c不了解  js和go直接的数据类型转换成了一个坑

         简易处理方案转换成json字符串调用的时候来解析成对象

2.复杂业务还是无法取代c++,比如带界面的扩展,截图一类的工具开发还是得qt做