在 OSX 上交叉编译 Go?
Posted
技术标签:
【中文标题】在 OSX 上交叉编译 Go?【英文标题】:Cross compile Go on OSX? 【发布时间】:2012-08-23 12:41:00 【问题描述】:我正在尝试在 OSX 上交叉编译一个 go 应用程序来为 windows 和 linux 构建二进制文件。我已经阅读了我在网上可以找到的所有内容。我发现的最接近的例子已经发布(除了关于 go-nuts 邮件列表的许多未完成的讨论):
http://solovyov.net/en/2012/03/09/cross-compiling-go/
但它不适用于我的安装。我已经去了 1.0.2。由于 1.0.2 是最近的版本,在我看来以上所有示例都不适用于此版本。
尝试在 ENV vars 设置为 386/windows 的情况下执行./make.bash --no-clean
,它确实构建了 go,但是它为我的安装构建了 go,它是 darwin/amd64
,并且完全忽略了 ENV 中设置的假设构建不同编译器的内容。
任何建议如何完成(如果可以完成的话)?
【问题讨论】:
与此平行,我在 golang-nuts 邮件列表上提出了同样的问题,在人们的善意帮助和耐心的帮助下,最终的食谱已经完成......这是讨论主题:groups.google.com/forum/?fromgroups=#!topic/golang-nuts/… 那里有几个步骤和结论,我在路上弄错了,但现在配方看起来很简单 - 3 个步骤和一些迭代。 现在我要回顾一下,我想知道为什么 ENV vars 没有触发正确的编译 - 可能是因为我做了sudo
(很可能我会在 sudo-ing 时得到不同的 unix ENV 所以 GOOS & GOARCH 将不可用,如果它们没有内联完成)
re: jdi - 我只是想将我的“模型”go 应用程序编译为 mac 上的 win/lin 二进制文件,但是,要做到这一点,我必须为每个平台组合构建 go 本身/处理器。 (还不能回答我自己的问题 - 这里没有足够的声誉)
您是否准确输入了示例中的内容? CGO_ENABLED=0 GOOS=windows GOARCH=amd64 ./make.bash
- 如果您尝试将其拆分为多行,则不会导出符合症状的环境变量
确保您没有混淆主机和目标架构。您应该会看到以下输出:“#Building compilers and Go bootstrap tool for host, darwin/amd64.” "# 为主机 darwin/amd64 构建包和命令。" "# 为 windows/386 构建包和命令。"
【参考方案1】:
在 Go 1.5 中,他们似乎改进了交叉编译过程,这意味着它现在是内置的。不需要./make.bash
-ing 或brew
-ing。该过程描述为here,但对于那里的 TLDR-ers(如我):您只需设置 GOOS
和 GOARCH
环境变量并运行 go build。
对于那些更懒惰的复制粘贴者(比如我),如果你在 *nix 系统上,请执行以下操作:
env GOOS=linux GOARCH=arm go build -v github.com/path/to/your/app
您甚至学会了 env
技巧,它让您只为该命令设置环境变量,完全免费。
【讨论】:
env
命令仅在自定义环境中运行该调用,并在完成后“重置”它。例如运行export GOOS=windows
,然后运行带有或不带有env
和echo $GOOS
的命令。使用env
,GOOS 没有改变。
没有env
也是如此(至少在Bash中)。我跑了export GOOS=windows
,然后是GOOS=linux bash -c 'echo "GOOS: $GOOS"'
,然后是echo "GOOS: $GOOS"
。 env
是否提供与其他 shell 方言或其他平台更大的兼容性?如果不是,这里似乎是多余的。
@davidchambers 在 BASH 中它们是等价的。在其他一些壳牌中,例如FISH shell,它不支持FOO=bar cmd
,所以你必须使用env FOO=bar cmd
。因此我认为使用env FOO=bar cmd
的最大优势是兼容性。
难以置信的答案就在这里。你解决了我的问题,教了我一个新技巧,让我自嘲。
很好的答案,谢谢!为了在 heroku (intel x86) 上编译使用,我将行稍微修改为 env GOOS=linux GOARCH=386 go build -v github.com/path/to/your/app
,它就像一个冠军【参考方案2】:
感谢 golang-nuts 的善意和耐心帮助,配方如下:
1) 需要为不同的目标平台和架构编译 Go 编译器。这是从 go 安装中的 src 文件夹完成的。就我而言,Go 安装位于 /usr/local/go
中,因此要编译编译器,您需要发出 make
实用程序。在执行此操作之前,您需要了解一些注意事项。
交叉编译时CGO库有问题,需要禁用CGO库。
通过将位置更改为源目录来完成编译,因为编译必须在该文件夹中完成
cd /usr/local/go/src
然后编译 Go 编译器:
sudo GOOS=windows GOARCH=386 CGO_ENABLED=0 ./make.bash --no-clean
您需要通过更改 GOOS 和 GOARCH 参数,对您希望交叉编译的每个操作系统和架构重复此步骤。
如果您像我一样在用户模式下工作,则需要 sudo,因为 Go 编译器位于系统目录中。否则,您需要以超级用户身份登录。在 Mac 上,您可能需要启用/配置 SU 访问权限(默认情况下不可用),但如果您已成功安装 Go,您可能已经拥有 root 访问权限。
2) 构建完所有交叉编译器后,您可以愉快地使用以下设置交叉编译您的应用程序:
GOOS=windows GOARCH=386 go build -o appname.exe appname.go
GOOS=linux GOARCH=386 CGO_ENABLED=0 go build -o appname.linux appname.go
将 GOOS 和 GOARCH 更改为您希望构建的目标。
如果您遇到 CGO 问题,请在命令行中包含 CGO_ENABLED=0。另请注意,用于 linux 和 mac 的二进制文件没有扩展名,因此您可以添加扩展名以获得不同的文件。 -o 开关指示 Go 生成类似于 c/c++ 的旧编译器的输出文件,因此上面使用的 appname.linux 可以是任何其他扩展名。
【讨论】:
最初让我感到困惑的是,在编译的第一部分 make 说:# Building compilers and Go bootstrap tool for host, darwin/amd64
但后来它实际上以:--- Installed Go for windows/386 in /usr/local/go Installed commands in /usr/local/go/bin
结束,所以人们应该观察编译器的结束而不是开始。
一切都从尝试做开始:$ GOARCH=386 GOOS=linux go build app.go
并得到错误# runtime /usr/local/go/src/pkg/runtime/extern.go:137: undefined: theGoos /usr/local/go/src/pkg/runtime/extern.go:137: cannot use theGoos as type string in const initializer
Go 的 Homebrew 包有一个选项“--cross-compile-all”,它会自动构建所有的交叉编译器。
伟大的提示@nimrodm!要重新编译你的 go 安装,你需要运行 brew reinstall go --cross-compile-all
@ljgww 'sudo' 没有配置 ENV。我最终在 /usr/local/go/pkg/linux_amd64/ 上使用了 chown【参考方案3】:
如果您在 OS X 上使用Homebrew,那么您有一个更简单的解决方案:
$ brew install go --with-cc-common # Linux, Darwin, and Windows
或者..
$ brew install go --with-cc-all # All the cross-compilers
如果您已经安装了go
,请使用reinstall
。
【讨论】:
注意更新的开关是: --cross-compile-all 为所有支持的平台构建交叉编译器和运行时支持 --cross-compile-common 为darwin构建交叉编译器和运行时支持, linux和windows--cross-compile-all
现在是--with-cc-all
@sheeks06 - 已修复。谢谢!
据我所知,这些标志不再存在。我看到的唯一相关选项是 --without-cgo :(
从 Go 1.5 开始,没有单独的交叉编译器,你现在只能使用标志 tip.golang.org/doc/go1.5#compiler_and_tools【参考方案4】:
您可以使用 Docker 轻松完成此操作,因此不需要额外的库。只需运行以下命令:
docker run --rm -it -v "$GOPATH":/go -w /go/src/github.com/iron-io/ironcli golang:1.4.2-cross sh -c '
for GOOS in darwin linux windows; do
for GOARCH in 386 amd64; do
echo "Building $GOOS-$GOARCH"
export GOOS=$GOOS
export GOARCH=$GOARCH
go build -o bin/ironcli-$GOOS-$GOARCH
done
done
'
您可以在这篇文章中找到更多详细信息: https://medium.com/iron-io-blog/how-to-cross-compile-go-programs-using-docker-beaa102a316d
【讨论】:
当他们可以在env GOOS=x GOARCH=y go install something/...
上执行一个shell 循环并最终在$GOPATH/bin/$GOOS_$GOARCH
下得到适当的二进制文件时,为什么有人想要安装Docker 来执行此操作?顺便说一句,Go 支持的操作系统不止您列出的三个操作系统,为什么不喜欢 BSD?
你不会安装 Docker 只是为了做到这一点,但如果你有它,这比替代品更容易、更干净。【参考方案5】:
为许多平台创建可执行文件的过程可能有点乏味,所以我建议使用脚本:
#!/usr/bin/env bash
package=$1
if [[ -z "$package" ]]; then
echo "usage: $0 <package-name>"
exit 1
fi
package_name=$package
#the full list of the platforms: https://golang.org/doc/install/source#environment
platforms=(
"darwin/386"
"dragonfly/amd64"
"freebsd/386"
"freebsd/amd64"
"freebsd/arm"
"linux/386"
"linux/amd64"
"linux/arm"
"linux/arm64"
"netbsd/386"
"netbsd/amd64"
"netbsd/arm"
"openbsd/386"
"openbsd/amd64"
"openbsd/arm"
"plan9/386"
"plan9/amd64"
"solaris/amd64"
"windows/amd64"
"windows/386" )
for platform in "$platforms[@]"
do
platform_split=($platform//\// )
GOOS=$platform_split[0]
GOARCH=$platform_split[1]
output_name=$package_name'-'$GOOS'-'$GOARCH
if [ $GOOS = "windows" ]; then
output_name+='.exe'
fi
env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package
if [ $? -ne 0 ]; then
echo 'An error has occurred! Aborting the script execution...'
exit 1
fi
done
我只在 OSX 上检查过这个脚本
gist - go-executable-build.sh
【讨论】:
正是我要找的...我已经将它 docker 化了 :) gist.github.com/marcellodesales/…【参考方案6】:适用于需要启用 CGO 并从 OSX 定位进行交叉编译的人 窗户
我需要 CGO 在从我的 mac 编译 Windows 时启用,因为我已经导入了 https://github.com/mattn/go-sqlite3 并且它需要它。 根据其他答案编译给了我和错误:
/usr/local/go/src/runtime/cgo/gcc_windows_amd64.c:8:10: fatal error: 'windows.h' file not found
如果您像我一样,必须使用 CGO 进行编译。这就是我所做的:
1.我们将为具有 CGO 依赖库的 windows 进行交叉编译。首先我们需要安装一个交叉编译器,比如mingw-w64
brew install mingw-w64
这可能会在这里安装它/usr/local/opt/mingw-w64/bin/
。
2.就像其他答案一样,我们现在首先需要将我们的 windows arch 添加到我们的 go 编译器工具链中。编译一个编译器需要一个编译器(奇怪的句子)编译go编译器需要一个单独的预建编译器。我们可以下载预构建的二进制文件或从文件夹中的源代码构建,例如:~/Documents/go
现在我们可以根据最佳答案改进我们的 Go 编译器,但这次使用 CGO_ENABLED=1
和我们单独的预编译编译器 GOROOT_BOOTSTRAP
(Pooya 是我的用户名):
cd /usr/local/go/src
sudo GOOS=windows GOARCH=amd64 CGO_ENABLED=1 GOROOT_BOOTSTRAP=/Users/Pooya/Documents/go ./make.bash --no-clean
sudo GOOS=windows GOARCH=386 CGO_ENABLED=1 GOROOT_BOOTSTRAP=/Users/Pooya/Documents/go ./make.bash --no-clean
3.现在在编译我们的 Go 代码时,使用 mingw
来编译我们启用 CGO 的 go 文件目标窗口:
GOOS="windows" GOARCH="386" CGO_ENABLED="1" CC="/usr/local/opt/mingw-w64/bin/i686-w64-mingw32-gcc" go build hello.go
GOOS="windows" GOARCH="amd64" CGO_ENABLED="1" CC="/usr/local/opt/mingw-w64/bin/x86_64-w64-mingw32-gcc" go build hello.go
【讨论】:
【参考方案7】:从 go 1.17.1 开始,您必须显式设置 go env 变量。
我已经在 shell 脚本中完成了
#!/bin/bash
GOOS=linux
GOARCH=amd64
go.exe get -d -v ./...
go.exe env -w GOOS=$GOOS
go.exe env -w GOARCH=$GOARCH
go.exe build -v ./cmd/tecnoalarm/main.go
【讨论】:
【参考方案8】:适用于需要启用 CGO 并从另一个系统进行交叉编译的人
有一个docker解决方案golang-crossbuild
这是在 Windows/MacOS 上构建 linux/armv7
的一个示例
docker run -it --rm \
-v $GOPATH/src/github.com/user/go-project:/go/src/github.com/user/go-project \
-w /go/src/github.com/user/go-project \
-e CGO_ENABLED=1 \
docker.elastic.co/beats-dev/golang-crossbuild:1.16.4-armhf \
--build-cmd "make build" \
-p "linux/armv7"
【讨论】:
以上是关于在 OSX 上交叉编译 Go?的主要内容,如果未能解决你的问题,请参考以下文章
在ubuntu上交叉编译Boost 1.57.0 for arm