GO 交叉编译环境配置
背景
大多数嵌入式设备都是没有自己的工具链的,基本上都是通过交叉编译以及远程调试的方案进行开发;目标机上连 C/C++ 的开发环境都没有,自然就不用提及 GO 了。
为了在嵌入式设备上运行 GO 编写的程序,需要交叉编译 GO 。
而 GO 又是一门比较离谱的语言,其一开始编译环境与 python 一致,使用 gcc 进行编译,但是后来在 1.4 版本之后,之后 GO 的编译采取的方式都是使用旧的 GO 编译新的 GO ,用人话来说就是自己编译自己;所以要配置 GO 的交叉编译环境,需要先编译 GO1.4 ,然后用 GO1.4 去编译更高版本的 GO,所以下文的逻辑如果理不顺的话要好好地思考一下这段话。
环境说明
宿主机
- 发行版本 : Ubuntu
- 内核版本 : 5.4.0-90-generic
- ubuntu 版本 : Ubuntu 20.04.3 LTS
- gcc : 9.3.0
目标机
- 发行版本 : 无
- 内核版本 : 3.18.20
- 交叉编译工具链 : arm-hisiv600-linux
- gcc : 4.9.4
GO 安装
找一个地方作为你的安装工作区
git clone https:///golang/go.git
export WORKSPACE=$(pwd)
cp -rf go go1.4
# echo ${WORKSPACE}
GO 1.4 安装
cd ${WORKSPACE}/go1.4/src
# 切换到 go 1.4
git checkout go1.4
CGO_ENABLED=0 CC=gcc GOOS=linux GOARCH=amd64 ./make.bash
如果出现像下面这样的错误:
437 | if(ndigits > prec) {
| ^
451 | default:
| ^~~~~~~
cc1: all warnings being treated as errors
说明你的 gcc 版本有点高,两种解决方案:
降级 gcc
sudo apt install gcc-5
# 临时降低 gcc 版本
CGO_ENABLED=0 CC=gcc-5 GOOS=linux GOARCH=amd64 ./make.bash
屏蔽警告
CGO_ENABLED=0 CFLAGS='-Wno-implicit-fallthrough -Wno-shift-negative-value' CC=gcc GOOS=linux GOARCH=amd64 ./make.bash
个人推荐第二种解决方案,出现这种问题的原因主要还是因为 GO1.4 是挺久之前写的了, 使用
git log
就可以看到最后一次修改差不多是 2015 年的时候,差不多过去 7 年了,gcc 的版本也升级了挺多个版本。
GO 1.17 安装
mv go go1.17
cd ${WORKSPACE}/go1.17/src
git checkout go1.17
# GOROOT_BOOTSTRAP 填写刚刚编译出来的 go1.4
# CC_FOR_TARGET 和 CXX_FOR_TARGET 填写自己的交叉工具链
# CGO_ENABLED 使能运行 GO 去调用 c 的代码
GOROOT_BOOTSTRAP=${WORKSPACE}/go1.4 CC_FOR_TARGET=arm-hisiv600-linux-gcc CXX_FOR_TARGET=arm-hisiv600-linux-gcc++ CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 ./make.bash
为 GO 添加环境变量
环境变量添加方式还是挺多种的,这里直接添加到 ~/..bashrc
下,在后面添加上如下内容,需要按照自己的进行修改,或者用 echo
追加算了:
# ${WORKSPACE} 需要保证你从头到尾没有换过终端
# 交叉编译工具链自己填写
echo "export GOROOT=${WORKSPACE}/go1.17" >> ~/.bashrc
echo "export CC_FOR_TARGET=arm-hisiv600-linux-gcc" >> ~/.bashrc
echo "export CXX_FOR_TARGET=arm-hisiv600-linux-g++" >> ~/.bashrc
echo "export GOBIN=${WORKSPACE}/go1.17/bin" >> ~/.bashrc
echo "export PATH=${PATH}:${WORKSPACE}/go1.17/bin" >> ~/.bashrc
然后把环境变量刷新一下:
source ~/.bashrc
测试 GO
写一个 hello_world.go
程序测试一下 go。
cat << EOF > hello_world.go
package main
import "fmt"
func main() {
fmt.Printf("hello, world\n")
}
EOF
GO 的版本
go version
# go version go1.17 linux/amd64
GO 宿主机运行
go run hello_world.go
出现:
hello, world
GO 目标机运行
# 生成可执行程序,放在目标机上看看
GOOS=linux GOARCH=arm GOARM=7 go build hello_world.go
出现:
hello, world
总结
至此 go 的交叉编译环境配置就完成了,总结一下:
- 编译宿主机程序 : go build xx.go
- 编译目标机程序 : GOOS=linux GOARCH=arm GOARM=7 go build