目前小菜刀的我的项目中须要用到SQLite数据库,https://github.com/mattn/go-s...,采纳Go的标准接口有利于我的项目后续扩大,因而抉择了该驱动。然而,它是基于CGO实现的,所以跨平台编译会比拟麻烦,小菜刀总结了一些教训,特分享给读者敌人们。
什么是跨平台编译?
简略地说, 就是在一个平台上生成另一个平台上的可执行代码。这里须要留神的是,所谓平台,实际上蕴含两个概念:体系架构(Architecture)、操作系统 (Operating System)。同一个体系架构能够运行不同的操作系统;同样,同一个操作系统也能够在不同的体系架构上运行。
咱们晓得Go语言是反对跨平台编译的,在之前的文章《Go穿插编译》中有具体介绍过怎么操作。Go实现跨平台编译的思维其实很简略:通过保留能够生成最终机器码的多份翻译代码,在编译时依据 GOARCH=xxx
和GOOS=xxx
参数(对应体系架构和操作系统)进行初始化设置,最终调用对应平台编写的特定办法来生成机器码,从而实现跨平台编译。
CGO编译存在的问题
有一点须要留神:Go所谓的跨平台编译只是针对Go代码局部,它是Go的穿插编译器(cross-compiler toolchains)。当咱们应用了CGO时,要想实现跨平台编译,同时须要让C/C++代码也反对跨平台。
package main/*#include <stdio.h>void printint(int v) { printf("printint: %d\n", v);}*/import "C"func main() { v := 42 C.printint(C.int(v))}
小菜刀的开发机器:amd64架构,darwin零碎。指标编译平台:amd64架构,linux零碎。现想将上述含有CGO的代码编译为指标平台的可执行文件。
$ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o main main.go
通过以上命令,失去编译谬误如下
/usr/local/go/pkg/tool/darwin_amd64/link: running clang failed: exit status 1ld: warning: ignoring file /var/folders/xk/gn46n46d503dsztbc6_9qb2h0000gn/T/go-link-220081766/go.o, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 )Undefined symbols for architecture x86_64: "_main", referenced from: implicit entry/start for main executableld: symbol(s) not found for architecture x86_64clang: error: linker command failed with exit code 1 (use -v to see invocation)
能够看到,因为CGO的存在,跨平台编译失败。那该如何解决呢?
其实思路能够很简略:和Go一样,当咱们领有指标平台的C/C++代码翻译零碎后,天然就可能编译为指标平台的可执行文件。
Mac下的可行计划
下载linux编译工具链
brew install FiloSottile/musl-cross/musl-cross
或者windows编译工具链
brew install mingw-w64
以linux编译工具链为例。在下载结束后,/usr/local/bin下会存在以下对应平台C/C++编译器
x86_64-linux-musl-addr2line x86_64-linux-musl-elfedit x86_64-linux-musl-gcov x86_64-linux-musl-objcopyx86_64-linux-musl-ar x86_64-linux-musl-g++ x86_64-linux-musl-gcov-dump x86_64-linux-musl-objdumpx86_64-linux-musl-as x86_64-linux-musl-gcc x86_64-linux-musl-gcov-tool x86_64-linux-musl-ranlibx86_64-linux-musl-c++ x86_64-linux-musl-gcc-9.2.0 x86_64-linux-musl-gprof x86_64-linux-musl-readelfx86_64-linux-musl-c++filt x86_64-linux-musl-gcc-ar x86_64-linux-musl-ld x86_64-linux-musl-sizex86_64-linux-musl-cc x86_64-linux-musl-gcc-nm x86_64-linux-musl-ld.bfd x86_64-linux-musl-stringsx86_64-linux-musl-cpp x86_64-linux-musl-gcc-ranlib x86_64-linux-musl-nm x86_64-linux-musl-strip
上述指定下载命令只下载了x86_64体系下的编译器,但其实并不止这些。可通过brew info musl-cross
命令进行查看。
$ brew info musl-crossfilosottile/musl-cross/musl-cross: stable 0.9.9 (bottled), HEADLinux cross compilers based on musl libchttps://github.com/richfelker/musl-cross-make/usr/local/Cellar/musl-cross/0.9.9 (1,851 files, 245.8MB) * Poured from bottle on 2020-11-16 at 17:09:31From: https://github.com/filosottile/homebrew-musl-cross/blob/master/musl-cross.rb==> DependenciesBuild: gnu-sed ✔, make ✔==> Options--with-aarch64 Build cross-compilers targeting arm-linux-muslaarch64--with-arm Build cross-compilers targeting arm-linux-musleabi--with-arm-hf Build cross-compilers targeting arm-linux-musleabihf--with-i486 Build cross-compilers targeting i486-linux-musl--with-mips Build cross-compilers targeting mips-linux-musl--with-mips64 Build cross-compilers targeting mips64-linux-musl--with-mips64el Build cross-compilers targeting mips64el-linux-musl--with-mipsel Build cross-compilers targeting mipsel-linux-musl--without-x86_64 Do not build cross-compilers targeting x86_64-linux-musl--HEAD Install HEAD version
此时,通过指定C/C++编译器为/usr/local/bin/x86_64-linux-musl-gcc
,替换默认的C/C++编译器(本机编译,可通过go env CC
查看),即可实现含有CGO的Go代码穿插编译工作。
$ GOOS=linux CC="/usr/local/bin/x86_64-linux-musl-gcc" GOARCH=amd64 CGO_ENABLED=1 go build -ldflags "-linkmode external -extldflags -static" main.go
最终,在本机mac零碎上就编译失去了amd64 linux平台的可执行文件。
Docker解决方案
在小菜刀通过上述形式实现cgo的跨平台编译之余,找到了另外一种可行计划:基于Docker容器的xgo打包工具。
它的实现也很简略:将多平台所须要的Go工具链,C/C++穿插编译器和头文件/库都组装到Docker容器中(因而,在镜像拉取时,会下载大量的依赖资源),再借助xgo打包工具实现跨平台编译。
- Docker装置(省略)
- 拉取镜像
docker pull karalabe/xgo-latest
- 打包工具装置
go get github.com/karalabe/xgo
轻量级的命令包装器,它的作用就是简化简单的Docker命令。
- 跨平台编译
指定要编译的导入门路即可,其余工作由xgo实现。在本例中,代码地位位于$GOPATH/src/workspace/example/cgoDemo2/
xgo $GOPATH/src/workspace/example/cgoDemo2/
编译之后,本目录下会存在以下各平台可执行文件
$ ls -altotal 44960drwxr-xr-x 23 slp staff 736 Nov 17 11:43 .drwxr-xr-x 39 slp staff 1248 Nov 16 17:59 ..-rwxr-xr-x 1 slp staff 1761872 Nov 17 11:42 cgoDemo2-android-16-386drwxr-xr-x 5 slp staff 160 Nov 17 11:42 cgoDemo2-android-16-aar-rwxr-xr-x 1 slp staff 1778464 Nov 17 11:42 cgoDemo2-android-16-arm-rwxr-xr-x 1 slp staff 902436 Nov 17 11:43 cgoDemo2-darwin-10.6-386-rwxr-xr-x 1 slp staff 1053816 Nov 17 11:43 cgoDemo2-darwin-10.6-amd64-rwxr-xr-x 1 slp staff 1065232 Nov 17 11:43 cgoDemo2-ios-5.0-arm64-rwxr-xr-x 1 slp staff 978016 Nov 17 11:43 cgoDemo2-ios-5.0-armv7drwxrwxrwx 3 slp staff 96 Nov 17 11:43 cgoDemo2-ios-5.0-framework-rwxr-xr-x 1 slp staff 1084208 Nov 17 11:42 cgoDemo2-linux-386-rwxr-xr-x 1 slp staff 1226072 Nov 17 11:42 cgoDemo2-linux-amd64-rwxr-xr-x 1 slp staff 1093728 Nov 17 11:42 cgoDemo2-linux-arm-5-rwxr-xr-x 1 slp staff 1074348 Nov 17 11:43 cgoDemo2-linux-arm-6-rwxr-xr-x 1 slp staff 1073800 Nov 17 11:43 cgoDemo2-linux-arm-7-rwxr-xr-x 1 slp staff 1196520 Nov 17 11:43 cgoDemo2-linux-arm64-rwxr-xr-x 1 slp staff 1152088 Nov 17 11:43 cgoDemo2-linux-mips-rwxr-xr-x 1 slp staff 1274272 Nov 17 11:43 cgoDemo2-linux-mips64-rwxr-xr-x 1 slp staff 1271464 Nov 17 11:43 cgoDemo2-linux-mips64le-rwxr-xr-x 1 slp staff 1148892 Nov 17 11:43 cgoDemo2-linux-mipsle-rwxr-xr-x 1 slp staff 1712214 Nov 17 11:43 cgoDemo2-windows-4.0-386.exe-rwxr-xr-x 1 slp staff 2115121 Nov 17 11:43 cgoDemo2-windows-4.0-amd64.exe-rw-r--r-- 1 slp staff 157 Nov 16 16:51 main.go
默认状况下,xgo会尝试编译Go运行时所反对的所有平台。如果咱们只想构建特定的几个指标零碎,能够应用逗号分隔的--targets
选项管制,例如--targets=windows/amd64,linux/amd64
代表编译指标仅包含amd64架构的windows和linux平台。
$ xgo --targets=windows/amd64,linux/amd64 $GOPATH/src/workspace/example/cgoDemo2/
目前反对的平台列表如下
- 操作系统:
android
,darwin
,ios
,linux
,windows
- 架构:
386
,amd64
,arm-5
,arm-6
,arm-7
,arm64
,mips
,mipsle
,mips64
,mips64le
xgo提供了比拟灵便的编译计划,通过$ xgo -h
查看选项信息,更多详情可点击文末的xgo链接。
参考链接
[easy windows and linux cross-compilers for macOS] https://blog.filippo.io/easy-...
[musl-cross-make] https://github.com/richfelker...
[homebrew-musl-cross] https://github.com/FiloSottil...
[xgo] https://github.com/karalabe/xgo