python与go的对接

在项目中遇到的问题,go写的程序需要被python调用,要将项目打包成.so文件

首先要确保go build能编译出可执行文件,再打包成.so文件,因为原理与go build是一样的

编译

用测试项目来记录解决过程

测试环境:windows64

源码目录结构:

---test
    |___Add___add.go
    |___main___main.go

给python调用需要在被调用的函数前加上

//export 函数名

并引入import "C"包,这是后面编译出现问题的主要原因

遇到的问题

进行的操作:

在test目录下直接go bulid,报错,提示必须要有 go 文件

go调用python函数 python调用go语言_环境变量

于是进入main包,执行go build -o main,报错

go调用python函数 python调用go语言_Windows_02

这个错误是因为在 32 位的 Windows 操作系统上使用了 64 位版本的 Go,或者是因为在 64 位的 Windows 操作系统上使用了不支持 64 位编译的 C 编译器。

于是修改环境变量

SET CGO_ENABLED=1   
SET GOARCH=amd64
SET CC=x86_64-w64-mingw32-gcc.exe

说明:

1、CGO_ENABLED 表示是否开启cgo,因为引入了“C”包,如果不开启会报 cgo 的错误,如下图

go调用python函数 python调用go语言_go调用python函数_03

2、python平台也是Windows,需要设置 GOARCH 为64位平台,对方才能调用

3、这个部分是报错的原因,要先重新下载 mingw32 ,之前下载的环境是32位系统,再修改环境变量

原来的环境变量如下,用作备份

go调用python函数 python调用go语言_python_04

 

最后可以成功build,此时就可以打包成.so

打包

如果是一个单独的 go 文件,只需要在文件中包含一个空的 main 函数,并在函数头部注释//export 函数名,函数名首字母大写即可供 python 调用

在终端输入

go build -buildmode=c-shared -o mylib.so ./main.go

即可产生mylib.so文件,python可以引用

第一个参数是打包后的共享库名字,第二个参数是文件路径位置,./表示当前路径

如果是需要打包项目,需要进入项目目录下,执行

go build -buildmode=c-shared -o mylib.so ./...

python调用

python调用的时候也遇到了一些问题

1、go 函数入参为[]byte类型,但是python经过处理后,传过来的内容与预期不同,python 那边也不知道什么问题,个人感觉可能是因为 python 的 bytes 类型是16 进制存储,而 go 的[]byte是10进制存储,导致互相转化的结果不一样

2、于是我修改 go 的传参为 string类型,在内部处理为[]byte,发现又报内存溢出错误,可能是由于 go 的字符串底层是一个结构体,包含指针,而 C 语言的字符串底层就是一个*char指针,在调用时容易内存溢出?

go调用python函数 python调用go语言_Windows_05

在查阅资料后,将传参修改为*C.char类型,同时 python 在调用时,进行一些处理,即可调用

python 的处理如下

# 限制函数传参的返回类型
lib.my_func.argtypes = [c_char_p]
lib.my_func.restype = c_char_p
# 字符串处理
teststr='012def'
test_byte = teststr.encode("utf-8")

go需要调用C.GoString()将*C.char转为go中的string类型

最后补充一个表, python,ctypes , c 对应类型

go调用python函数 python调用go语言_go调用python函数_06