如何在Ubuntu20.04上为多个平台构建Go可执行文件

来自菜鸟教程
跳转至:导航、​搜索

介绍

Go 编程语言 带有丰富的工具链,使获取包和构建可执行文件变得异常容易。 Go 最强大的功能之一是能够为任何支持 Go 的外国平台交叉构建可执行文件。 这使得测试和包分发变得更加容易,因为您无需访问特定平台即可为其分发包。

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

先决条件

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

第 1 步——创建一个简单的 Go 程序

现在 Go 已安装,您可以尝试创建 Hello, World!

首先,为您的 Go 工作区创建一个新目录,Go 将在该目录中构建其文件:

mkdir hello

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

cd hello

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

go mod init hello

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

nano hello.go

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

你好.go

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

然后,按 CTRL+X,然后按 Y,然后按 ENTER 保存并关闭文件。

测试您的代码以检查它是否打印 Hello, World! 问候语:

go run .
OutputHello, World!

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

第 2 步 - 构建可执行文件

go run 命令运行“Hello, World!”的代码程序,但您可能希望将程序构建为二进制文件,以便在系统上的任何位置运行,而不仅仅是从源代码运行。 go build 命令构建可执行文件。

go build hello

和以前一样,没有输出表示操作成功。 可执行文件将在您的当前目录中生成,与包含该包的目录同名。 在这种情况下,可执行文件将被命名为 hello

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

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

go build -o build/hello hello

此命令创建可执行文件,如果 ./build 目录不存在,还会创建它。

现在让我们看看安装可执行文件。

第 3 步 — 安装可执行文件

构建可执行文件会在当前目录或您选择的目录中创建可执行文件。 安装可执行文件是创建可执行文件并将其存储在 $GOPATH/bin 中的过程。 go install 命令的工作方式与 go build 类似,但 go install 负责将输出文件放置在适合您的位置。

要安装可执行文件,请使用 go install,后跟包导入路径。 再一次,使用你的“Hello, World!” 程序来试试这个:

go install hello

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

which hello

您将看到以下输出:

Output of which/home/sammy/go/bin/hello

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

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

go build 命令让您可以在您的平台 上为任何支持 Go 的目标平台 构建可执行文件。 这意味着您可以测试、发布和分发您的应用程序,而无需在您希望使用的目标平台上构建这些可执行文件。

交叉编译通过设置指定目标操作系统和体系结构的所需环境变量来工作。 我们将变量 GOOS 用于目标操作系统,将 GOARCH 用于目标架构。 要构建可执行文件,该命令将采用以下形式:

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

在运行 go build 命令之前设置操作系统和架构。 这使您可以仅将环境变量用于当前命令执行。 命令执行后变量未设置或重置。

为了找出可用于构建可执行文件的操作系统和平台,您可以使用 dist 工具:

go tool dist list

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

Outputaix/ppc64
android/386
android/amd64
android/arm
android/arm64
darwin/amd64
darwin/arm64
dragonfly/amd64
freebsd/386
freebsd/amd64
freebsd/arm
freebsd/arm64
illumos/amd64
ios/amd64
ios/arm64
js/wasm
linux/386
linux/amd64
linux/arm
linux/arm64
linux/mips
linux/mips64
linux/mips64le
linux/mipsle
linux/ppc64
linux/ppc64le
linux/riscv64
linux/s390x
netbsd/386
netbsd/amd64
netbsd/arm
netbsd/arm64
openbsd/386
openbsd/amd64
openbsd/arm
openbsd/arm64
openbsd/mips64
plan9/386
plan9/amd64
plan9/arm
solaris/amd64
windows/386
windows/amd64
windows/arm

警告: 为 Android 交叉编译可执行文件需要 Android NDK,以及一些超出本教程范围的额外设置。


使用列表中的值,我们可以为 Windows 64 位构建 hello,如下所示:

GOOS=windows GOARCH=amd64 go build hello

再一次,没有输出表明操作成功。 可执行文件将在当前目录中创建,使用包名作为其名称。 但是,由于我们为 Windows 构建了这个可执行文件,所以名称以后缀 .exe 结尾。

您的当前目录中应该有一个 hello.exe 文件,您可以使用 ls 命令对其进行验证。

ls hello.exe

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

Outputhello.exe

注意:您可以使用 -o 标志重命名可执行文件或将其放置在不同的位置。 但是,在为 Windows 构建可执行文件并提供不同名称时,请务必在设置可执行文件名称时明确指定 .exe 后缀。


让我们看一下编写此过程的脚本,以便更轻松地为多个目标环境发布软件。

第 5 步 — 创建脚本以自动进行交叉编译

为许多平台创建可执行文件的过程可能有点乏味,但我们可以创建一个脚本来让事情变得更简单。

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

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

nano go-executable-build.bash

我们将从 shebang 行开始我们的脚本。 这一行定义了当它作为可执行文件运行时哪个解释器将解析这个脚本。 添加以下行以指定 bash 应执行此脚本:

go-executable-build.bash

#!/usr/bin/env bash

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

go-executable-build.bash

...
package=$1

接下来,确保用户提供了此值。 如果未提供该值,请退出脚本并显示说明如何使用脚本的消息:

go-executable-build.bash

...

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

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

注意:如果你想让这个脚本使用预定义的包,改变package变量指向那个导入路径:

go-executable-build.bash

...
package="github.com/user/hello"

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

go-executable-build.bash

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

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

go-executable-build.bash

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

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

go-executable-build.bash

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

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

go-executable-build.bash

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

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

go-executable-build.bash

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

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

go-executable-build.bash

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 创建可执行文件。 将此行添加到 for 循环的主体,就在 done 关键字上方:

go-executable-build.bash

...
    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 关键字上方。

go-executable-build.bash

...

    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 包构建多个可执行文件。 这是完成的脚本:

go-executable-build.bash

#!/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

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

./go-executable-build.bash hello

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

ls hello*

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

Example ls outputhello-darwin-amd64 hello-windows-386.exe hello-windows-amd64.exe

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

结论

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

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

为确保您的应用程序正常运行,您可以查看 testingcontinuous integration like Travis-CI and AppVeyor for testing在 Windows 上。