Golang跨平台交叉编译

近期在某本书上看到Go跨平台交叉编译的强大功能,于是想自己测试一下。以下记录了测试过程以及一些结论,希望能给大家带来帮助。

我的Linux环境如下:

uname -a
Linux Ubuntu-Server-14 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

$ go version
go version go1.3.1 linux/amd64

跨平台交叉编译涉及两个重要的环境变量:GOOS和GOARCH,分别代表Target Host OS和Target Host ARCH,如果没有显式设置这些环境变量,我们通过go env可以看到go编译器眼中这两个环境变量的当前值:

$ go env
GOARCH="amd64"
GOOS="linux"

GOHOSTARCH="amd64"
GOHOSTOS="linux"

… …

这里还有两个变量GOHOSTOS和GOHOSTARCH,分别表示的是当前所在主机的的OS和CPU ARCH。我的Go是采用安装包安装的,因此默认情况下,这两组环境变量的值都是来自当前主机的信息。

现在我们就来交叉编译一下:在linux/amd64平台下利用Go编译器编译一个可以运行在linux/amd64下的程序,样例程序如下:

//testport.go
package main

import (
        "fmt"
        "os/exec"
        "bytes"
)

func main() {
        cmd := exec.Command("uname", "-a")
        var out bytes.Buffer
        cmd.Stdout = &out

        err := cmd.Run()
        if err != nil {
                fmt.Println("Err when executing uname command")
                return
        }

        fmt.Println("I am running on", out.String())
}

在Linux/amd64下编译运行:

$ go build -o testport_linux testport.go
$ testport_linux
I am running on Linux ubuntu-Server-14 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

接下来,我们来尝试在Linux/amd64上编译一个可以运行在darwin/amd64上的程序。我只需修改GOOS和GOARCH两个标识目标主机OS和ARCH的环境变量:

$ GOOS=darwin GOARCH=amd64 go build -o testport_darwin testport.go
go build runtime: darwin/amd64 must be bootstrapped using make.bash

编译器报错了!提示darwin/amd64必须通过make.bash重新装载。显然,通过安装包安装到linux/amd64下的Go编译器还无法直接交叉编译出darwin/amd64下可以运行的程序,我们需要做一些准备工作。我们找找make.bash在哪里!

我们到Go的$GOROOT路径下去找make.bash,Go的安装路径下的组织很简约,扫一眼便知make.sh大概在$GOROOT/src下,打开make.sh,我们在文件头处看到如下一些内容:

# Environment variables that control make.bash:
#
# GOROOT_FINAL: The expected final Go root, baked into binaries.
# The default is the location of the Go tree during the build.
#
# GOHOSTARCH: The architecture for host tools (compilers and
# binaries).  Binaries of this type must be executable on the current
# system, so the only common reason to set this is to set
# GOHOSTARCH=386 on an amd64 machine.
#
# GOARCH: The target architecture for installed packages and tools.
#
# GOOS: The target operating system for installed packages and tools.

… …

make.bash头并未简要说明文件的用途,但名为make.xx的文件想必是用来构建Go编译工具的。这里提到几个环境变量可以控制 make.bash的行为,显然GOARCH和GOOS更能引起我们的兴趣。我们再回过头来输出testport.go编译过程的详细信息:

$ go build -x -o testport_linux testport.go
WORK=/tmp/go-build286732099
mkdir -p $WORK/command-line-arguments/_obj/
cd /home/linuxidc/Test/Go/porting
/usr/local/go/pkg/tool/linux_amd64/6g -o $WORK/command-line-arguments.a -trimpath $WORK -p command-line-arguments -complete -D _/home/linuxidc/Test/Go/porting -I $WORK -pack ./testport.go
cd .
/usr/local/go/pkg/tool/linux_amd64/6l -o testport_linux -L $WORK -extld=gcc $WORK/command-line-arguments.a

我们发现Go实际上用的是$GOROOT/pkg/tool/linux_amd64下的6g(编译器)和6l(链接器)来完成整个编译过程的,看到6g 和6l所在目录名为linux_amd64,我们可以大胆猜测编译darwin/amd64 go程序应该使用的是$GOROOT/pkg/tool/darwin_amd64下的工具。不过在我在$GOROOT/pkg/tool下没有发现 darwin_amd64目录,也就是说我们通过安装包安装的Go仅自带了for linux_amd64的编译工具,要想交叉编译出for darwin_amd64的程序,我们需要通过make.bash来手工编译出这些工具。

linuxidc@ubuntu-Server-14:/usr/local/go/pkg$ ls
linux_amd64  linux_amd64_race  obj  tool

linuxidc@ubuntu-Server-14:/usr/local/go/pkg/tool$ ls
linux_amd64

根据前面make.bash的用法说明,我们来尝试构建一下:

cd $GOROOT/src
sudo GOOS=darwin GOARCH=amd64 ./make.bash

# Building C bootstrap tool.
cmd/dist

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/1104587e48c58665a85241c7134c63a1.html