Golang在 Docker 中交叉编译 Windows

前言: 前端时间把本地的 Golang 开发环境卸载了,如果编写代码的话就是启动一个 Golang 的 Docker 容器。这样做对于服务端开发本来也是没有问题的,但是有时候想要把程序放到 Windows 上面来执行,那就遇到麻烦了。因为 Docker 容器本质上是 Linux 环境,所以它直接编译的二进制可执行文件也是基于 Linux 的,直接是 Windows 上是无法运行的。不过幸好,Golang 在交叉编译这方面做得很好,我们只需要简单设置一下就可以了:CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build main.go
CGO_ENABLE=0 关闭 CGO。

GOOS 目标操作系统,通常就是 windows linux drawin

GOARCH 目标架构,通常就是 amd64,现在也有些是arm架构的,不过我也没有使用过。

注:我了解到有 Windows 容器这个概念,似乎是直接运行在 Windows 上的,不过我也没有仔细了解,毕竟技术栈还是基于 Linux 生态的。

这样做通常就能解决问题了,但是如果我们引入了第三方库,那么它就可能不行了。这里就和 CGO_ENABLE 这个选项有关了。前段时间在写那个 HTTP 代理的 demo,之后我引入了 sqlite3 这个库,用于记录访问数据。然后再次交叉编译之后就遇到问题了,我们来看一下这个问题。

编译

Windows 执行

执行的话,它直接就报错了,并且也说了原因是因为 CGO_ENABLED=0,同时也指出了是 go-sqlite3 这个库导致的。

Linux执行

这里尝试在 Linux 执行一下,这样做也没有意义,不过这个报错很有趣的。它提示是没有文件或者目录,但是实际上是可执行文件无法解析导致的。所以以后遇到类似的问题,就不需要去想为什么文件不存在了,它就是报这个错误,并不是文件不存在。

那么该怎么解决呢?最方便快捷的方式就是重新在本地安装一个 Golang 的开发环境。 没开玩笑,因为这样确实是最快的,而且节省时间。如果你有时间和兴趣,那就来看接下来的部分吧。

什么是交叉编译?

所谓编译就是把代码变成二进制可执行文件的过程。代码就是一段 Unicode 字符,它是肯定可以跨平台的,但是最终运行的并不是它(最终运行的是代码的编译产物)。我们平时写完一个小程序,直接就点击运行了。但是这里的代码其实是不能直接运行的(编译型语言),它内部还是要进行一个编译的过程,把代码转成目标平台的二进制可执行文件。这个二进制可执行文件是和操作系统和目标架构绑定的,所以你换一个操作系统或者架构它就不能运行了。但是,有时候我们需要在某个架构的某个操作系统上,为特定架构和指定操作系统的另一个平台编译程序,这就是交叉编译。

那么我们这里遇到的问题就是我需要在 Linux 下交叉编译可以在 Windows 下可以运行的二进制可执行文件了。交叉编译一般需要交叉编译工具链,这个其实还是比较复杂的。所以我们就要采取一些简单的方式了------站在巨人的肩膀上。已经有人做了相关的工作了,我们直接采取拿来主义就好了。

交叉编译的 Docker 镜像

这是在 Github 上面找到的一个项目,因为上面说的这种需求还是挺常见的,所以已经有人做了相关的工作了,它是将交叉编译的相关工具链制作成了 Docker 镜像。

Docker image for building Go binaries for Windows with MinGW-w64 toolchain based on official Go Docker image.

The repository provides simple cross-compilation environment for windows 32 and 64bit builds.

Docker镜像,用于使用基于官方Go Docker镜像的 MinGW-w64 工具链为Windows构建Go二进制文件。

这个仓库提供了简单的 win32 和 win64 构建的跨平台编译环境。

注:虽然我也了解 Linux 上用 gcc/clang,windows 上用 mingw。不过我对于它们的了解也仅限于此了,以前也遇到过有些软件在 windows 上需要安装 mingw 的问题,不过也没有深入去了解过,因为现在使用的语言像是 Go、Python 开发 Web 服务通常也接触不到这些东西。

Docker image for building Go binaries with MinGW toolchain

拉取镜像
docker pull x1unix/go-mingw:latest # or "1.17" for specific Go version

在容器内编译

sh 复制代码
docker run --rm -it -v /YourPackageSrc:/go/work \
    -w /go/work \
    x1unix/go-mingw go build .

它的用法很简单,启动一个交互式容器,然后把本地项目挂载到容器内的目录中,直接编译就行了(默认是64位的,也可以编译32位的,不过我也没有这个需求,就没有尝试)。

解决问题

好了,那么我们用它来解决自己遇到的问题吧。

看这个输出,我感觉似乎引入了一些多余的库,而且最后生成的文件也是大了一圈:

程序启动正常:


PS:

这里用的这个 github 的项目简单易用,对于这种简单的需求,直接拉取镜像然后编译就行了。我在 Github 上面搜索的时候,还发现了一个更加强大的项目:vxbuild-cross,看描述它支持 Windows 和 MacOS,不过因为我没有 MacOS 的设备,所以我就没有尝试。不过还是把它记录在这里了,也许有人会需要这个东西呢。

相关推荐
奋斗羊羊21 小时前
rocketmq 及依赖环境编译安装过程记录(windows)
windows·rocketmq
为什么不问问神奇的海螺呢丶1 天前
n9e categraf docker 监控配置
运维·docker·容器
青树寒鸦1 天前
wsl的docker备份mongo和迁移
运维·mongodb·docker·容器
有代理ip1 天前
Python 与 Golang 爬虫的隐藏优势
爬虫·python·golang
鲨辣椒100861 天前
Linux软件编程基石——基础指令使用
linux·windows·microsoft
云小逸1 天前
【Nmap 源码学习】深度解析:main.cc 入口函数详解
网络·windows·学习·nmap
郝学胜-神的一滴1 天前
Python美学的三重奏:深入浅出列表、字典与生成器推导式
开发语言·网络·数据结构·windows·python·程序人生·算法
天远云服1 天前
天远车辆过户查询API微服务实战:用Go语言构建高性能车况溯源系统
大数据·微服务·架构·golang
牙牙要健康1 天前
【open3d】Windows 下编译 Open3D C++ 源码完整教程
开发语言·c++·windows
女王大人万岁1 天前
Go标准库 sync 详解
服务器·开发语言·后端·golang