在 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(如我):您只需设置 GOOSGOARCH 环境变量并运行 go build。

对于那些更懒惰的复制粘贴者(比如我),如果你在 *nix 系统上,请执行以下操作:

env GOOS=linux GOARCH=arm go build -v github.com/path/to/your/app

您甚至学会了 env 技巧,它让您只为该命令设置环境变量,完全免费。

【讨论】:

env 命令仅在自定义环境中运行该调用,并在完成后“重置”它。例如运行export GOOS=windows,然后运行带有或不带有envecho $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?的主要内容,如果未能解决你的问题,请参考以下文章

在linux上交叉编译opencv踩过的坑

关于Mac上交叉编译几个小问题,求解答

在ubuntu上交叉编译Boost 1.57.0 for arm

windows上交叉编译go程序

在 Ubuntu 中在 32 位上交叉编译 64 位程序时缺少包含“bits/c++config.h”

使用 arm-apple-darwin10-llvm-gcc-4.2 在 MacOS 上交叉编译问题