简体   繁体   English

在没有 GCO 的情况下编译 go 库以在 alpine 上运行,libczmq 中出错

[英]Compiling go library without GCO to run on alpine, error in libczmq

When trying to run my binary on alpine , I got the error:尝试在alpine上运行我的二进制文件时,出现错误:

... binary not found

which typically happens when there's a problem with architecture, or as I found, glibc .这通常发生在架构出现问题时,或者我发现的glibc I searched and discovered that alpine instead uses muslc , an alternative C library.我搜索并发现alpine使用muslc ,一个替代的C库。 I then found this Installed Go binary not found in path on Alpine Linux Docker that teaches how to compile without CGO , which is the thing that permits loading C libraries from go:然后我发现在 Alpine Linux Docker 的路径中找不到这个Installed Go 二进制文件,它教了如何在没有CGO情况下进行编译,这是允许从 go 加载C库的东西:

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o [name of binary]

When I run this, I get:当我运行这个时,我得到:

go build gopkg.in/zeromq/goczmq.v4: no buildable Go source files in /home/lucas/Go/src/gopkg.in/zeromq/goczmq.v4

I suspect that it's because libczmq is just a wrapper for the C written libzmq .我怀疑这是因为libczmq只是C编写的libzmq的包装器。 In this case, how do I compile in a way that I can use libczmq ?在这种情况下,如何以可以使用libczmq的方式进行编译? Why exactly CGO must be disabled in alpine?为什么必须在高山中禁用CGO

What's exactly CGO ? CGO到底是什么? Shouldn't it use libc when available but muslc when not?它不应该在可用时使用libc在不可用时使用muslc吗? I'd like to know more about what's happening in the background.我想更多地了解背景中发生的事情。

Note: I'm compiling outside alpine, in ubuntu, is that a problem?注意:我在 alpine 之外编译,在 ubuntu 中,这是一个问题吗?

I know this question is about three years old now but there is nothing on the Internet about this and I was facing the exact same problem and it took about two days before I finally found a proper solution.我知道这个问题现在大约三年了,但互联网上没有关于这个的任何内容,我面临着完全相同的问题,我花了大约两天的时间才最终找到了合适的解决方案。

In short, I had a Go project that uses goczmq that I wanted to compile to a complete binary to put it into a FROM scratch Docker container (although in this case, an alpine container would work just as well).简而言之,我有一个使用goczmq的 Go 项目,我想将其编译为一个完整的二进制文件,然后将其放入一个FROM scratch Docker 容器(尽管在这种情况下,一个 alpine 容器也能正常工作)。 On the Internet, people now tend to tell you to set CGO_ENABLED=0 and everything will work fine, which is true.在互联网上,人们现在倾向于告诉你设置CGO_ENABLED=0一切都会正常工作,这是真的。 This tells Go to not use CGO, which allows you to use C libraries in your Go code, but needs those C libraries to be available on the system when you run your code.这告诉 Go 不要使用 CGO,这允许您在 Go 代码中使用 C 库,但在运行代码时需要这些 C 库在系统上可用。 As you have figured out, alpine does not have those C libraries (or, well, it has different ones in muslc instead of glibc ).正如您所发现的,alpine 没有那些 C 库(或者,它在muslc而不是glibc有不同的muslc )。

However, in our case, this is not helpful.但是,在我们的情况下,这没有帮助。 We want our Go code to be able to use existing C libraries because we use goczmq , which, as you have identified, is a Go wrapper for czmq which itself is a C wrapper for libzmq (which is written in C++, which makes our life even harder).我们希望我们的Go代码,以便能够使用现有的C库,因为我们使用goczmq ,正如你已经确定,是一个围棋包装为czmq这本身就是一个C包装libzmq (这是用C ++编写,这使我们的生活更难)。

I solved this problem by using a static binary.我通过使用静态二进制文件解决了这个问题。 Instead of linking to whatever C libraries are available on the target system (in this case muslc on alpine) dynamically, I compile my code AND all the libraries ( muslc , czmq and libzmq ) into one unified binary.我没有动态链接到目标系统上可用的任何 C 库(在这种情况下是muslc在 alpine 上),而是将我的代码和所有库( muslcczmqlibzmqlibzmq成一个统一的二进制文件。

I'm using Docker multi-stage builds based on alpine here but in theory you could also do this directly on your computer.我在这里使用基于 alpine 的Docker 多阶段构建,但理论上您也可以直接在您的计算机上执行此操作。

# stage 1: build the binary
# we are using alpine Linux with the latest version of golang
FROM golang:1.13-alpine as golang

# first install some dependencies
# (we are using the static versions for each for them as we want these libraries included statically, not dynamically!)
# czmq requires libzmq which in turn requires libsodium
# on alpine Linux we also need to install some specific tools to build C and C++ programs
# libsodium also requires libuuid, which is included in util-linux-dev
RUN apk add --no-cache libzmq-static czmq-dev libsodium-static build-base util-linux-dev

# now we do the magic command mentioned here
# https://stackoverflow.com/questions/34729748/installed-go-binary-not-found-in-path-on-alpine-linux-docker?noredirect=1&lq=1
# this fools the C compiler into thinking we have glibc installed while we are actually using musl
# since we are compiling statically, it makes sense to use musl as it is smaller
# (and it uses the more permissive MIT license if you want to distribute your binary in some form, but check your other libraries before!)
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

# create your project directory for the Go project
WORKDIR /go/src/github.com/<username>/<projectname>/

# copy in all your Go files, assuming these are in the same directory as your Dockerfile
COPY . .

# here is the first hack: we need to tell CGO to use g++ instead of gcc or else it will struggle with libzmq, which is written in C++
# creating and empty C++ file actually works for this
RUN touch ./dummy.cc

# now run go install (go build could also work here but your binary would end up in a different directory)
# the -ldflags will be passed along the CGO toolchain
# -extldflags is especially important here, it has two important flags that we need:
# -static tells the compiler to use static linking, which does the actual magic of putting everything into one binary
# -luuid is needed to correctly find the uuid library that czmq uses
RUN go install -a -ldflags '-linkmode external -w -s -extldflags "-static -luuid" ' .

# stage 2: here is your actual image that will later run on your Docker host
# you can also use alpine here if you so choose
FROM scratch

# now we just copy over the completed binary from the old builder image
COPY --from=golang /go/bin/<projectname> bin

# and we start our program
ENTRYPOINT ["./bin"]

Now this almost works!现在这几乎有效! The only thing left is to add this statement to the beginning of your main.go file or else CGO is confused about what you are doing:唯一剩下的就是将此语句添加到main.go文件的开头,否则 CGO 对您在做什么感到困惑:

import "C"

This is important even if you don't directly use CGO in your program.即使您不在程序中直接使用 CGO,这也很重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 “编译”go 项目作为 C 在 AIX 7.2 上共享 object 库导致无法运行的可执行文件 - "Compiling" go project as C shared object library on AIX 7.2 results in Executable that doesn't run 编译共享库时出错 - Error while compiling a shared library 自制库的C编译错误 - C compiling error with homemade library Go/Cgo:生成没有定义 Go 运行时函数的 static 库 - Go/Cgo: produce static library without definitions of Go runtime functions GCC:编译应用程序而不链接任何库 - GCC: compiling an application without linking any library 在 Docker Alpine 中编译 NSS 模块 - 致命错误:nss.h:没有这样的文件或目录 - Compiling NSS module in Docker Alpine - fatal error: nss.h: No such file or directory c编程 - 在Ubuntu中编译和在Alpine中编译之间的区别 - gcc - valgrind - c programming - difference between compiling in Ubuntu and compiling in Alpine - gcc - valgrind 使用C编译静态库时出现“未定义引用”错误 - “undefined reference” error compiling a static library in C 在Android上运行C代码而无需编译整个树 - Run C code on Android without compiling the entire tree 编译调用extern库的cython代码导致的链接错误 - linking error from compiling a cython code calling extern library
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM