如何在 Ubuntu 16.04 上为多个平台构建 Go 可执行文件

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站

简介

Go 编程语言配备了丰富的工具链,使得获取包和构建可执行文件变得非常容易。Go 最强大的特性之一是能够为任何 Go 支持的外部平台交叉构建可执行文件。这使得测试和包分发变得更加容易,因为您不需要访问特定平台就能为其分发您的包。

在本教程中,您将使用 Go 的工具来从版本控制获取包并自动安装其可执行文件。然后,您将手动构建和安装可执行文件,以便熟悉该过程。接着,您将为不同架构构建一个可执行文件,并自动化构建过程以创建多个平台的可执行文件。完成后,您将知道如何为 Windows 和 macOS 构建可执行文件,以及其他您想要支持的平台。

先决条件

要完成本教程,您需要:

  • 通过遵循 Ubuntu 16.04 初始服务器设置指南设置好的一个 Ubuntu 16.04 服务器,包括一个具有 sudo 非根用户和防火墙。
  • 已安装 Go,如《如何在 Ubuntu 16.04 上安装 Go 1.6》中所述。

步骤 1 —— 从版本控制安装 Go 程序

在我们可以从 Go 包创建可执行文件之前,我们必须获取其源代码。go get 工具可以从 GitHub 等版本控制系统中获取包。在幕后,go get 将包克隆到 $GOPATH/src/ 目录的子目录中。然后,如果适用,它会通过构建其可执行文件并将其放置在 $GOPATH/bin 目录中来安装包。如果您按照先决条件教程中的说明配置了 Go,那么 $GOPATH/bin 目录将包含在您的 $PATH 环境变量中,这可以确保您可以从系统的任何位置使用已安装的包。

go get 命令的语法是 go get package-import-pathpackage-import-path 是一个唯一标识包的字符串。它通常是包在远程存储库(如 GitHub)中的位置,或者是您机器上 $GOPATH/src/ 目录中的一个目录。

通常会使用 go get-u 标志一起使用,该标志指示 go get 获取包及其依赖项,或者如果它们已经存在于机器上,则更新这些依赖项。

在本教程中,我们将安装一个用 Go 编写的 Web 服务器 Caddy。根据 Caddy 的说明,我们将使用 github.com/mholt/caddy/caddy 作为包导入路径。使用 go get 来获取并安装 Caddy:

go get -u github.com/mholt/caddy/caddy

该命令将花费一些时间来完成,但在获取包并安装它时,您不会看到任何进度。实际上,没有任何输出表明命令执行成功。

当命令完成时,您将在 $GOPATH/src/github.com/mholt/caddy 找到 Caddy 的源代码。此外,由于 Caddy 有一个可执行文件,它会自动创建并存储在 $GOPATH/bin 目录中。通过使用 which 命令来打印可执行文件的位置来验证这一点:

which caddy

您将看到以下输出:


/home/sammy/work/bin/caddy

让我们更详细地了解安装 Go 包的过程,从已经获取的包中创建可执行文件开始。

步骤 2 —— 构建可执行文件

go get 命令以单个命令下载了源代码并为我们安装了 Caddy 的可执行文件。但您可能希望重新构建可执行文件,或者从您自己的代码构建可执行文件。go build 命令用于构建可执行文件。

尽管我们已经安装了 Caddy,让我们再次手动构建它,以便熟悉该过程。执行 go build 并指定包导入路径:

go build github.com/mholt/caddy/caddy

与之前一样,没有输出表示成功操作。可执行文件将在当前目录中生成,与包含包的目录同名。在本例中,可执行文件将被命名为 caddy

如果您位于包目录中,可以省略包的路径,直接运行 go build

要为可执行文件指定不同的名称或位置,请使用 -o 标志。让我们构建一个名为 caddy-server 的可执行文件,并将其放置在当前工作目录中的 build 目录中:

go build -o build/caddy-server github.com/mholt/caddy/caddy

该命令将创建可执行文件,并且如果该目录不存在,则会创建 ./build 目录。

现在让我们来看一下安装可执行文件的过程。

步骤 3 — 安装可执行文件

构建可执行文件会在当前目录或指定目录中创建可执行文件。安装可执行文件是指创建可执行文件并将其存储在 $GOPATH/bin 中的过程。go install 命令的工作方式与 go build 相似,但 go install 会为您处理好将输出文件放在正确位置的工作。

要安装可执行文件,使用 go install,后面跟上包导入路径。再次使用 Caddy 来尝试这一过程:

go install github.com/mholt/caddy/caddy

go build 一样,如果命令成功,您将看不到任何输出。与之前一样,可执行文件的名称与包含该包的目录名称相同。但是这次,可执行文件存储在 $GOPATH/bin 中。如果 $GOPATH/bin 是您的 $PATH 环境变量的一部分,那么该可执行文件将可以在操作系统的任何位置使用。您可以使用 which 命令验证其位置:

which caddy

您将看到以下输出:

[secondary_label Output of which]
/home/sammy/work/bin/caddy

现在您已经了解了 go getgo buildgo install 的工作原理以及它们之间的关系,让我们来探索 Go 中最受欢迎的功能之一:为其他目标平台创建可执行文件。

步骤 4 — 为不同架构构建可执行文件

go build 命令允许您为任何 Go 支持的目标平台在您的平台上构建可执行文件。这意味着您可以在不构建目标平台上的可执行文件的情况下测试、发布和分发您的应用程序。

交叉编译是通过设置指定目标操作系统和架构的必要环境变量来实现的。我们使用变量 GOOS 来指定目标操作系统,GOARCH 来指定目标架构。构建可执行文件的命令如下:

env GOOS=target-OS GOARCH=target-architecture go build package-import-path

env 命令在修改后的环境中运行程序。这使您可以仅对当前命令执行使用环境变量。这些变量在命令执行后被取消或重置。

下表显示了您可以使用的 GOOSGOARCH 的可能组合:

GOOS - 目标操作系统GOARCH - 目标平台
androidarm
darwin386
darwinamd64
darwinarm
darwinarm64
dragonflyamd64
freebsd386
freebsdamd64
freebsdarm
linux386
linuxamd64
linuxarm
linuxarm64
linuxppc64
linuxppc64le
linuxmips
linuxmipsle
linuxmips64
linuxmips64le
netbsd386
netbsdamd64
netbsdarm
openbsd386
openbsdamd64
openbsdarm
plan9386
plan9amd64
solarisamd64
windows386
windowsamd64

使用表中的值,我们可以这样为 Windows 64 位构建 Caddy:

env GOOS=windows GOARCH=amd64 go build github.com/mholt/caddy/caddy

再次,如果操作成功,将不会有任何输出。可执行文件将在当前目录中创建,使用包名称作为其名称。但是,由于我们为 Windows 构建了此可执行文件,因此名称以后缀 .exe 结尾。

您应该在当前目录中有 caddy.exe 文件,您可以使用 ls 命令进行验证。

ls caddy.exe

您将在输出中看到 caddy.exe 文件列出:


caddy.exe

让我们来看一下如何编写脚本来简化发布多个目标环境的软件。

步骤 5 —— 创建一个脚本来自动进行交叉编译

为多个平台创建可执行文件的过程可能有点繁琐,但我们可以创建一个脚本来简化这个过程。

该脚本将以包导入路径作为参数,遍历预定义的操作系统和平台对列表,并为每个对生成一个可执行文件,将输出放在当前目录中。每个可执行文件的命名方式为包名称,后跟目标平台和架构,形式为 package-OS-architecture。这将是一个通用脚本,您可以在任何项目中使用。

切换到您的主目录并在文本编辑器中创建一个名为 go-executable-build.bash 的新文件:

cd ~
nano go-executable-build.bash

我们将以 shebang 行开始我们的脚本。该行定义了在以可执行文件形式运行时将解析此脚本的解释器。添加以下行以指定 bash 应执行此脚本:

#!/usr/bin/env bash

我们希望将包导入路径作为命令行参数。为此,我们将使用 $n 变量,其中 n 是非负数。变量 $0 包含您执行的脚本的名称,而 $1 及更大的值将包含用户提供的参数。添加以下行到脚本中,它将从命令行中获取第一个参数并将其存储在名为 package 的变量中:

...
package=$1

接下来,确保用户提供了这个值。如果未提供该值,则使用一条消息解释如何使用该脚本退出脚本:

...

if [[ -z "$package" ]]; then
  echo "usage: $0 <package-name>"
  exit 1
fi

if 语句检查 $package 变量的值。如果它未设置,我们使用 echo 打印正确的用法,然后使用 exit 终止脚本。exit 接受一个返回值作为参数,对于成功执行应为 0,对于不成功执行应为任何非零值。这里我们使用 1,因为脚本执行不成功。

接下来,我们要从路径中提取包名称。包导入路径由 / 字符分隔,包名称位于路径的末尾。首先,我们将使用 / 作为分隔符,将包导入路径拆分为数组:

package_split=(${package//\// })

包名称应该是这个新的 $package_split 数组的最后一个元素。在 Bash 中,您可以使用负数组索引来访问数组的末尾而不是开头。添加以下行以从数组中获取包名称并将其存储在名为 package_name 的变量中:

...
package_name=${package_split[-1]}

现在,您需要决定要为哪些平台和架构构建可执行文件。在本教程中,我们将为 Windows 64 位、Windows 32 位和 64 位 macOS 构建可执行文件。我们将这些目标放在一个格式为 OS/Platform 的数组中,因此我们可以使用相同的方法将每个对拆分为 GOOSGOARCH 变量。将这些平台添加到脚本中:

...
platforms=("windows/amd64" "windows/386" "darwin/amd64")

接下来,我们将遍历平台数组,将每个平台条目拆分为 GOOSGOARCH 环境变量的值,并使用这些值构建可执行文件。我们可以使用以下 for 循环来实现:

...
for platform in "${platforms[@]}"
do
	...
done

在每次迭代中,platform 变量将包含来自 platforms 数组的一个条目。我们需要将 platform 拆分为两个变量 - GOOSGOARCH。在 for 循环中添加以下行:

for platform in "${platforms[@]}"
do
	platform_split=(${platform//\// })
	GOOS=${platform_split[0]}
	GOARCH=${platform_split[1]}
	
done

接下来,我们将通过将包名称与操作系统和架构组合来生成可执行文件的名称。当我们为 Windows 构建时,还需要向文件名添加 .exe 后缀。在 for 循环中添加以下代码:

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
done

设置好变量后,我们使用 go build 创建可执行文件。在 done 关键字上方将以下行添加到 for 循环的主体中:

...
	if [ $GOOS = "windows" ]; then
		output_name+='.exe'
	fi
	
	env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package

done

最后,我们应该检查是否有错误构建可执行文件。例如,如果我们尝试构建我们没有源代码的包,可能会遇到错误。我们可以检查 go build 命令的返回代码是否为非零值。变量 $? 包含上一个命令执行的返回代码。如果 go build 返回除 0 以外的任何值,就表示出现了问题,我们将希望退出脚本。在 for 循环中,将以下代码添加到 go build 命令之后,done 关键字之前。

...

	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

现在,我们有一个可以从我们的 Go 包构建多个可执行文件的脚本。以下是完成的脚本:

#!/usr/bin/env bash

package=$1
if [[ -z "$package" ]]; then
  echo "usage: $0 <package-name>"
  exit 1
fi
package_split=(${package//\// })
package_name=${package_split[-1]}
	
platforms=("windows/amd64" "windows/386" "darwin/amd64")

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

验证您的文件是否与上述代码匹配。然后保存文件并退出编辑器。

在使用脚本之前,我们必须使用 chmod 命令使其可执行:

chmod +x go-executable-build.bash

最后,通过为 Caddy 构建可执行文件来测试脚本:

./go-executable-build.bash github.com/mholt/caddy/caddy

如果一切顺利,您应该在当前目录中有可执行文件。没有输出表示脚本执行成功。您可以使用 ls 命令验证是否创建了可执行文件:

ls caddy*

您应该看到所有三个版本:

[secondary_label Example ls output]
caddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe

要更改目标平台,只需更改脚本中的 platforms 变量。

结论

在本教程中,您学习了如何使用 Go 的工具从版本控制系统获取软件包,以及为不同平台构建和交叉编译可执行文件。

您还创建了一个可以用于为多个平台交叉编译单个软件包的脚本。

为了确保您的应用程序正常工作,您可以查看测试持续集成,如 Travis-CI 和 AppVeyor 用于在 Windows 上进行测试。

如果您对 Caddy 及其使用感兴趣,请查看《如何在 Ubuntu 16.04 上使用 Caddy 托管网站》。

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白如意i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值