V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
CoolSpring
V2EX  ›  Go 编程语言

使用了 cgo 的库该如何分发?

  •  
  •   CoolSpring · 2020-10-14 18:04:28 +08:00 · 2997 次点击
    这是一个创建于 1497 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个 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 库事先安装为动态库了?)

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

    第 1 条附言  ·  2020-10-16 00:51:41 +08:00
    感谢各位的建议,最终参考 https://github.com/bytecodealliance/wasmtime-go/ 在 repo 里放了预编译的静态库文件,之后的 go get 安装过程非常简便。

    另外,发现之前起的标题不太准确,应该是“调用了 Rust 库的 cgo binding 该如何作为 Go Module 分发”。
    8 条回复    2020-10-15 09:39:54 +08:00
    janxin
        1
    janxin  
       2020-10-14 18:26:02 +08:00
    为什么不能包含预编译 lib 的?
    timonwong
        2
    timonwong  
       2020-10-14 18:53:50 +08:00
    依赖 cgo 的 library 是这样的,因为也不像 npm 或者 python setup.py 可以运行自定义的安装脚本,所以会比较麻烦(以前「可以」,但是是个漏洞被修复了)

    ldflags 和 cflags (或者对应的环境变量)这两个可以让 caller 在 go build 的时候转入
    或者提供 pkg-config,然后 # cgo pkg-config xxx
    include 的头文件,跟 go 文件放在一起,能稍微提高点实用性
    wangyzj
        3
    wangyzj  
       2020-10-14 19:28:48 +08:00
    docker
    CoolSpring
        4
    CoolSpring  
    OP
       2020-10-14 21:38:50 +08:00
    @janxin
    谢谢,这个方式我之前没有想到,确实可以,但是似乎不是很“优雅”

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

    @wangyzj
    docker 与 cgo 的组合我所了解到的是 https://stackoverflow.com/questions/59741795/how-to-distribute-a-go-module-with-c-dependencies 提问者自己的回答,也算是一种方法吧,但我主要还是想让自己的库能够在启用 Go Modules 的情况下通过 go get 的方式来安装
    reus
        5
    reus  
       2020-10-14 23:32:17 +08:00
    编译成 .a 文件,然后用 #cgo LDFLAGS: foo.a 链接即可
    maoxs2
        6
    maoxs2  
       2020-10-15 00:42:19 +08:00 via Android   ❤️ 1
    我看下来基本上用 c-binding 的库都是自带各个 platform 的.a 文件,我自己写的也都是这么做的。同样是 go 调用 rust,你可以看看 Mozilla 的字节码联盟它们的 wasmtime-go
    missdeer
        7
    missdeer  
       2020-10-15 08:28:06 +08:00
    我就是自带预编译的.a,.so
    然后还写了个 Makefile
    buzailianxi
        8
    buzailianxi  
       2020-10-15 09:39:54 +08:00
    基本上都是搞 lib 带过去,不关是不是 cgo
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1336 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 17:54 · PVG 01:54 · LAX 09:54 · JFK 12:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.