引言

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

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

先决条件

要遵循本教程,你需要:

  • 根据 Ubuntu 16.04初始服务器设置指南设置一个 Ubuntu 16.04服务器,包括一个 sudo 非 root 用户和一个防火墙。
  • 如何在 Ubuntu 16.04上安装 Go 1.6。

第一步ー从版本控制安装 Go 程序

在从 Go 包创建可执行文件之前,我们必须获得它的源代码。 Go get 工具可以从诸如 GitHub 这样的版本控制系统中获取软件包。 在引擎盖下,将克隆包放入 $gopath / src / 目录的子目录中。 然后,如果适用,它通过构建其可执行文件并将其放置在 $gopath / bin 目录中来安装包。 如果您按照先决条件教程中的描述配置了 Go,$gopath / bin 目录将包含在 $PATH 环境变量中,这确保您可以从系统的任何地方使用安装的包。

Go get 命令的语法是 go get package-import-path。 Package-import-path 是唯一标识包的字符串。 它通常是包在诸如 Github 这样的远程存储库中的位置,或者是在机器上的 $gopath / src / 目录中的目录。

使用 go get with-u 标志是很常见的,它指示 go get 获取包及其依赖项,或者更新那些已经存在于计算机上的依赖项。

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

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

这个命令需要一些时间才能完成,但是当它取出并安装包时,您不会看到任何进展。 没有任何输出实际上表明成功执行的命令。

当命令完成后,您可以在 $gopath / src / github 上找到 Caddy 的源代码。 Com / mholt / caddy. 此外,由于 Caddy 有一个可执行文件,所以它被自动创建并存储在 $gopath / bin 目录中。 通过打印可执行文件的位置来验证这一点:

  • which caddy

您将看到以下输出:

Output
/home/sammy/work/bin/caddy
注意: go get 命令从 Git 存储库的缺省分支安装包,在许多情况下,该分支是主存储库或在开发分支。 在使用 go get 之前,请确保查看说明(通常位于存储库的 README 文件中)。 您可以使用像 Git checkout 这样的 Git 命令在使用 go get 命令获得的源上选择不同的分支。 查看教程如何使用 Git 分支来学习更多关于如何切换分支的知识。

让我们更详细地了解一下 Go 软件包的安装过程,首先从已经获得的软件包创建可执行文件开始。

步骤2ー构建可执行文件

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

虽然我们已经安装了 Caddy,但是让我们手动再次构建它,这样我们就可以熟悉这个过程。 执行 go build 并指定包导入路径:

  • go build github.com/mholt/caddy/caddy

与前面一样,没有输出表明操作成功。 可执行文件将在您的工作目录文件夹中生成,并使用与包含包的目录相同的名称。 在这种情况下,可执行文件将被命名为 caddy。

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

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

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

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

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

第三步ー安装可执行文件

构建一个可执行文件会在工作目录文件或者你选择的目录中创建一个可执行文件。 安装可执行文件是创建可执行文件并将其存储在 $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 caddy

您将看到以下输出:

Output of which
/home/sammy/work/bin/caddy

现在您已经了解了 Go get、 Go build 和 Go install 工作,以及它们之间的关系,接下来让我们探索一个最流行的 Go 特性: 为其他目标平台创建可执行文件。

第四步ー为不同的体系结构构建可执行文件

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

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

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

Env 命令在一个修改过的环境中运行一个程序。 这使您只能对当前命令的执行使用环境变量。 在命令执行后,变量被取消设置或重置。

下表显示了你可以使用的 GOOS 和 GOARCH 的可能组合:

GOOS - Target Operating System GOARCH - Target Platform
android arm
darwin 386
darwin amd64
darwin arm
darwin arm64
dragonfly amd64
freebsd 386
freebsd amd64
freebsd arm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux mips
linux mipsle
linux mips64
linux mips64le
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
plan9 386
plan9 amd64
solaris amd64
windows 386
windows amd64
警告: Android 的交叉编译可执行文件需要 Android NDK 和一些额外的设置,这超出了本教程的范围。

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

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

同样,没有输出表明操作成功。 这个可执行文件将在工作目录中创建,使用包名作为它的名称。 但是,因为我们为 Windows 构建了这个可执行文件,所以名称以后缀结尾。 执行。

你应该在你的工作目录中有 cady.exe 文件,你可以用 ls 命令来验证。

  • ls caddy.exe

你会在输出中看到列出的 cady.exe 文件:

Output
caddy.exe

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

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

第五步ー创建一个自动化交叉编译的脚本

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

该脚本将包导入路径作为参数,迭代预定义的操作系统和平台对列表,并为每个对生成一个可执行文件,将输出放置在工作目录文件夹中。 在表单 package-OS-architecture 中,每个可执行文件都将以包名称命名,后面跟着目标平台和体系结构。 这将是一个通用脚本,您可以在任何项目中使用。

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

  • cd ~
  • 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,因为脚本不成功。

注意: 如果希望使这个脚本与预定义的包一起工作,请将包变量更改为指向导入路径: go-executable-build。 Bash... 软件包“ github. com / user / hello”

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

go-executable-build.bash
package_split=(${package//\// })

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

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

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

go-executable-build.bash
...
platforms=("windows/amd64" "windows/386" "darwin/amd64")

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

go-executable-build.bash
...
for platform in "${platforms[@]}"
do
    ...
done

平台变量将在每次迭代中包含来自平台数组的条目。 我们需要将平台划分为两个变量: GOOS 和 GOARCH。 在 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

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

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

如果一切顺利,你应该在你的工作目录 / 项目中拥有可执行文件。 没有输出表明脚本执行成功。 您可以验证是否使用 ls 命令创建了可执行文件:

  • ls caddy*

你应该看到这三个版本:

Example ls output
caddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe

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

总结

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

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

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

如果你对 Caddy 和如何使用它感兴趣,看看如何在 Ubuntu 16.04上用 Caddy 管理网站。