python与go的对接
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 文件
于是进入main包,执行go build -o main
,报错
这个错误是因为在 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 的错误,如下图
2、python平台也是Windows,需要设置 GOARCH 为64位平台,对方才能调用
3、这个部分是报错的原因,要先重新下载 mingw32 ,之前下载的环境是32位系统,参考,再修改环境变量
原来的环境变量如下,用作备份
最后可以成功build,此时就可以打包成.so
了
可参考https://blog.csdn.net/u012474395/article/details/120615372
打包
如果是一个单独的 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
指针,在调用时容易内存溢出?
在查阅资料后,将传参修改为*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 对应类型