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

介绍

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

在本教程中,您将使用Go的工具从版本控制中获取一个包,并自动安装其可执行的程序,然后您将手动构建和安装可执行的程序,以便您熟悉该过程。

前提条件

要遵循本教程,您将需要:

步骤1 - 创建一个简单的Go程序

现在安装了 Go,您可以尝试创建您的你好,世界!

首先,为您的 Go 工作区创建一个新目录,这就是 Go 将其文件构建的地方:

1mkdir hello

然后进入您刚刚创建的目录:

1cd hello

导入包时,您必须通过代码的自身模块来管理依赖性,您可以通过使用go mod init命令创建一个go.mod文件来做到这一点:

1go mod init hello

接下来,在您喜爱的文本编辑器中创建一个Hello, World!Go文件:

1nano hello.go

将以下文本添加到您的hello.go文件中:

1[label hello.go]
2package main
3
4import "fmt"
5
6func main() {
7    fmt.Println("Hello, World!")
8}

然后,通过按CTRL+X,然后按Y,然后按ENTER来保存和关闭文件。

测试您的代码,检查它是否打印了你好,世界!的问候:

1go run .
1[secondary_label Output]
2Hello, World!

go run命令编译并从您创建的新hello目录和您导入的路径的.go源文件列表中运行Go包,但您也可以使用go build创建可执行的文件,从而节省您一些时间。

步骤 2 — 构建一个可执行的

Go Run命令为您的Hello World!程序运行了代码,但您可能希望将您的程序构建成二进制来在您的系统上运行,而不仅仅是从源头。

1go build hello

如前所述,没有输出表示成功操作. 可执行的将生成在当前目录中,与包含包的目录相同的名称。

如果您位于包目录中,您可以跳过通往包的路径,然后简单地运行去构建

要指定可执行的不同的名称或位置,请使用-o旗帜. 让我们构建一个名为hello的可执行,并将其放置在当前工作目录中的构建目录中:

1go build -o build/hello hello

此命令会创建可执行的文件,并在不存在的情况下创建 `./build’ 目录。

现在让我们来看看安装 executables。

步骤 3 — 安装一个可执行的

构建可执行文件会在当前目录或您选择的目录中创建可执行文件. 安装可执行文件是创建可执行文件并将其存储在$GOPATH/bin中。

要安装一个可执行的,请使用去安装,然后使用包导入路径. 再一次,请使用您的Hello, World!程序来尝试:

1go install hello

就像「Go build」一樣,如果命令成功的話,你將不會看到任何輸出。 和以前一樣,執行程式的名稱與包含包的目錄相同,但這次執行程式儲存在「$GOPATH/bin」。 如果「$GOPATH/bin」是您的「$PATH」環境變量的一部分,執行程式將可在您的作業系統上任何地方使用。 您可以使用「哪個」命令來驗證其位置:

1which hello

您将看到以下输出:

1[secondary_label Output of which]
2/home/sammy/go/bin/hello

现在,你已经了解了go get,go buildgo install是如何工作的,以及它们是如何相关的,让我们探索最流行的Go功能之一:为其他目标平台创建可执行的功能。

步骤4 - 构建不同架构的执行程序

Go build命令允许您在您的平台上为任何 Go 支持的目标平台构建可执行文件,这意味着您可以测试,发布和分发您的应用程序,而不会在您想要使用的目标平台上构建这些可执行文件。

通过设置指定目标操作系统和架构的所需环境变量来进行交叉编译,我们使用目标操作系统的变量GOOS,目标架构的变量GOARCH

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

操作系统和架构在运行go build命令之前设置,这允许您仅使用当前命令执行的环境变量。

为了了解哪些操作系统和平台可用于构建可执行的,您可以使用dist工具:

1go tool dist list

这将为您提供由 / 字符分开的操作系统和架构列表:

 1[secondary_label Output]
 2aix/ppc64
 3android/386
 4android/amd64
 5android/arm
 6android/arm64
 7darwin/amd64
 8darwin/arm64
 9dragonfly/amd64
10freebsd/386
11freebsd/amd64
12freebsd/arm
13freebsd/arm64
14illumos/amd64
15ios/amd64
16ios/arm64
17js/wasm
18linux/386
19linux/amd64
20linux/arm
21linux/arm64
22linux/mips
23linux/mips64
24linux/mips64le
25linux/mipsle
26linux/ppc64
27linux/ppc64le
28linux/riscv64
29linux/s390x
30netbsd/386
31netbsd/amd64
32netbsd/arm
33netbsd/arm64
34openbsd/386
35openbsd/amd64
36openbsd/arm
37openbsd/arm64
38openbsd/mips64
39plan9/386
40plan9/amd64
41plan9/arm
42solaris/amd64
43windows/386
44windows/amd64
45windows/arm

金钱(警告)

警告: 跨编译的执行程序 Android 需要 Android NDK,和一些额外的设置,这是超出本教程的范围。

美元

使用列表中的值,我们可以像这样构建 64 位 Windows 的 Hello:

1GOOS=windows GOARCH=amd64 go build hello

再一次,没有输出表明操作是成功的。执行将创建在当前目录中,使用包名称作为其名称。

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

1ls hello.exe

您将看到输出中列出的 hello.exe 文件:

1[secondary_label Output]
2hello.exe

<$>[注] :您可以使用 -o 标志重新命名可执行的文件,或将其放置在不同的位置,但是,在为 Windows 构建可执行的文件并提供不同的名称时,请确保在设置可执行的名称时明确指定 .exe suffix。

让我们来看看这个过程的脚本,以便更容易为多个目标环境发布软件。

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

为许多平台创建可执行程序的过程可能有点无聊,但我们可以创建一个脚本来使事情变得更容易。

该脚本将采用包导入路径作为一个参数,通过预定义的操作系统和平台对列表迭代,并为每个对生成一个可执行的,将输出放置到当前目录中。

在项目目录中,在文本编辑器中创建一个名为go-executable-build.bash的新文件:

1nano go-executable-build.bash

我们将以 shebang 行开始我们的脚本. 该行定义了哪个解释器在作为可执行程序运行时将该脚本解析。

1[label go-executable-build.bash]
2#!/usr/bin/env bash

要做到这一点,我们将使用$n变量,其中n是一个非负数。$0变量包含你执行的脚本的名称,而$1和更大将包含用户提供的参数。

1[label go-executable-build.bash]
2...
3package=$1

接下来,请确保用户提供此值. 如果没有提供该值,请离开脚本,并发出说明如何使用脚本的消息:

1[label go-executable-build.bash]
2...
3
4if [[ -z "$package" ]]; then
5  echo "usage: $0 <package-name>"
6  exit 1
7fi

如果语句检查了$package变量的值。如果没有设置,我们会使用echo来打印正确的使用,然后使用exit终止脚本。

美元(注)

注意 :如果您想让此脚本与预定义的包一起工作,请更改变量以指向该导入路径:

1[label go-executable-build.bash]
2...
3package="github.com/user/hello"

美元

接下来,我们要从路径中提取包的名称。包的导入路径由 / 字符划分,而包的名称位于路径的尽头。

1[label go-executable-build.bash]
2package_split=(${package//\// })

该包名称应该是这个新的$package_split数组的最后一个元素。在Bash中,您可以使用负数组索引从末端访问一个数组,而不是从开始。

1[label go-executable-build.bash]
2...
3package_name=${package_split[-1]}

在本教程中,我们将构建 64 位 Windows、32 位 Windows 和 64 位 macOS 的执行程序. 我们将将这些目标放置在一个组合中,格式为OS/Platform,以便我们可以将每个对分为GOOSGOARCH变量,使用相同的方法从路径中提取包名称。

1[label go-executable-build.bash]
2...
3platforms=("windows/amd64" "windows/386" "darwin/amd64")

接下来,我们将重复通过平台的数组,将每个平台输入分为GOOSGOARCH环境变量的值,并使用这些来构建可执行的。

1[label go-executable-build.bash]
2...
3for platform in "${platforms[@]}"
4do
5    ...
6done

平台变量将在每个迭代中包含一个平台数组的输入,我们需要将平台分为两个变量,即GOOSGOARCH

1[label go-executable-build.bash]
2for platform in "${platforms[@]}"
3do
4    platform_split=(${platform//\// })
5    GOOS=${platform_split[0]}
6    GOARCH=${platform_split[1]}
7
8done

接下来,我们将通过将包名称与操作系统和架构相结合来生成可执行的名称. 当我们为 Windows 构建时,我们还需要在文件名中添加.exe字符串。

 1[label go-executable-build.bash]
 2for platform in "${platforms[@]}"
 3do
 4    platform_split=(${platform//\// })
 5    GOOS=${platform_split[0]}
 6    GOARCH=${platform_split[1]}
 7
 8    output_name=$package_name'-'$GOOS'-'$GOARCH
 9
10    if [ $GOOS = "windows" ]; then
11        output_name+='.exe'
12    fi
13done

随着变量设置,我们使用go build来创建可执行的行. 将此行添加到for循环的体内,直接在完成关键字上方:

1[label go-executable-build.bash]
2...
3    if [ $GOOS = "windows" ]; then
4        output_name+='.exe'
5    fi
6
7    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package
8
9done

最后,我们应检查一下是否存在可执行文件编制错误。 例如,如果我们试图构建一个我们没有来源的软件包,我们可能会遇到错误. 我们可以检查去建立命令的返回代码是否为非零值。 变数"$"? 包含来自先前命令执行的返回代码。 如果去建设'返回除0'以外的任何东西,就有一个问题,我们想退出剧本。 在去建立 ' 命令后,在去建立 ' 关键词上方,将这个代码添加到 " for " 循环中.

 1[label go-executable-build.bash]
 2
 3...
 4
 5    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package
 6
 7    if [ $? -ne 0 ]; then
 8           echo 'An error has occurred! Aborting the script execution...'
 9        exit 1
10    fi

有了这一点,我们现在有一个脚本,将从我们的Go包中构建多个执行程序。

 1[label go-executable-build.bash]
 2
 3#!/usr/bin/env bash
 4
 5package=$1
 6if [[ -z "$package" ]]; then
 7  echo "usage: $0 <package-name>"
 8  exit 1
 9fi
10package_split=(${package//\// })
11package_name=${package_split[-1]}
12
13platforms=("windows/amd64" "windows/386" "darwin/amd64")
14
15for platform in "${platforms[@]}"
16do
17    platform_split=(${platform//\// })
18    GOOS=${platform_split[0]}
19    GOARCH=${platform_split[1]}
20    output_name=$package_name'-'$GOOS'-'$GOARCH
21    if [ $GOOS = "windows" ]; then
22        output_name+='.exe'
23    fi    
24
25    env GOOS=$GOOS GOARCH=$GOARCH go build -o $output_name $package
26    if [ $? -ne 0 ]; then
27           echo 'An error has occurred! Aborting the script execution...'
28        exit 1
29    fi
30done

检查您的文件是否匹配前面的代码,然后保存文件并退出编辑器。

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

1chmod +x go-executable-build.bash

最后,通过构建 hello 的执行程序来测试脚本:

1./go-executable-build.bash hello

如果一切顺利,你应该在当前的目录中有可执行的内容. 没有输出显示了成功的脚本执行情况. 你可以通过使用ls命令来验证是否有可执行的内容:

1ls hello*

你应该看到这三个版本:

1[secondary_label Example ls output]
2hello-darwin-amd64 hello-windows-386.exe hello-windows-amd64.exe

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

结论

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

您还创建了一个脚本,您可以使用它来对多个平台进行单个包的交叉编译。

要确保您的应用程序正常工作,您可以查看 测试 和** 连续集成** 如 Travis-CIAppVeyor在 Windows 上进行测试。

Published At
Categories with 技术
comments powered by Disqus