golang中采用cgo调用c++的so
背景
基于arm平台的生鲜识别系统,采用了go语言做为边缘端业务逻辑语言,其中调用识别模型so库来实现推理(so调用jetson nano cuda)将返回结果进行业务处理。在生鲜场景已运用成熟,当向零食识别集成时,若采用单一模型,也就是在原有模型的基础上,增加零食数据训练出来的大模型,生鲜的识别将受影响,所以,诞生了生鲜与零食两个模型的想法。
技术实现
go调用c++的so,需要通过c来调用,网上有关于cgo的使用方法,介绍篇幅非常有限,特别是对so的调用。最难的是在于复杂类型的转换,golang与c++中的类型,哪怕是常见的int、char、指针等,因两种语言定义不同,为so的集成增添了难度,经过一段时间的摸索,终于将功能实现。
那么go中如何调用so库呢?C++写的libxxxx.so库,golang中集成时,需定义出so中函数的头文件,在go文件中引用,并描述so的名称,就可以调用so中的函数了。接下来,我们由简入深吧!
golang中直接调用c
// go的源代码中直接声明C代码,比较简单的应用情况 可以直接使用这种方法 C代码直接写在 go 代码的注释中 注释之后紧跟import "C" 通过C.xx来引用C的结构和函数
package main
/*
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int id;
}ctx;
ctx *createCtx(int id) {
ctx *obj = (ctx *)malloc(sizeof(ctx));
obj->id = id;
return obj;
}
*/
import "C"
import (
"fmt"
"sync"
)
func main() {
var ctx *C.ctx = C.createCtx(100)
fmt.Printf("id : %d\n", ctx.id)
}
参考:https://www.codercto.com/a/39274.html,其中也有直接调用c++的示例
golang中调用so库
- 定义头文件,描述so中的函数
#ifndef F1_INFERENCE_API_H
#define F1_INFERENCE_API_H
#ifdef __cplusplus
extern "C" {
#endif
char* get_version();
int process(const unsigned char *data, int length, int num, float *result);
#ifdef __cplusplus
}
#endif
#endif //F1_INFERENCE_API_H
- 将libxxxx.so放到指定的目录中
cp libxxxx.so ~/.local/lib/
- golang中的调用
- 编译go代码
export GODEBUG=cgocheck=0
export LD_LIBRARY_PATH=:/home/f1/.local/lib;
export LIBRARY_PATH=:/home/f1/.local/lib;
CGO_ENABLED=1 GOOS=linux go build main.go
golang与c++中类型转换
- c++中的long long类型
Golang 中采用C.longlong(t)来转换
- c++中的float数组
var scores [2]float32
scores[0] = 0.8
scores[1] = 0.9
// 调用:入参
C.test_float((*C.float)(unsafe.Pointer(&scores[0])))
- c++中的字符串
Golang 中对应的类型与赋值
var path *C.char
path = C.CString("/home/f1/ailog.log")
- c++中的字符数组
Golang 中对应的类型与赋值
var names [8]*C.char
names[0] = C.CString("苹果")
names[1] = C.CString("大白菜")
输入参数时需转换为**char类型
C.test_chararray((**C.char)(unsafe.Pointer(&sku[0])))
- c++中**char转golang切片[]string
//char** 转化成 []string
list := C.getStringArray()
var str []string
var pbuf []*C.char
header := (*reflect.SliceHeader)(unsafe.Pointer(&pbuf))
header.Cap = 3
header.Len = 3
header.Data = uintptr(unsafe.Pointer(list))
for _, i := range pbuf {
str = append(str, C.GoString(i))
}
fmt.Println(str)
//[]string 转化成 char**
box := []string{"xing", "jack", "john"}
var buf []*C.char
for i, _ := range box {
buf = append(buf, (*C.char)(unsafe.Pointer(C.CString(box[i]))))
}
box2 := (**C.char)(unsafe.Pointer(&buf[0]))
参考:https://www.zhihu.com/question/27168644