Golang Go语言中使用了cgo的库该如何分发?

Golang Go语言中使用了cgo的库该如何分发?

有一个 Rust 写的库提供了 C ABI 的调用方式,我觉得这个库挺有趣的,就尝试给它写了一个 binding:

https://github.com/CoolSpring8/go-lolhtml
(存在的问题还比较多,无意推广,只是考虑到给出问题的具体情境更好理解)

问题来了,虽然在 go build 时指定 CGO_ENABLED=1 可以让 CC 参数指定的编译器编译工作目录下的 C/C++ 源文件,但是这个库需要调用 cargo 来编译。

我在开发时采用的方案是预先使用 cargo build --release 得到静态库或者动态库,然后在 Go 文件头部指定以下注释:

#cgo CFLAGS: -I${SRCDIR}/lol-html/c-api/include
#cgo LDFLAGS: -L${SRCDIR}/lol-html/c-api/target/release -llolhtml

但是到了 push 到 GitHub 后,尝试新建一个项目引用 import path 写 demo 时,才发现问题:

在启用 go mod 的情况下,go get 之后( go get 不会下载 git submodule 是另一个问题了,容易解决),它依赖的 Rust 库怎么办呢?

cd 到 $GOPATH/pkg/mod/github.com/... 去 make 之类的应该不可行,修改文件夹内容之后 module 的 sum 会改变,会无法使用。

总结起来:

cgo \

+ non-main package (不能通过发布预编译二进制的方案)\

+ no official library distribution (不能像大部分 binding 一样要求用户用包管理器安装对应包后,调用系统动态库,例如 ffmpeg 的 binding )\

+ go module (不能先 git clone 再 make 最后 go install 。所以看起来如果要用 go module 只能将依赖的 Rust 库事先安装为动态库了?)

看了网络上能搜索到的资料,都无法解决我的问题。感觉难点都撞在一起了,好纠结……


更多关于Golang Go语言中使用了cgo的库该如何分发?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

9 回复

为什么不能包含预编译 lib 的?

更多关于Golang Go语言中使用了cgo的库该如何分发?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


依赖 cgo 的 library 是这样的,因为也不像 npm 或者 python setup.py 可以运行自定义的安装脚本,所以会比较麻烦(以前「可以」,但是是个漏洞被修复了)

ldflags 和 cflags (或者对应的环境变量)这两个可以让 caller 在 go build 的时候转入
或者提供 pkg-config,然后 # cgo pkg-config xxx
include 的头文件,跟 go 文件放在一起,能稍微提高点实用性


谢谢,这个方式我之前没有想到,确实可以,但是似乎不是很“优雅”


感谢,可以传入参数就相对灵活一些了,或许可以写一个 shell 脚本


docker 与 cgo 的组合我所了解到的是 https://stackoverflow.com/questions/59741795/how-to-distribute-a-go-module-with-c-dependencies 提问者自己的回答,也算是一种方法吧,但我主要还是想让自己的库能够在启用 Go Modules 的情况下通过 go get 的方式来安装

编译成 .a 文件,然后用 #cgo LDFLAGS: foo.a 链接即可

我看下来基本上用 c-binding 的库都是自带各个 platform 的.a 文件,我自己写的也都是这么做的。同样是 go 调用 rust,你可以看看 Mozilla 的字节码联盟它们的 wasmtime-go

我就是自带预编译的.a,.so
然后还写了个 Makefile

基本上都是搞 lib 带过去,不关是不是 cgo

在Golang中使用cgo库后的分发问题,涉及到如何将包含C代码依赖的Go程序有效地分发给用户。以下是几种可行的分发方式:

  1. 编译成可执行文件

    • 将Go代码与cgo依赖的C代码一起编译成与操作系统和CPU架构一致的二进制可执行文件。
    • 优点:用户安装和运行方便,无需安装额外的软件或库。
    • 缺点:可执行文件较大,且更换操作系统或CPU架构时需要重新编译。
  2. 打包成容器

    • 将程序打包成镜像文件,用户可以通过容器运行时部署这个镜像文件。
    • 优点:支持跨操作系统和CPU架构,镜像文件体积相对较小,便于版本管理和更新。
    • 缺点:需要用户安装容器环境,相对不如可执行文件方便。
  3. 在线编译和下载

    • 将源代码上传到在线编译网站,用户下载生成的二进制可执行文件运行。
    • 优点:无需安装和配置编译环境,支持跨平台运行,可以对源代码进行保护和加密。
    • 缺点:依赖于在线编译网站,安全性和稳定性可能存在问题,且需要下载可执行文件。

开发者应根据项目的具体需求、目标用户群体以及分发环境的限制来选择合适的分发方式。

回到顶部