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

huangapple go评论93阅读模式
英文:

How to compile cross-platform Go language project on Linux?

问题

我正在尝试在Linux上设置我的Go编译器,以便可以为任何其他架构或平台编译项目。我正在使用来自官方Ubuntu 14.04软件仓库的默认软件包,并且我正在使用64位系统。这个配置只允许我编译适用于Linux的64位系统。至少我想要编译适用于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.
英文:

I am trying to set up my Go compiler on Linux which could compile project for any other architecture or platform. I am using default packages from official Ubuntu 14.04 repositories and I am using 64 bit system. This configuration allows me to compile only for Linux and only for 64 bit system. At least I would like to compile for 32 bit Linux or even for 32 bit Windows systems. Is it possible to do somehow?

One additional thing is I want to use two Go bindings:
https://github.com/mattn/go-gtk and https://github.com/mattn/go-webkit

I was testing with go-webkit example code:

package main
import (
&quot;os&quot;
&quot;github.com/mattn/go-gtk/gtk&quot;
&quot;github.com/mattn/go-webkit/webkit&quot;
)
const HTML_STRING = `
&lt;doctype html&gt;
&lt;meta charset=&quot;utf-8&quot;/&gt;
&lt;style&gt;
div { font-size: 5em }
&lt;/style&gt;
&lt;script src=&quot;http://code.jquery.com/jquery-latest.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
$(function() {
$(&#39;#hello1&#39;).slideDown(&#39;slow&#39;, function() {
$(&#39;#hello2&#39;).fadeIn()
})
})
&lt;/script&gt;
&lt;div id=&quot;hello1&quot; style=&quot;display: none&quot;&gt;Hello&lt;/div&gt;
&lt;div id=&quot;hello2&quot; style=&quot;display: none&quot;&gt;世界&lt;/div&gt;
&lt;/div&gt;
`
const MAP_EMBED = `
&lt;style&gt; *{ margin : 0; padding : 0; } &lt;/style&gt;
&lt;iframe width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; src=&quot;http://maps.google.co.jp/maps?f=q&amp;amp;source=s_q&amp;amp;hl=en&amp;amp;geocode=&amp;amp;q=osaka&amp;amp;aq=&amp;amp;sll=34.885931,-115.180664&amp;amp;sspn=29.912003,39.506836&amp;amp;brcurrent=3,0x6000e86b2acc70d7:0xa399ff48811f596d,0&amp;amp;ie=UTF8&amp;amp;hq=&amp;amp;hnear=%E5%A4%A7%E9%98%AA%E5%BA%9C%E5%A4%A7%E9%98%AA%E5%B8%82&amp;amp;ll=34.693738,135.502165&amp;amp;spn=0.471406,0.617294&amp;amp;z=11&amp;amp;output=embed&quot;&gt;&lt;/iframe&gt;
`
func main() {
gtk.Init(nil)
window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)
window.SetTitle(&quot;webkit&quot;)
window.Connect(&quot;destroy&quot;, gtk.MainQuit)
vbox := gtk.NewVBox(false, 1)
entry := gtk.NewEntry()
entry.SetText(&quot;http://golang.org/&quot;)
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(&quot;load-committed&quot;, func() {
entry.SetText(webview.GetUri())
})
swin.Add(webview)
vbox.Add(swin)
entry.Connect(&quot;activate&quot;, func() {
webview.LoadUri(entry.GetText())
})
button := gtk.NewButtonWithLabel(&quot;load String&quot;)
button.Clicked(func() {
webview.LoadString(&quot;hello Go GTK!&quot;, &quot;text/plain&quot;, &quot;utf-8&quot;, &quot;.&quot;)
})
vbox.PackStart(button, false, false, 0)
button = gtk.NewButtonWithLabel(&quot;load HTML String&quot;)
button.Clicked(func() {
webview.LoadHtmlString(HTML_STRING, &quot;.&quot;)
})
vbox.PackStart(button, false, false, 0)
button = gtk.NewButtonWithLabel(&quot;Google Maps&quot;)
button.Clicked(func() {
webview.LoadHtmlString(MAP_EMBED, &quot;.&quot;)
})
vbox.PackStart(button, false, false, 0)
window.Add(vbox)
window.SetSizeRequest(600, 600)
window.ShowAll()
proxy := os.Getenv(&quot;HTTP_PROXY&quot;)
if len(proxy) &gt; 0 {
soup_uri := webkit.SoupUri(proxy)
webkit.GetDefaultSession().Set(&quot;proxy-uri&quot;, soup_uri)
soup_uri.Free()
}
entry.Emit(&quot;activate&quot;)
gtk.Main()
}

It works fine if I compile it with

go build

If I try to compile it with other settings:

GOOS=windows GOARCH=386 go build
GOARCH=386 go build

I get this error:

> webview.go:5:2: no buildable Go source files in
> /home/yeeapple/Documents/Coding/Go/Source/src/github.com/mattn/go-gtk/gtk
>
> webview.go:6:2: no buildable Go source files in
> /home/yeeapple/Documents/Coding/Go/Source/src/github.com/mattn/go-webkit/webkit

Another thing I saw is that in GOPATH directory and pkg folder is only "linux_amd64" folder with *.a files.

For example, I can compile Go files for other systems if it does not have additional imports. Cross-platform compiling works fine with:

package main
import &quot;fmt&quot;
func main() {
fmt.Printf(&quot;hello, world\n&quot;)
}

Versions:

$ 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.

答案1

得分: 6

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

在amd64 Linux系统上,如果你尝试为x86编译,将会出现构建失败的情况:

要使该程序能够编译,你还需要设置环境变量CGO_ENABLED=1来手动启用cgo。这将导致它尝试编译程序,但如果你没有安装x86编译器,它仍然会失败。由于你说你正在使用Ubuntu,你可以通过安装gcc-multilib软件包来实现:

安装完成后,你应该能够编译该程序:

虽然Ubuntu带有一个用于Windows交叉编译的工具链(在mingw32软件包中),但你仍然会遇到编译Windows可执行文件的问题:

GO 1.3版本中不再进行此检查,所以你可能会在该版本中有一些运气。

现在,拥有交叉编译工具链只是战斗的一部分:你还需要为目标架构编译的依赖项的版本可用。对于像WebKit这样庞大的项目来说,这并不容易,但你可以使用CFLAGSLDFLAGSPKG_CONFIG_PATH环境变量来指定Go使用适当的副本。

英文:

With Go 1.2, the cgo feature is disabled when cross compiling code. This means that any source file containing import &quot;C&quot; will not be compiled, which leaves many packages unusable. So while your simple "hello world" program compiles, an equivalent one using cgo will fail:

package main
/*
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
*/
import &quot;C&quot;
import &quot;unsafe&quot;
func main() {
hello := C.CString(&quot;Hello world&quot;)
defer C.free(unsafe.Pointer(hello))
C.puts(hello)
}

On an amd64 Linux system, you will get a build failure if you try to compile for x86:

$ GOARCH=386 go build hello.go
can&#39;t load package: no buildable Go source files in /...

To get this program to compile, you will also need to set the environment variable CGO_ENABLED=1 to manually enable cgo. This will cause it to attempt to compile the program, but it will still fail if you don't have an x86 compiler installed. Since you said you are using Ubuntu, you can do this by installing the gcc-multilib package:

$ sudo apt-get install gcc-multilib

With that installed, you should be able to compile the program:

$ 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

While Ubuntu comes with a Windows cross compile tool chain (in the mingw32 package), you'll still have trouble compiling Windows binaries:

$ 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

This check is no longer present in GO 1.3, so you may have some luck with that release.

Now having the cross-compiler tool chain available is only part of the battle: you will also need versions of the your dependencies compiled for the target architecture(s) available. This isn't going to be trivial for something as big as WebKit, but you could probably point Go at an appropriate copy using the CFLAGS, LDFLAGS and PKG_CONFIG_PATH environment variables.

huangapple
  • 本文由 发表于 2014年6月22日 19:17:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/24350698.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定