如何在Linux上编译跨平台的Go语言项目?

4
我正在尝试在Linux上设置我的Go编译器,以便为任何其他架构或平台编译项目。我使用的是来自官方Ubuntu 14.04仓库的默认软件包,并且我正在使用64位系统。这种配置只允许我编译64位Linux系统。至少我想为32位Linux甚至为32位Windows系统进行编译。有可能吗?
另外,我想使用两个Go绑定: https://github.com/mattn/go-gtkhttps://github.com/mattn/go-webkit 我正在使用go-webkit示例代码进行测试。
package main

import (
    "os"
    "github.com/mattn/go-gtk/gtk"
    "github.com/mattn/go-webkit/webkit"
)

const HTML_STRING = `
<doctype html>
<meta charset="utf-8"/>
<style>
div { font-size: 5em }
</style>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
$(function() {
    $('#hello1').slideDown('slow', function() {
        $('#hello2').fadeIn()
    })
})
</script>
<div id="hello1" style="display: none">Hello</div>
<div id="hello2" style="display: none">世界</div>
</div>
`

const MAP_EMBED = `
<style> *{ margin : 0; padding : 0; } </style>
<iframe width="100%" height="100%" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="http://maps.google.co.jp/maps?f=q&amp;source=s_q&amp;hl=en&amp;geocode=&amp;q=osaka&amp;aq=&amp;sll=34.885931,-115.180664&amp;sspn=29.912003,39.506836&amp;brcurrent=3,0x6000e86b2acc70d7:0xa399ff48811f596d,0&amp;ie=UTF8&amp;hq=&amp;hnear=%E5%A4%A7%E9%98%AA%E5%BA%9C%E5%A4%A7%E9%98%AA%E5%B8%82&amp;ll=34.693738,135.502165&amp;spn=0.471406,0.617294&amp;z=11&amp;output=embed"></iframe>
`

func main() {
    gtk.Init(nil)
    window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
    window.SetTitle("webkit")
    window.Connect("destroy", gtk.MainQuit)

    vbox := gtk.NewVBox(false, 1)

    entry := gtk.NewEntry()
    entry.SetText("http://golang.org/")
    vbox.PackStart(entry, false, false, 0)

    swin := gtk.NewScrolledWindow(nil, nil)
    swin.SetPolicy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
    swin.SetShadowType(gtk.SHADOW_IN)

    webview := webkit.NewWebView()
    webview.Connect("load-committed", func() {
        entry.SetText(webview.GetUri())
    })
    swin.Add(webview)

    vbox.Add(swin)

    entry.Connect("activate", func() {
        webview.LoadUri(entry.GetText())
    })
    button := gtk.NewButtonWithLabel("load String")
    button.Clicked(func() {
        webview.LoadString("hello Go GTK!", "text/plain", "utf-8", ".")
    })
    vbox.PackStart(button, false, false, 0)

    button = gtk.NewButtonWithLabel("load HTML String")
    button.Clicked(func() {
        webview.LoadHtmlString(HTML_STRING, ".")
    })
    vbox.PackStart(button, false, false, 0)

    button = gtk.NewButtonWithLabel("Google Maps")
    button.Clicked(func() {
        webview.LoadHtmlString(MAP_EMBED, ".")
    })
    vbox.PackStart(button, false, false, 0)

    window.Add(vbox)
    window.SetSizeRequest(600, 600)
    window.ShowAll()

    proxy := os.Getenv("HTTP_PROXY")
    if len(proxy) > 0 {
        soup_uri := webkit.SoupUri(proxy)
        webkit.GetDefaultSession().Set("proxy-uri", soup_uri)
        soup_uri.Free()
    }
    entry.Emit("activate")
    gtk.Main()
}

如果我使用以下方式编译,它可以很好地工作:

go build

如果我尝试使用其他设置进行编译:
GOOS=windows GOARCH=386 go build
GOARCH=386 go build

我收到了以下错误信息:

webview.go:5:2: 在 /home/yeeapple/Documents/Coding/Go/Source/src/github.com/mattn/go-gtk/gtk 目录中没有可编译的 Go 源文件。

webview.go:6:2: 在 /home/yeeapple/Documents/Coding/Go/Source/src/github.com/mattn/go-webkit/webkit 目录中没有可编译的 Go 源文件。

此外,我注意到在 GOPATH 目录和 pkg 文件夹中只有 "linux_amd64" 文件夹和 *.a 文件。
例如,如果没有额外的导入,我可以为其他系统编译 Go 文件。跨平台编译使用正常:
package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

版本:

$ go version
go version go1.2.1 linux/amd64

$ gccgo --version
gccgo (Ubuntu 4.9-20140406-0ubuntu1) 4.9.0 20140405 (experimental) [trunk revision 209157]
Copyright (C) 2014 Free Software Foundation, Inc.

这不是一个答案,但你可能想尝试类似GoXC (https://github.com/laher/goxc) 的工具。如果你是新手,它很容易上手。 - Intermernet
我已经成功地向跨平台编译迈出了一步。我下载了Go 1.3并在src文件夹中运行了make.bash来制作引导程序。当我尝试为Windows 32位编译时,我收到了这个消息(使用CGO_ENABLED=1):

runtime/cgo

gcc: error: unrecognized command line option ‘-mthreads’
- user1621987
1个回答

6
在 Go 1.2 版本中,当进行交叉编译时,cgo 功能会被禁用。这意味着任何包含 import "C" 的源代码文件都将不会被编译,这将导致许多包无法使用。因此,尽管简单的“hello world”程序可以编译,但使用 cgo 的等效程序将会失败。
package main

/*
#include <stdlib.h>
#include <stdio.h>
*/
import "C"
import "unsafe"

func main() {
        hello := C.CString("Hello world")
        defer C.free(unsafe.Pointer(hello))
        C.puts(hello)
}

在amd64 Linux系统上,如果您尝试为x86编译,则会出现构建失败。
$ GOARCH=386 go build hello.go
can't load package: no buildable Go source files in /...

为了使这个程序编译通过,您还需要设置环境变量CGO_ENABLED=1以手动启用cgo。这将导致它尝试编译该程序,但如果您没有安装x86编译器,它仍然会失败。由于您说您正在使用Ubuntu,因此可以通过安装gcc-multilib软件包来解决这个问题。
$ sudo apt-get install gcc-multilib

安装完成后,您应该能够编译程序:
$ GOARCH=386 CGO_ENABLED=1 go build hello.go
$ file hello
hello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=..., not stripped

虽然Ubuntu自带Windows交叉编译工具链(在mingw32包中),但您仍然会遇到编译Windows二进制文件的问题:
$ GOOS=windows GOARCH=386 CGO_ENABLED=1 go build hello.go 
go build runtime/cgo: cannot use cgo when compiling for a different operating system

这个检查在GO 1.3中不再存在,因此您可能会在该版本中有所收获。
现在拥有交叉编译工具链只是战斗的一部分:您还需要为目标架构编译的依赖项版本。对于像WebKit这样的大型项目,这不会很容易,但您可以使用环境变量CFLAGS、LDFLAGS和PKG_CONFIG_PATH将Go指向适当的副本。

谢谢。这对我很有帮助,但它并没有解决跨平台编译的问题。我认为Go语言(v1.3)目前还没有完全支持跨平台编译。 - user1621987
我发现go-gtk和go-webkit库存在一些问题,在Go 1.3下无法正常工作。我接受这个答案。 - user1621987

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接