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 的设备,所以我就没有尝试。不过还是把它记录在这里了,也许有人会需要这个东西呢。

相关推荐
依旧阳光的老码农16 分钟前
Windows下使用 VS Code + g++ 开发 Qt GUI 项目的完整指南
开发语言·windows·qt
草海桐40 分钟前
go 的 net 包
网络·golang·net
李菠菜2 小时前
Kubernetes上通过Helm部署高可用Redis集群
docker·容器·kubernetes
李菠菜2 小时前
修改KubeSphere外网访问端口
docker·容器·kubernetes
福大大架构师每日一题2 小时前
docker v28.1.1 正式发布!修复关键Bug,网络与安全性再升级
网络·docker·bug
一个小坑货3 小时前
Docker 部署 PostgreSQL 数据库
数据库·docker·postgresql
残轩4 小时前
Win10 家庭版 Docker 环境搭建详解(基于 WSL2)
前端·后端·docker
David爱编程4 小时前
90%工程师都踩过的坑:K8s三种探针最佳组合方案全解析
docker·云原生·kubernetes
davysiao4 小时前
基于 CentOS 的 Docker Swarm 集群管理实战指南
linux·docker·centos
Archie_IT5 小时前
Puter部署指南:基于Docker的多功能个人云平台掌控自己的数据
运维·docker·容器