背景
Go是一門全新的靜態類型開發語言,具有自動垃圾回收
,豐富的內置類型
,函數多返回值
,錯誤處理
,匿名函數
,並發編程
,反射
等特性。
從Go1.4之后Go語言的編譯器完全由Go語言編寫,所以為了從源代碼編譯Go需要先編譯一個1.4版本的Go版本。
所以,搭建go語言開發環境(版本>1.4)只需要:
1)編譯go1.4版本,設置好GOROOT_BOOTSTRAP
2)然后再執行腳本編譯安裝GO1.4以上版本(任何支持的平台都可以)
注意,go的安裝/移植 比較奇怪,它是以 源碼包當前的路徑作為根目錄的,相當於prefix =PWD
有關資料: 【英文文檔】 Installing Go from source Go語言官方編譯指南 2019.02.27
開發環境介紹
- 主機操作系統:Ubuntu18.04 64位
- 目標平台:S5P6818(ARM-A53)
- 交叉工具鏈:arm-none-linux-gnueabi-gcc,gcc7.3.0
- Go版本:1.12 (https://github.com/golang/go/releases)
- 編譯時間:2019.03.03
准備Go Bootstrap
編譯3個版本
#/** @file make_go.sh
# * @author Schips
# * @date 2020/09/15
# * @version v1.1
# * @copyright Copyright By Schips, All Rights Reserved
# *
# **********************************************************************************
# */
#!/bin/sh
BUILD_HOST=arm-eabi
BASE=`pwd`
ARM_GO_DIR=${BASE}/source/_arm_go
HIG_GO_DIR=${BASE}/source/_go_higher
BOOTSTRAP_DIR=${BASE}/source/_go_boot_strap
GOROOT_BOOTSTRAP=${BOOTSTRAP_DIR}/go
test_env() {
CMD=$1
command -v ${CMD} >/dev/null 2>&1 || { echo >&2 "Aborted : Require \"${CMD}\" but not found."; exit 1; }
}
CROSS_TOOL_DIR=`dirname \`whereis ${BUILD_HOST}-gcc | awk -F: '{ print $2 }'\``
if [ -z "$CROSS_TOOL_DIR" ]; then
ARM_GCC_PATH=/home/schips/6818/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin
echo "no found cross gcc, using ${ARM_GCC_PATH}"
CROSS_TOOL_DIR=$ARM_GCC_PATH
fi
export PATH=$PATH:$CROSS_TOOL_DIR
test_env ${BUILD_HOST}-gcc
make_dirs () {
#為了方便管理,創建有關的目錄
cd ${BASE} && mkdir compressed install source -p
}
tget () { #try wget
filename=`basename $1`
echo "Downloading [${filename}]..."
if [ ! -f ${filename} ];then
wget $1
fi
echo "[OK] Downloaded [${filename}] "
}
download_package () {
cd ${BASE}/compressed
tget https://dl.google.com/go/go1.4.3.src.tar.gz
# 高版本
tget https://dl.google.com/go/go1.13.8.src.tar.gz
}
tar_go_for_boot_stap () {
cd ${BASE}/compressed
mkdir ${BOOTSTRAP_DIR} -p
tar -xf *go1.4* -C ${BOOTSTRAP_DIR}
}
make_go_for_boot_stap () {
cd ${BOOTSTRAP_DIR}/go/src
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 ./make.bash
}
tar_go_version_higher_host () {
cd ${BASE}/compressed
HIGHER=`ls go* | grep -v 1.4 `
mkdir ${HIG_GO_DIR} -p
tar -xf $HIGHER -C ${HIG_GO_DIR}
}
make_go_version_higher_host() {
export GOROOT_BOOTSTRAP=$GOROOT_BOOTSTRAP
cd ${HIG_GO_DIR}/go/src
GOOS=linux GOARCH=amd64 ./make.bash
}
tar_go_version_higher_arm () {
cd ${BASE}/compressed
HIGHER=`ls go* |grep -v 1.4 `
mkdir ${ARM_GO_DIR} -p
tar -xf $HIGHER -C ${ARM_GO_DIR}
}
make_go_version_higher_arm() {
export GOROOT_BOOTSTRAP=$GOROOT_BOOTSTRAP
cd ${ARM_GO_DIR}/go/src
CGO="no"
if [ $CGO = "yes" ]
then
echo "CGO is enable"
# 開啟CGO編譯(參考下文)
export CC_FOR_TARGET=${CROSS_TOOL_DIR}/${BUILD_HOST}-gcc
export CXX_FOR_TARGET=${CROSS_TOOL_DIR}/${BUILD_HOST}-g++
CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 ./make.bash
else
echo "CGO is disable"
# 關閉CGO編譯
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 ./make.bash
fi
}
show_config () {
#echo "go bootstarp is : $GOROOT_BOOTSTRAP"
echo "made go"
tree ${BASE}/install/go_with_arm/bin
echo "go bootstarp is : ${BASE}/install/go_boot_strap"
echo " CC_FOR_TARGET is : ${CROSS_TOOL_DIR}/${BUILD_HOST}-gcc"
echo "CXX_FOR_TARGET is : ${CROSS_TOOL_DIR}/${BUILD_HOST}-g++"
# 關於下方的變量請參考有關文章
GOROOT="${BASE}/install/go_with_arm"
GOPATH=`dirname $GOROOT`/gopath
echo "GOROOT is : ${GOROOT}"
echo "GOPATH is : ${GOPATH}"
echo "==========================================="
echo "## for Run cmd-pc"
echo "export GOROOT=${GOROOT}"
echo "export GOPATH=${GOPATH}"
echo "export PATH=\$PATH:\$GOROOT/bin:\$GOPATH/bin"
echo
echo "## for Next time bootstarp"
echo "export GOROOT_BOOTSTRAP=${BASE}/install/go_boot_strap"
echo "export CC_FOR_TARGET=${CROSS_TOOL_DIR}${BUILD_HOST}-gcc"
echo "export CXX_FOR_TARGET=${CROSS_TOOL_DIR}/${BUILD_HOST}-g++"
echo
echo "## [Optional]"
echo "alias arm-go=\"GOOS=linux GOARCH=arm GOARM=7 go build\""
echo "alias gob=\"go build\""
echo
echo "## for Run cmd-target"
echo "export GOROOT=${GOROOT}"
echo "export GOPATH=${GOPATH}"
echo "export PATH=\$PATH:\$GOROOT/bin:\$GOPATH/bin"
}
make_together () {
#boot strap
mv ${BOOTSTRAP_DIR}/go ${BASE}/install/go_boot_strap
#higher_host(好像arm版本的編譯里面也自帶了本機可以用的go)
#mv ${HIG_GO_DIR}/go ${BASE}/install/go_host
#higher_arm
mv ${ARM_GO_DIR}/go ${BASE}/install/go_with_arm
show_config
}
echo "Using ${BUILD_HOST}-gcc"
make_dirs
download_package
tar_go_for_boot_stap
make_go_for_boot_stap
#好像arm版本的編譯里面也帶了本機可以用的go,所以這2句腳本是不需要的
# tar_go_version_higher_host
#make_go_version_higher_host
tar_go_version_higher_arm
make_go_version_higher_arm
make_together
編譯完成以后,最后會提示應該如何配置環境變量(在下文中需要用到)
提示:當選擇開啟CGO編譯時必須配置先CC_FOR_TARGET和CXX_FOR_TARGET兩個環境變量
建議 高版本的go設置CGO=0;建議 arm版本的go 設置CGO=1。
腳本中編譯go的時候,用到了兩個變量:
- GOOS:目標操作系統
- GOARCH:目標操作系統的架構
OS | ARCH | OS version |
---|---|---|
linux | 386 / amd64 / arm | >= Linux 2.6 |
darwin | 386 / amd64 | OS X (Snow Leopard + Lion) |
freebsd | 386 / amd64 | >= FreeBSD 7 |
windows | 386 / amd64 | >= Windows 2000 |
編譯其他平台的時候根據上面表格參數執行編譯就可以了。
-
-
$GOARM (for arm only; default is auto-detected if building on the target processor, 6 if not)
This sets the ARM floating point co-processor architecture version the run-time should target. If you are compiling on the target system, its value will be auto-detected.
-
- 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
-
If in doubt, leave this variable unset, and adjust it if required when you first run the Go executable. The GoARM page on the Go community wiki contains further details regarding Go's ARM support.
在install/go_arm/
目錄下會生成arm和amd64兩個平台的Go命令和依賴包,所以這個版本編譯的Go命令可以進行兩個平台的Go應用程序開發。
# schips @ ubuntu in ~/host/go/install/go_arm/bin [20:57:41]
$ tree
.
├── go(PC上正常使用的)
├── gofmt
└── linux_arm(這個目錄下的程序是在arm上運行的)
├── go
└── gofmt
設置環境變量
在自己的bash中的對應資源文件(*rc)中添加如下內容(重啟命令行后生效)):
不同bash對應rc文件也不同,比如 .ashrc,.bashrc,.zshrc 等
關於 go有關的環境變量可以參考: 《GOROOT、GOPATH、GOBIN變量的含義》
# 設置 GOROOT_BOOTSTRAP是為了下次 編譯的時候可以用
export GOROOT_BOOTSTRAP=根據上面腳本的編譯結果
export CC_FOR_TARGET=根據上面腳本的編譯結果
export CXX_FOR_TARGET=根據上面腳本的編譯結果
# 一定需要的
export GOROOT=根據上面腳本的編譯結果
export GOPATH=可以參考根據上面腳本的編譯結果
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
# 可選的,快捷命令
alias arm-go="GOOS=linux GOARCH=arm GOARM=7 go build"
alias gob="go build"
例如:
Installed Go for linux/amd64 in /home/schips/go/source/_go_boot_strap/go
Installed commands in /home/schips/go/source/_go_boot_strap/go/bin
CGO is disable
Building Go cmd/dist using /home/schips/go/source/_go_boot_strap/go.
Building Go toolchain1 using /home/schips/go/source/_go_boot_strap/go.
Building Go bootstrap cmd/go (go_bootstrap) using Go toolchain1.
Building Go toolchain2 using go_bootstrap and Go toolchain1.
Building Go toolchain3 using go_bootstrap and Go toolchain2.
Building packages and commands for host, linux/amd64.
Building packages and commands for target, linux/arm.
---
Installed Go for linux/arm in /home/schips/go/source/_arm_go/go
Installed commands in /home/schips/go/source/_arm_go/go/bin
go bootstarp is : /home/schips/go/install/go_boot_strap
CC_FOR_TARGET is : /home/schips/6818/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-gcc
CXX_FOR_TARGET is : /home/schips/6818/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/arm-eabi-g++
GOROOT is : /home/schips/go/install/go_arm
GOPATH is : /home/schips/go/install/gopath # 沒錯,真的是這么寫的
測試
驗證go 是否正常運行 以及 輸出版本
新開一個bash,輸入 go version
可以進行安裝的簡單驗證:
$ go version
go version go1.12 linux/amd64
有關程序的驗證
新建helloworld.go
package main
import "fmt"
func main() {
fmt.Println("Hello world")
}
編譯與運行
在本地運行的結果:
go build helloworld.go
./helloworld
Hello world
在板子上:
# 在 host 上交叉編譯
GOOS=linux GOARCH=arm GOARM=7 go build helloworld.go
[root@6818 ~/nfs]#./helloworld
Hello world