Go构建遇到cgo动态库时解决方案

[复制链接]
发表于 2023-3-7 18:53:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
1. 问题


  • golang构建程序很简单,当遇到需要调用c库时,如通常使用 net,kafka, sqlite3 程序运行时就会调用当前服务器的 动态库,如果遇到没有库时,通常还需要 下载比如 alpine需要安装sqlite
    1. apk add --no-cache sqlite-libs sqlite-dev
    复制代码
  • 通常我们构建时使用CGO_ENABLED=1 就能在构建时将代码需要调用C库用动态连接的形势供代码调用
    1. CGO_ENABLED=1 go build -ldflags "-s -w" -o perception_node ./cmd/
    复制代码
  • 但是这里面会有个问题,如果将编译好的 二进制文件移植到其他服务器,但是服务器上面的动态库版本又和构建时的动态库版本不一样, 或者动态库的路径不一样。可能有想到,升级c库,或降低版本。但是一旦升级或降级C库,很可能导致服务器上原来的服务受影响。

2. 解决

如何解决:

  • 使用 golang 的 kafka 库:开发人员需要更改代码以切换使用的 kafka sdk。这可以作为替代方案。
  • 降低 golang:latest 的 glibc 版本:发行版通常修复 glibc 以编译其他工具链,替换 glibc 是不明智的。虽然有这样的工具yum downgrade glibc*可以帮助解决这个问题。
  • 更改为旧的 glibc 映像:同样,您无法避免一堆旧的 bash 脚本。
  • 静态链接 c 依赖项

综上所述,使用最新的镜像来编译,但是会依赖所有的静态链接,这样一编译完成后就不用担心c库兼容的问题, 如果使用 glibc,则它不是静态可链接的。
因为 glibc 依赖于支持不同提供程序的 libnss,所以它必须动态链接。

  • 所以这里替换glibc的唯一方法就是使用musl。librdkafka和 golang 包confluent-kafka-go都支持 musl 构建(构建时指定 –tags musl 即可) alpine 是基于 musl 的发行版,所以这里可以直接用 alpine Linux 构建。
  • 然后指定外部 ld 和-staticfor 标志,编译后的二进制文件将完全静态链接。编译过程如下。
    1. $  docker run -it -v $(pwd):/workspace  golang:1.18-alpine
    2. /go $ cd /workspace/
    3. /workspace $ sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && \
    4. >     apk add git openssh make build-base alpine-sdk
    5. fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
    6. fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
    7. (1/37) Installing fakeroot (1.25.3-r3)
    8. (2/37) Installing openssl (1.1.1l-r0)
    9. (3/37) Installing libattr (2.5.1-r0)
    10. (4/37) Installing attr (2.5.1-r0)
    11. (5/37) Installing libacl (2.2.53-r0)
    12. (6/37) Installing tar (1.34-r0)
    13. (7/37) Installing pkgconf (1.7.4-r0)
    14. ...
    15. $ export GOPROXY="https://goproxy.cn"
    16. /workspace $ go build -ldflags "-linkmode external -extldflags '-static'" -tags musl -o  perception_node ./cmd/
    17. /workspace $ ldd  perception_node
    18. /lib/ld-musl-x86_64.so.1: spex: Not a valid dynamic program
    复制代码
  • windows下使用如下指令
    1. $ docker run -it -v $(pwd):/workspace  golang:1.18-alpine
    2. /go $ cd /workspace/
    3. /workspace $ sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories
    4. $ apk add openssh make build-base alpine-sdk mingw-w64-gcc musl-dev gcc build-base
    5. fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/main/x86_64/APKINDEX.tar.gz
    6. fetch https://dl-cdn.alpinelinux.org/alpine/v3.14/community/x86_64/APKINDEX.tar.gz
    7. (1/37) Installing fakeroot (1.25.3-r3)
    8. (2/37) Installing openssl (1.1.1l-r0)
    9. (3/37) Installing libattr (2.5.1-r0)
    10. (4/37) Installing attr (2.5.1-r0)
    11. (5/37) Installing libacl (2.2.53-r0)
    12. (6/37) Installing tar (1.34-r0)
    13. (7/37) Installing pkgconf (1.7.4-r0)
    14. ...
    15. $ export GOPROXY="https://goproxy.cn"
    16. $ CGO_ENABLED=1 GOOS=windows CC=x86_64-w64-mingw32-gcc go build -ldflags "-linkmode external -extldflags '-static'"  -tags musl -o seduce_node_agent.exe main.go
    复制代码
参考

1.golang动态链接库问题
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表