Golang编写动态库实现回调函数

我们现在要做一个动态库,但是C++实在是比较难,于是就想能不能用更简单的golang来实现,golang也就是最近的版本才支持编译成动态库,在网上也没找到可用的案例,好在我们解决了这个问题,这边写个笔记造福大众。

main.go

package main
/*
#cgo CFLAGS: -I .
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void (*callback)(void *,int);
extern void c_callback (void *,int);
extern callback _cb;
*/
import "C"
import (
	"encoding/json"
	"unsafe"
)

func funccallback(gostring string,goint int) {
	var cmsg *C.char = C.CString(gostring)
	var ivalue C.int = C.int(len(gostring))
	defer C.free(unsafe.Pointer(cmsg))
	C.c_callback(unsafe.Pointer(cmsg),ivalue)
}

//export register_rsucallback
func register_rsucallback(p C.callback) {
	C._cb = p;
	return
}

//export test_callback
func test_callback() {
	funccallback("hello,this is func callback.",123)
}

func main() {
}

bridge.go

package main

/*
#include <stdio.h>

typedef void (*callback)(void *,int);

callback _cb;

void c_callback(void* p,int i)
{
	_cb(p,i);
}
*/
import "C"

这样写完直接调用以下命令即可生成main.dll文件和main.h文件

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

然后就是C语言的测试程序调用

main.c

#include <stdio.h>
#include "main.h"

void gocallback(void* s,int len) {
     printf("raw data: %s\n",s);
}

int main() {
    // 注册回调
    register_callback(gocallback);
    
    // 测试回调
    test_callback();
}

把C程序编译一下即可测试。

有时我们需要在别的包里调用这个回调函数,这时可以做一个工具

utils包callbackutils.go

package utils

type funVarType func(string,int)

var FunVar func(string,int)

func SetFuncAddr(a funVarType) {
	FunVar=a
}

func Funccallbackutil (gostring string,i int) {
	FunVar(gostring,i)
}

在main.go中可以写个init函数做个初始化

func init() {
	utils.SetFuncAddr(funccallback)
}

然后在写一个测试的函数导出

//export test_callbackutil
func test_callbackutil() {
	utils.Funccallbackutil("hello this is func callbackutil test",123)
}

最后在main.c中调用测试函数即可测试。