Golang交叉編譯
1. 編譯環境
宿主開發平台為:
Linux wanhy-ubuntu 5.3.0-62-generic
#56~18.04.1-Ubuntu SMP Wed Jun 24 16:17:03 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
目標執行平台為:
Linux pilotx-du 4.14.98+gebeb3d5
#1 SMP PREEMPT Wed Aug 21 10:17:13 UTC 2019 aarch64 GNU/Linux
2. 常規編譯
2.1 Go Build使用
2.1.1 GOOS變量
The operating system for which to compile code.
Examples are linux, darwin, windows, netbsd.
2.1.2 GOARCH變量
The architecture, or processor, for which to compile code.
Examples are amd64, 386, arm, ppc64.
2.2.3 GOARM變量
For GOARCH=arm, the ARM architecture for which to compile.
Valid values are 5, 6, 7.
2.2 編譯設置
2.2.1 建立Makefile
文件,內容如下:
NAME=agent
OS=linux
#OS=windows
# ARCH=amd64
# ARCH=arm
ARCH=arm64
ARM=7
build:
GOOS=$(OS) GOARCH=$(ARCH) GOARM=$(ARM) go build -o $(NAME)_$(OS)_$(ARCH)_$(ARM) ./max_client.go
2.2.2 編譯指令:
make build
2.2.3 特別注意:
默認按照這種方式,在linux下可以正常輸出linux,window,mac的可執行程序,但輸出的arm不能在arm車機上運行,需要使用下面的交叉編譯設置。
2. 交叉編譯
本例使用docker環境來進行交叉編譯環境的搭建。
2.1 獲取阿里雲的軟件源
鏡像網址為:https://developer.aliyun.com/mirror/
點擊進入:系統->Ubuntu目錄
網址為:https://developer.aliyun.com/mirror/ubuntu?spm=a2c6h.13651102.0.0.3e221b111qDsJK
復制ubuntu 18.04(bionic) 配置如下
內容到/etc/apt/sources.list
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
2.2 獲取Golang安裝文件
獲取網址為:https://gomirrors.org/
使用最新的Go1.14.4版本 : https://gomirrors.org/dl/go/go1.14.4.linux-amd64.tar.gz
2.3 Dockerfile
Dockerfile文件內容為:
FROM ubuntu:18.04
VOLUME /opt/go_docker/
WORKDIR /go_workspace
COPY ./src ./
COPY ./entry.sh ./
COPY sources.list /etc/apt/sources.list
ENTRYPOINT [ "sh", "./entry.sh" ]
2.3 entry.sh
echo "bash"
# 更新軟件源ls
apt-get update
# 安裝交叉編譯庫
apt install g++-aarch64-linux-gnu -y
apt install gcc-aarch64-linux-gnu -y
# 添加此選項可以避免一個go run時的一個錯誤,錯誤描述為:
# X509
apt install ssh -y
# 解壓並安裝golang
tar -xvf go1.14.4.linux-amd64.tar.gz -C /usr/local
export PATH=$PATH:/usr/local/go/bin
echo $PATH
# 設置golang為國內代理
go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.io,direct
bash
2.4 src文件夾內容
.
├── build.sh
├── go1.14.4.linux-amd64.tar.gz #golang安裝文件
├── go.mod # 使用 go mod init utils 生成
├── go.sum # go run max_client.go 自動創建
└── hello.go # 源代碼文件
2.5 hello.go
package main
import (
"log"
"github.com/gorilla/websocket"
)
func main() {
go recv_message("ws://127.0.0.1:2303/maxcount")
for {
}
}
func recv_message(ws_url string) {
log.Println("Dial To:", ws_url)
conn, _, err := websocket.DefaultDialer.Dial(ws_url, nil)
if err != nil {
log.Fatal("Dial Error:", err)
}
defer conn.Close()
for {
message_type, message_data, err := conn.ReadMessage()
if err != nil {
log.Println("ReadMessage Error:", err)
break
}
log.Printf("Recv [%v] : [%s]", message_type, message_data)
break
}
}
2.6 build.sh
export CGO_ENABLED=1
export GOOS=linux
export GOARCH=arm64
export GOARM=7
export BINARY_NAME=agent
# export CC=/usr/bin/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc
# export CXX=/usr/bin/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++
export CC=/usr/bin/aarch64-linux-gnu-gcc
export CXX=/usr/bin/aarch64-linux-gnu-g++
go build -o ./bin/${BINARY_NAME}_${GOOS}_${GOARCH}_${GOARM} ./hello.go
2.6 運行指令
#進入docker環境后,執行
sh build.sh
#會在bin目錄下創建 agent_linux_arm64_7文件
3 測試運行
為了測試編譯的arm執行文件是否可以正確運行,需要搭建arm的docker運行環境,步驟如下:
3.1 在宿主機安裝 qemu
sudo apt install qemu-user-static -y
3.2 建立Dockerfile
FROM arm64v8/ubuntu
VOLUME /opt/go_docker/
WORKDIR /go_workspace
COPY ./src ./
ENTRYPOINT [ "bash" ]
3.2 運行docker
sudo docker run -it --name service_test -v /usr/bin/qemu-aarch64-static:/usr/bin/qemu-aarch64-static service_test:v1.0
3.3 運行結果
2020/07/08 13:30:24 Dial To: ws://127.0.0.1:2303/maxcount
2020/07/08 13:30:24 Recv [1] : [1594186224]
4. 存在問題
其實里面還存在一個問題,但我僅僅在程序內
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello Golang")
}
編譯出的程序是不能運行的,原因是編譯出的程序為statically linked
,暫時還不能解決此問題。
(base) wanhy@wanhy-ubuntu:~/Project/backer777_github/go_workspace/test_docker_golang/test_build2/src$ file agent_linux_arm64_7
agent_linux_arm64_7: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, not stripped
(base) wanhy@wanhy-ubuntu:~/Project/backer777_github/go_workspace/test_docker_golang/test_build2/src$ file agent_linux_arm64_7_cc
agent_linux_arm64_7_cc: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, not stripped