Go Wiki: Gccgo交叉编译

引言

如果您想在标准Go编译器gc不支持的平台上运行Go程序,您可以构建一个针对您期望的目标平台的GCC编译器版本,因为GCC支持的平台要多得多。这是可能的,因为有一个名为gccgo的GCC的Go前端。

详细信息

定义

  • 构建 (Build) 这是您正在构建交叉编译器的计算机。
  • 主机 (Host) 构建完成后将运行交叉编译器的计算机。这通常与构建计算机相同。
  • 目标 (Target) 这是目标系统,您希望交叉编译的程序在该系统上运行。

有关更多定义和复杂交叉编译情况,请参阅Wikipedia文章

Go工具和gccgo

稍后您需要Go工具的源代码,所以最好卸载您从包管理器安装的版本以避免混淆(完全可选)。同时构建并安装针对主机(host)的gccgo(是的,您需要一个不仅为目标而且也为主机编译的gccgo)。

构建交叉编译器

构建

首先,您必须构建您的交叉编译版本的GCC。这是一个复杂的过程,因为它需要几个阶段的引导(bootstrapping),因为GCC和libc实现之间存在相互依赖关系。Jim Blandy撰写了一篇非常好的教程,介绍了如何使用eglibc(也可与glibc一起使用)构建GCC交叉工具链,并发布在eglibc的邮件列表中,标题为patches Cross-building instructions。在构建完整GCC的最后阶段,只需使用–enable-languages=c,c++,go配置脚本(请参阅官方Go文档)。

您可以将ewxb_gcc_cross-compiler_builder脚本作为起点。不要期望该脚本能够立即正常工作,而是将其作为构建x-toolchain可能采取的步骤的提示。

如果您足够幸运,并且想要一个不是最新的GCC版本(您可能希望拥有最新的Go功能),您可以使用交叉编译器构建工具来简化配置,例如crosstool-NG,它允许您通过一个简单的TUI菜单配置GCC。

较新版本的crosstool-NG可以通过启用CT_EXPERIMENTALCT_CC_SUPPORT_GOLANG来构建Go语言。这将自动将go添加到--enable-languages

现在您应该有一个bin目录,其中包含诸如“<target>-gcc”、“<target>-gnu-gccgo”等文件。因为go构建工具不允许您指定要使用的编译器的文件名(仅静态支持字符串‘gc’和‘gccgo’),它会在您的$PATH环境变量中查找第一个名为‘gccgo’和‘gcc’的文件。因此,当您想使用交叉编译器而不是系统上的普通gcc二进制文件时,您必须通过将其设置为$PATH中的第一个目录来添加此目录作为覆盖。由于go工具查找名为gccgo的二进制文件,您将必须创建一些符号链接,以便它能找到所需的工具。

    $ cd path/to/cross-comp-gcc/bin
    $ ln -s <arch>-<os>-gnu-gcc gcc 
    $ ln -s <arch>-<os>-gnu-gccgo gccgo
    $ ln -s <arch>-<os>-gnu-ar ar
    $ export PATH="path/to/crosscomp-gcc/bin:$PATH" # Do this whenever you want to use the cross-compilers targeting your target instead of the system default targeting host.

等等。

将$TARGET设置为目标体系结构,$PREFIX设置为构建文件的目标路径,您可以使用以下命令创建符号链接:

##!/usr/bin/env bash        

cd $PREFIX/bin
for file in $(find . -type f); do       
    tool_name=$(echo $file | sed -e "s/${TARGET}-\(.*\)$/\1/")      
    ln -sf "$file" "$tool_name"         
done

Test

当交叉编译器构建完成后,您应该测试它是否正常工作,包括一个简单的C程序和一个简单的Go程序。

    $ gccgo -Wall -o helloworld helloworld.go
    $ file helloworld # verify that the architecture of the binary is the desired target and not a binary that can run on your host machine.
    $ <upload-command-to-target> helloworld
    $ <ssh/telnet etc. to target and test run>

注意事项

如果您没有为您目标编译Go库(libgo)的共享对象,您可能希望像gc一样静态编译Go程序,以包含运行程序所需的所有内容。通过将-static开关添加到gccgo来完成此操作。如果您不确定生成的ELF文件是如何链接的,请使用readelf -d <elf>objdump -T <elf>进行检查。

构建一个支持交叉gccgo的Go工具版本

假设

  • 假设您已按照从源代码安装Go上的说明进行操作,您应该在$GOROOT中有一个已签出的Go源代码版本。
  • 环境变量$GOROOT已设置。
  • 环境变量$GOARCH$GOOS代表**目标**体系结构和操作系统。在想要交叉编译时,找出它们并将其设置为这些值。

构建

您可以使用go build -compiler gccgo <go-package,files>指定构建时使用的编译器。但这还不够。如果您设置的$GOARCH$GOOSgc不支持的,但gccgo支持的,那么您必须构建一个特殊的Go工具版本,该版本能够理解这些额外的体系结构。如果您使用go工具编译另一个版本的go工具,并指定使用针对主机的gccgo,则生成的go工具将能够编译所有gccgo支持的体系结构的程序。

    $ cd ~/tmp
    $ hg clone ~/src/go # [0]
    $ cd go/src/cmd/go
    $ go build -o xgo -compiler gccgo . # [1] [2] [3]
    $ cp xgo ~/bin/ # Or any directory that is in your $PATH
  • [0] 将Go源代码克隆到$GOROOT目录之外的目录。这是必需的,因为我们将要编译的cmd/go文件被特殊处理。
  • [1] 这里必须使用**主机**的gccgo,而不是交叉编译的gccgo。确保您的$PATH设置正确。
  • [2] 将生成一个名为xgo的二进制文件,以区别于现有的go二进制文件。将其命名为合适的名称,例如,如果您的目标是MIPS,则命名为mgo。
  • [3] 编译步骤(go build)可能会因一些编译错误而失败,因为gccgo落后于go项目(至少在go mercurial tip 7f2863716967时是这样)。通过注释掉错误或采取更聪明的办法来修复这些错误,然后重新编译。

交叉编译Go程序。

将您的$PATH设置为能够找到_xgo_和交叉编译版本的_gccgo,并将$GOARCH设置正确,您现在就可以使用go工具(命名为xgo)进行交叉编译了。

    $ export PATH="path/to/xgo/:path/to/crosscomp-gccgo/:$PATH"
    $ export GOARCH="<you-target's-arch>"
    $ export GOOS="<you-target's-OS>"
    $ xgo build -compiler gccgo <go-package/files>

待办事项

使用xgo时,导入“C”的Go程序似乎不起作用。目前受Go issue#7398的限制。

此Wiki页面受到“[golang-nuts] MIPS交叉编译的简化?”@ https://groups.google.com/forum/#!topic/golang-nuts/PgyS2yoO2jM中学到的经验的启发。


此内容是 Go Wiki 的一部分。