golang中采用cgo调用c++的so

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

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值