走出舒适区,我了解了 Go 的交叉编译功能。
在 Linux 上测试软件时,我使用各种架构的服务器,例如 Intel、AMD、Arm 等。当我 分配了一台满足我的测试需求的 Linux 机器) N $ m Q ~,我仍然需要执行许多步骤:
- 下载并安装必备软件
- 验证构X b 1 + E \建服务器上是否有新的测试软件包
- 获取并设置依赖软件包所需的 yum 仓库
- 下载并安装新的测试软件包(基于步骤 2)
- 获取并设置必需的 SSL 证书
- 设置测试环境,获取所需的 Git 仓库,更改配置,D c H Q 1 =重B U i / ( ? I 2 `新启动守护4 J & & Q进程等
- 做其他需要做的事情
用脚本自动化
这些步骤非常常规,以至于有必要对其进行自动化并将| / (脚本保存到中央位置(例如文件服务器),在需要时可以在此处下载P 5 O , | V #脚本。为此,我编写了 100-120 行的 Bash shell 脚本,它为我完成L Y ` U O 6了所有配置(包括错误检查)。这个脚本通过以下方式简化了我的工作流程:
- 配置新的 Linux 系统(支持测试的架9 y z { D &构)
- 登录系统并从中央位置下载自动化 shell 脚+ I g ! – 7 P本
- 运行它来配置系统
- 开始测试
学习 Go 语言
我想学习 Go 语言 有一段时间了,将我心爱的E A P Shell 脚本转换为 Go 程序似乎是一个很好的项目,可以帮助我入6 r X k k e门。它的语法看起来很简单,在尝试了一些测试程序后,我开始着手提高自己的知识并熟悉 Go 标准库。
我花了一个星期的时间在笔记本电脑上编写 Go 程序。我经常在我的T G 8 x8+ j S b O @ ; x6 服务器上测试程序,清除错* ( ; u N [ 4 ] ,误并使程序健壮起来,一切都很顺利。
直到完全转换到 Go 程序前,我继续依赖自己c s @ x a 7 X Z {的 shell 脚本。然后,我将二进制文件推送到中央文件服务器上,a . ] % t | N N以便每次配置新服务器时,我要做的就是获取二进制文件,将@ Q A , e S S P )可执行标志打开,然后运行二进制文件。我对早期的结果很满意:
- $wgethttp://file.ex] \ 0 = H c } X 8a[ 7 g n L { _ Nmple.com/&- V 0 g _ ; C . [lt;myuser>/binsn ` G = $ d/] r 7 t I ip. \ Arepnode
- $chmod+x./prepnode
- $./prepnode
然后,出现了一个问题
第二周,我\ I ) ) a Q u从资源池中分配了一台新的服务器,像往常一样,我下载了二进制文件,设置了可执行标志,然后运行二进制文件。但这次它出错了,是@ F $ J s o i一个奇怪E $ J i的错误:
- $./prepnode
- bash:./prepnode:cannotexecutebinaryf{ / n l r i # 3ile:Execformaterror
- $R n w 8 d
起初,我以为可能没有成功设9 f A置可执行标志。但是,它已按预期设置:
- $ls-lprepnode
- -rwxr-xr-x.1rootroot2640529Dec1605:43X 0 o 4 O pprepnode
发生了什么事?我没有对源代码进行任何更改,编译没有引发任何错误或警告,而且上次运行时效果很C { N好,因此2 U + R /我仔细查看了错误消息 format error。
我检查了二进制文件的格式,一切看起来都没问题:
- $fileprepnode
- prep y H a . ^ i )pnode:ELF3 ? Z } F 4 = a64-bitLSBexecutable,x86-6e ~ C ! V + i M4,version1(SYSV),static] [ @ / E , ?allylinI B Uked,notsty [ K 4 & & -ripped
我迅速运行了以下命令,识别所配置的测试服务器的架构以及二进制试图运行的平台。它是 Arm6E W A4 架构,但是D | ? ?我编译的二进制文件(在我的 x8& ; [6 笔记本电脑上)生成的是 x86-6 D G64 格式的二进制文v \ H P 1 0 u件:
- $uname-m
- aarch64
脚本编写人员的编译第一课
在那之前,我从未考虑过这种情况(尽管我知道这一点)。我主要研究脚本语言(通常是 Python)以及 Shell 脚本。在任何架构的大多数 Linux 服务器上都可以使用 Bash Shell 和 Python 解释器。总之,之前一切都很顺利。
但是,现在我正在处理 Go 这种编译语言,它生成可执行的二进制文件。K I ] s编译后的二进制文件由特定架构的 指令码 或汇编指令组成,这就是为什么我收到格式错误的原因。由于Y = * / V Arm64 CPU(运行二进制文件p j ? W的地方)无法解释二进制文件的 x86-64 指令,因此它抛出错误。以前,shell 和 Python 解释器为我处理了底层指令码或特定架构的指令。
Go 的交叉编译
我检查E u \了 Golang 的文档,发现要生成 Arm64 二进制文件,我要做的就是在运行 go build 命令编译 Go 程序之前设置两个环境变量。
GOOS 指的是操作系统,5 t J例如 LinuxA R p O #、Windows、BSD 等,而 GOARCH 指的是k 7 n c要在哪种架构上构建程序。
- $envGOOS=linuxGOARCH=arm64gobuild-opm - j a i 0 K 9 Srepnode_arm64
构建程序后,我重新运行 file 命令,这一次它显示的是 ARM AArch64,而不是之前显示的 x86。因此,我在我的笔记本上能为不同的架构构建二进制文件。
- $filept p 9 c C s x !repnode_arm64
- prepnode_at ~ Frm64:ELF64-bitLSBexecutable,ARMaarch64,version1(SYSV),staticallylinked,notstripped
我将二进制文件从笔. } { \记本电脑复制到 ARM 服务器上。现在运行二进制文件(将可执行标志打开)不会产生任何错误:
- $./prepnode_arm64-h
- Usageofi z _ + V K a l./prepnode_arm64:
- -cCleanexistinginstaG . b E s v Y &llation
- -nDonotstartl ~ 7 ] d ; u 8testrun(defaulttrue)
- -sUsestd a u + t ^ m 9 iagH W leenvironU { kment,defaultisqa
- -vEnableverboseoutpu; _ [ D 8t
其他架构呢?
x86 和 Arm 是我测试软件所支持的 5 种架构中的两种,我担心 Go 可能不会支持其它架构% Y U,但事实并非如此。你可以查看 Go 支~ O u W I持的架构:
- $gotooldistlist
Go 支持多种平台和操作系统,包括:
- AIX
- Android
- Darwin
- Dragonfly
- FreeBSD
- Illumos
- JavaScript
- Linux
- NetBSD
- OpenBSD
- Plan 9
- Solaris
- Windows
要查找其支持的特定 Linux 架构,运行:$ 2 _ c O [ J T =
- $gotooldistlist|greplinux
如下面的输出所示,Go 支持我使用的所有体系结构。尽管 x86_64 不在列表中,但 AMD64 兼容 x86-64,所以你可以生成 AMD64 二进制文件,它可以在 x86 架构上正常运行:
- $gotooldistlist|greplinux
- linux/386
- linux/amd64
- l/ ? 5 v c d }inux/arm
- linux/a@ c d 9rm64
- linux/mips
- linux/mips64
- linux/mips64le
- lm : Q O Sinux/mipsle
- linux/ppc64
- linux/ppc64le
- linux/riscv64
- linux/s390x
处理所有架构
为我测试的所有体系结构生成二进制文件,就像从我的 x86 笔记本电脑编写一个微小的 shell 脚本一样简单^ 6 C:
- #!/usr/bin/bash
- archs=(amd64arm64ppc64leppc64s390x)
- forarchin${archs[@]}
- do
- en% 0 Y 8 ! s # /vGOOS=linuxGOARCH=${arch}L _ W K \ Ygobuild-oprepnode_${arch}
- done
- $fileprepnode_@ ( w e ` * m*
- prepn. X A \ M Z tode_amd64:ELF64-bitLSBexecutable,x86-64,version1(SYSV),staticallyliK D f v p @ L D Lnked,GoBuildID=y03MzCXoZERH-0EwAAYI/p909FDnk7xEUo2LdHIyo/V2ABa7X_rLkPNHaFqUQ6/V \ L N5p_q8MZiR2WYkA5CzJiF,notstripped
- prepnode_4 _ , g }arm64:ELF64-bitLSBexecutaT & - . n s ?ble,H \ P yARMaarch64,version1(SYSV),staticallylinked,GoBuildID=q-H-CCtLv__jVOcdcOpA/CywRwDz9LN2Wk_fWeJHt/K4-3P5tU2mzlWJa0noGN/SEev9TJFyvHdKZnPaZgb,notstripped
- prepnodeV f 5 l Q Q H F a_ppc64:ELF64-bitMSBexecutable,64-bitPowerPCorcisco7500,) Y +version1(SYSV),staticallylinked,GoBuildID=DMWfc1QwOGIq2h3 - Z }xEzL_u/UE-9CC u G hIvkIMex S K ^ F j J TNC_ocW4ry/r-7NcMATXatoXJQz3yUO/xzfiDIBuUxbuiyaw5Goq,notstripped
- prepnodeK Q i T } ] 0 x_ppc64le:ELF64-bitLSBexecutable,64-bitPowerPCorcisco7500,version1(SYSV),staticallylinked,GoBuildID=C6qCjxwO9s63FJKDrv3f/xCJa4E6LPVv z @ o A - 3pEZqmbF6B4/Mu6T_2 t d 9OR-dx-vLavn1Gyq/AWR1pK1cLz9YzLSFt5eU,notstrippedb 3 ) G )
- prepnode_s390x:ELF64-h _ o S - - . y !bitMSBexep 5 = G T o - j ^cutable,IBMS/390,version1(SYSg 0 X ; g LV),staticallylinked,GoBuildID=faC_HDe1_iVq2XhpPD3d/7TIv0rulE4W A s Z 0 \ $ C \RZybgJVmPz/o_SZW_0iS0EkJJZHANxx/zuZgo79Je7zAs3v6Lxuz,notstripped
现在,每当配置一台新机器时,我就运行以下 wget 命令下载特定体系结构的二进制文件,将可执行标志打开,然后运行:
- $wgethttp://file.domain.com/<myuser&f l ?gt;/bins/prepnode_<arch>
- $chmod+x./prepnode_<arch>
- $./prepnode_<arch>
为什么?
你可能想知道,为什么我没有坚持s + U使用 shell 脚本或将I ! E h : ; 4 + G程序移植到 Python 而不是编译语言上来避免这些麻烦。所以有舍有得,那样的话我不会了S v u 6 Y D @ # j解 Go 的交叉编译功能,以u l I % g a D ~ H及程序在 CPU 上执行时的底层工作原理。B y o _ / ~ 2 L在计算机中,总要考虑取舍,但绝不要让它们阻碍你的学习。
点赞 0