GONACLI
相关连接
QQ交流群1:885267905
Gonacli 开发工具
Gonacli 的兼容支持
- Linux
- Mac OS
- Windows
NodeJS Addon 的兼容支持
- Linux / Mac OS / Windows
- NodeJS(12.0+)
- Npm(6.0+)
- Node-gyp(9.0+)
- Go(1.14+)
使用 go 方式安装 gonacli 工具
安装前需要确保系统配置好了 GOPATH 及最终编译保存到 bin 目录的相关环境变量
Linux Or Mac OS
# .bash_profile
export GOPATH="/Users/awen/go"
# 配置 bin 目录,使用 golang 方式安装是必须的
export PATH="$PATH:$GOPATH:$GOPATH/bin"
Windows
# 打开系统环境变量设置
GOPATH: C:\awen\go
# 配置 bin 目录,使用 golang 方式安装是必须的
PATH: %GOPATH%\bin
安装
$ GOPROXY=https://goproxy.cn/,direct && go install github.com/wenlng/gonacli@latest
#
$ gonacli version
Windows 环境编译
在 Windows 开发环境下需要安装 Go CGO 需要的 gcc/g++ 编译器,可以下载 "MinGW" 安装,配置好 MinGW/bin 的 PATH 环境变量即可,在命令行能够正常执行 gcc 。
$ gcc -v
Window 环境下还需要安装 NodeJS Addon 编译工具 node-gyp 依赖的 c/c++ 编译工具。
$ npm install --global --production windows-build-tools
gonacli 中的命令
1、generate
根据 goaddon 的配置生成对应 NodeJS Addon 扩展相关的 Napi、C/C++ 桥接代码
# 默认将读取当前目录下的 goaddon.json 配置文件
$ gonacli generate
# --config 参数指定配置文件
$ gonacli generate --config demoaddon.json
2、build
相当于 go build -buildmode=c-archive 命令,编译静态库
# 将 Go CGO 编译生成静态库
$ gonacli build
# --args 参数指定 go build 的参数
# --config 参数指定配置文件
$ gonacli build --args '-ldflags "-s -w"'
3、install
相当于 npm install 命令, 安装 NodeJS 需要的相关依赖
# --config 参数指定配置文件
$ gonacli install
4、msvc
该命令只针对 window 环境下的兼容处理,需要 dlltool.exe 或 lib.exe (二选一)。
1、"MinGW" 支持 "dlltool.exe" 工具。
2、"Microsoft Visual c++ Build tools" 或 "Visual Studio" 的 "lib.exe" 工具
# --vs 参数表示使用 VS 的 "lib.exe" 工具,默认是 MinGW 的 "dlltool.exe" 工具
# --32x 参数表示支持 32 位的系统,默认 64 位
# --config 参数指定配置文件
$ gonacli msvc
5、make
相当于 node-gyp configure && node-gyp build 命令,编译成最终的 NodeJS Addon 扩展
1、使用 make 命令请请确保系统已安装了 node-gyp 编译工具
2、使用 -npm-i 参数时请确保系统已安装了 NPM 包依赖管理工具
# 直接执行 node-gyp configure && node-gyp build 编译扩展
$ gonacli make
# --args 参数指定 node-gyp build 的参数,例如调试 --debug 参数
$ gonacli make --args '--debug'
使用 Golang 快速开发 NodeJS Addon 的 Demo
Tip:请确保相关命令能正常使用,该 Demo 是在 Linux / Macos 环境下进行。
# go
$ go version
# node
$ node -v
# npm
$ npm -v
# node-gyp
$ node-gyp -v
# gcc
$ gcc -v
1、新建配置文件
/goaddon.json
{
"name": "demoaddon",
"sources": [
"demoaddon.go"
],
"output": "./demoaddon/",
"exports": [
{
"name": "Hello",
"args": [
{
"name": "name",
"type": "string"
}
],
"returntype": "string",
"jscallname": "hello",
"jscallmode": "sync"
}
]
}
2、编写 Golang 代码
/demoaddon.go
package main
import "C"
// 注意://export xxxx 是必须的
//export Hello
func Hello(_name *C.char) s *C.char {
// 传入 string 类型,返回 string 类型
name := C.GoString(_name)
res := "hello"
if len(name) > 0 {
res += "," + name
}
return C.CString(res)
}
3、编译静态库
# 保存到 ./demoaddon/ 目录下
$ gonacli build
4、生成桥接的 Napi C/C++ 代码
# 生成保存到 ./demoaddon/ 目录下
$ gonacli generate --config ./goaddon.json
5、安装 NodeJS 相关依赖
# 保存到 ./demoaddon/ 目录下
$ gonacli install
6、编译 NodeJS Adddon
# 生成保存到 ./demoaddon/build 目录下
# 首次 make 需要加 --npm-i 参数
$ gonacli make --npm-i
7、编写 JS 测试文件
/test.js
const demoaddon = require('./demoaddon')
const name = "awen"
const res = demoaddon.hello(name)
console.log('>>> ', res)
$ node ./test.js
# >>> hello, awen
配置文件说明
{
"name": "demoaddon", // Nodejs Addon 扩展的名称
"sources": [ // go build 的文件列表,注意不能带有路径
"demoaddon.go"
],
"output": "./demoaddon/", // 最终输出目录路径
"exports": [ // 导出的接口,生成 Addon 的 Napi、C/C++ 代码
{
"name": "Hello", // 对应 Golang 的 "//export Hello" 接口名称,必须一致
"args": [ // 传递的参数列表,参数型必须按照下面的类型表保持一致
{ // 参数要细心严谨,往往是因为配置的类型与 Golang 入口的不一致而导致编译失败
"name": "name", // 参数名称,但不能与当前参数列表中某一项重复
"type": "string" // 参数类型
}
],
"returntype": "string", // 返回给 JavaScript 的类型,没有 callback 类型
"jscallname": "hello", // JavaScript 调用的名称
"jscallmode": "sync" // sync 为同步执行、async 为异步执行(async值必须在args参数中指明 callback 类型参数)
}
]
}
类型对照表
-------- 请严格按照类型对照表 -------
Type | Golang Args | Golang Return | JS / TS |
---|---|---|---|
int | int32 | C.int | number |
int32 | int32 | C.int | number |
int64 | int64 | C.longlong | number |
uint32 | uint32 | C.uint | number |
float | float32 | C.float | number |
double | float64 | C.double | number |
boolean | bool | bool | boolean |
string | *C.char | *C.char | string |
array | *C.char | *C.char | Array |
object | *C.char | *C.char | Object |
callback | *C.char | - | Function |
配置文件的 returntype 字段类型
returntype 字段没有 callback 类型
array 类型
当返回时存在多层时,在 returntype 中不推荐使用
1、array 类型在 Golang 接收是字符串类型,需要配合使用 []interface{} 和 json.Unmarshal
2、array 类型在 Golang 返回时是 *C.char 类型,配合使用 json.Marshal
3、array 类型在 JavaScript 传递时是数组类型,但在接收时目前只支持一层,在 Golang 返回多层请使用字符串方式返回再使用 JavaScrpt 的 JSON.parse
object 类型
当返回时存在多层时,在 returntype 中不推荐使用
1、object 类型在 Golang 接收是字符串 *C.char 类型,需要配合使用 [string]interface{} 和 json.Unmarshal
2、object 类型在 Golang 返回时是 *C.char 类型,配合使用 json.Marshal
3、object 类型在 JavaScript 传递时是对象类型,但在接收时目前只支持一层,在 Golang 返回多层请使用字符串方式返回再使用 JavaScrpt 的 JSON.parse
JavaScript 同步式调用
/goaddon.json
{
"name": "demoaddon",
"sources": [
"demoaddon.go"
],
"output": "./demoaddon/",
"exports": [
{
"name": "Hello",
"args": [
{
"name": "name",
"type": "string"
}
],
"returntype": "string",
"jscallname": "hello",
"jscallmode": "sync"
}
]
}
/demoaddon.go
package main
import "C"
//export Hello
func Hello(_name *C.char) s *C.char {
// 传入 string 类型,返回 string 类型
name := C.GoString(_name)
res := "hello"
ch := make(chan bool)
// 当使用协程时,由于 JS 使用同步式调用,JS 进程会发生阻塞等待返回
go func() {
// 耗时任务处理
time.Sleep(time.Duration(2) * time.Second)
if len(name) > 0 {
res += "," + name
}
ch <- true
}()
<-ch
return C.CString(res)
}
/test.js
const demoaddon = require('./demoaddon')
const name = "awen"
const res = demoaddon.hello(name)
console.log('>>> ', res)
JavaScript 异步式回调
/goaddon.json
{
"name": "demoaddon",
"sources": [
"demoaddon.go"
],
"output": "./demoaddon/",
"exports": [
{
"name": "Hello",
"args": [
{
"name": "name",
"type": "string"
},
{
"name": "cbs",
"type": "callback"
}
],
"returntype": "string",
"jscallname": "hello",
"jscallmode": "async"
}
]
}
/demoaddon.go
package main
import "C"
//export Hello
func Hello(_name *C.char, cbsFnName *C.char) s *C.char {
// 传入 string 类型,返回 string 类型
name := C.GoString(_name)
res := "hello"
ch := make(chan bool)
// 当使用协程时,由于 JS 使用异步式调用,JS 进程不会发生阻塞,当返回值时会 JS callback
go func() {
// 耗时任务处理
time.Sleep(time.Duration(2) * time.Second)
if len(name) > 0 {
res += "," + name
}
ch <- true
}()
<-ch
return C.CString(res)
}
/test.js
const demoaddon = require('./demoaddon')
const name = "awen"
demoaddon.hello(name, funciton(res){
console.log('>>> ', res)
})
发表评论 ( 0条 )
暂无 “评论” 相关数据