交叉编译Go程序

in #cn6 years ago (edited)

有几个Go的程序需要放在树莓派上跑,由于树莓派的性能太差、编译工具版本又低,想想还是在其他设备上编译好可执行文件直接拿来用方便,毕竟无需依赖的静态编译是Go的亮点嘛。

Go对交叉编译的支持是极好的:对于没有使用CGO的程序,只需要通过设置$CGO_ENABLED、$GOOS、$GOARCH参数即可轻松地实现跨平台编译;对于使用CGO的程序,大部分情况可以通过配置$CC参数使用自行准备的交叉编译工具进行编译。

cross-compile.png

下面以macOS为例,简单记录一下过程中踩的坑吧


不使用CGO的交叉编译

一般做法

在macOS编译Linux和Windows的arm可执行程序:

    CGO_ENABLED=0 GOOS=linux GOARCH=arm go build main.go
    CGO_ENABLED=0 GOOS=windows GOARCH=arm go build main.go

其中:

  • $CGO_ENABLED:0表示关闭CGO

  • $GOOS:目标平台(编译后要运行的目标平台)的操作系统(darwin、freebsd、linux、windows)

  • $GOARCH:目标平台(编译后要运行的目标平台)的体系架构(386、amd64、arm)分别对应(32位、64位、ARM平台)的架构

树莓派属于ARM平台,对于编译给ARM使用的Go程序,需要根据实际情况配置$GOARM,这是用来控制CPU的浮点协处理器的参数。$GOARM默认是6,对于不支持VFP使用软件运算的老版本ARM平台要设置成5,支持VFPv1的设置成6,支持VFPv3的设置成7,详细说明如下:

GOARM=5: use software floating point; when CPU doesn't have VFP co-processor

GOARM=6: use VFPv1 only; default if cross compiling; usually ARM11 or better cores (VFPv2 or better is also supported)

GOARM=7: use VFPv3; usually Cortex-A cores

综上,给跑着linux的老版本树莓派编译Go程序的命令为:

    CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=5 go build main.go

关于协处理器

协处理器是协助CPU完成其无法执行或执行效率、效果低下的处理工作而开发和应用的处理器。

这种CPU无法执行的专项工作有很多,比如设备间的信号传输、接入设备的管理等;执行效率、效果低下的有图形处理、声频处理等。为了进行这些专项处理,各种辅助处理器就诞生了。现在的计算机构架(x86、amd64)中,整数运算器与浮点运算器已经集成在一起,一般来讲因此浮点处理器内建于CPU中的协处理器,不算是辅助处理器,不过ARM架构因为低功耗的原因是个例外。

ARM架构中的VFP coprocessor是典型的协处理器,它提供浮点数基本运算(加、减、乘、除、开方、比较、取反)以及向量(vectors)功能,一般来讲,VFP可以同时支持最多8组单精度4组双精度浮点数的运算。

简单地说,使用协处理器可以提升某一方面的性能,可以粗暴地认为是一种硬件加速。

使用CGO的交叉编译

什么是CGO

C语言经过数十年发展,各个方面的开源代码、闭源库已经非常丰富。这对于一门现代编程语言而言,如何用好现成的C代码就显得极为重要,CGO就是一个令人惊异的技术,它允许Go与C的类库交互操作,让Go能够使用C语言积累的各种资源。

CGO作为Go中使用C语言代码的一种方式,在获得好处的同时就必定得有付出,这是亘古不变之理:由于CGO相当于使用了C语言,所以编译使用CGO部分的代码就必须按C语言路子来,而C语言原生的跨平台支持相对Go来说可是差远了,使得使用CGO后要编译跨平台的可执行文件就麻烦多了。

目前解决CGO跨平台编译问题的思路有:

  1. 用目标平台的工具链进行交叉编译
  2. 用原生代码重写CGO实现的功能

用目标平台的工具链进行交叉编译

以树莓派的ARM平台为例,用ARM GNU Linux工具链,编译使用了CGO的Go项目。

macOS的文件系统默认是大小写不敏感的,而交叉编译工具链是基于大小写敏感的文件系统的,所以应当新建一个大小写敏感的磁盘镜像用于安放ARM GNU Linux工具链。打开Disk Utility,然后 File>New Image>Blank Image,然后在弹出窗口中设置名称为armx(名称自定),大小大于512MB,格式为Mac OS Extended的映像。

DiskUtility.png

下载或者按说明自行编译ARM GNU Linux工具链。

假设工具链包已经在~/Download目录中,解压缩工具链到到新建的磁盘镜像中:

    tar -zxv -C /Volumes/armx/ --strip-components 1 -f ~/Download/ARMx-2009q3-67.tar.bz2

ARM-Tool.png

现在,你就已经能够直接使用ARM工具链了,比如要编译main.c程序,可以在终端执行:

    /Volumes/Armx/bin/arm-none-linux-gnueabi-gcc main.c -o main

就可以获得一个名为main的可执行程序,这个程序在macOS是不能运行的,只能在ARM平台设备上的Linux系统中才能执行。

好了,现在开始编译用了CGO的Go程序给树莓派用吧:

    CGO_ENABLED=1 GOOS=linux GOARCH=arm CC=/Volumes/Armx/bin/arm-none-linux-gnueabi-gcc GOARM=5 go build -x main.go

其中$CC参数指定的是ARM工具链位置,如果不出意外的话,编译完成后就可以得到可以在树莓派上运行的Go程序了。

ARMfile.png

如果使用Beego提供的bee工具进行编译和打包,效果也是一样的的。

    CGO_ENABLED=1 GOOS=linux GOARCH=arm CC=/Volumes/Armx/bin/arm-none-linux-gnueabi-gcc GOARM=5 ~/go/bin/bee pack main.go 

Beego-pack.png

交叉编译过程中如果出现错误,多半是因为使用CGO部分的代码,在不同的平台存在不兼容的问题,需要根据错误提示逐项解决。

用原生代码重写CGO实现的功能

这一小节是废话,用原生Go代码重写之后问题划归成了无需CGO的一类类,也就不存在CGO的交叉编译问题了。

Sort:  

Congratulations @holmesian! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You received more than 100 upvotes. Your next target is to reach 250 upvotes.

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

Meet the Steemians Contest - The results, the winners and the prizes

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @holmesian! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You got your First payout

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @holmesian! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You made more than 1500 upvotes. Your next target is to reach 1750 upvotes.

Click here to view your Board of Honor
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

Saint Nicholas challenge for good boys and girls

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @holmesian! You have completed the following achievement on the Steem blockchain and have been rewarded with new badge(s) :

You made more than 1750 upvotes. Your next target is to reach 2000 upvotes.

Click here to view your Board
If you no longer want to receive notifications, reply to this comment with the word STOP

Do not miss the last post from @steemitboard:

Christmas Challenge - The party continues
Christmas Challenge - Send a gift to to your friends

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @holmesian! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.24
TRX 0.26
JST 0.041
BTC 98449.34
ETH 3495.58
USDT 1.00
SBD 3.36