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

介绍

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

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

先决条件

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

第1步 - 从版本控制安装Go程序

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

go get命令的语法是go get package-import-path package-import-path是唯一标识包的字符串。 它通常是远程存储库(如Github)中的软件包位置,也是计算机上$GOPATH/src/目录中的$GOPATH/src/

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

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

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

该命令将需要一些时间才能完成,但是在获取软件包并进行安装时,您将看不到任何进度。 没有输出实际上表示命令执行成功。

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

which caddy

您将看到以下输出:

Output/home/sammy/work/bin/caddy

注意go get命令从Git存储库的默认分支安装软件包,在许多情况下,它们是master或in-development分支。 在使用go get之前,请务必查看通常位于存储库的README文件中的说明。

您可以使用Git命令(如git checkout为使用go get命令go get源选择不同的分支。 查看教程如何使用Git分支机构了解有关如何切换分支的更多信息。

让我们来看看安装Go软件包的过程,从创建我们已经获得的软件包的可执行文件开始。

第2步 - 构建可执行文件

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

虽然我们已经安装了卡迪,但是我们可以手动重新构建它,以便我们可以很方便地了解该过程。 执行go build并指定包导入路径:

go build github.com/mholt/caddy/caddy

如前所述,没有输出表示操作成功。 该可执行文件将在当前目录中生成,与包含该目录的目录名称相同。 在这种情况下,可执行文件将被命名为卡迪。

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

要为可执行文件指定不同的名称或位置,请使用-o标志。 我们来构建一个名为caddy-server的可执行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 ,然后使用包导入路径。 再次,使用凯蒂尝试这样做:

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 getgo buildgo install工作以及它们的相关性,让我们探索一个最受欢迎的Go功能:为其他目标平台创建可执行文件。

第4步 - 构建不同架构的可执行文件

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

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

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

env命令在修改的env运行程序。 这允许您仅使用环境变量来执行当前命令执行。 命令执行后,变量未设置或重置。

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

GOOS - 目标操作系统 GOARCH - 目标平台
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构建了此可执行文件,所以该名称以Postfix.exe结尾。

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

ls caddy.exe

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

Outputcaddy.exe

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

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

第5步 - 创建自动交叉编译的脚本

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

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

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

cd ~
nano go-executable-build.bash

我们将开始我们的脚本与shebang线。 该行定义哪个解释器在作为可执行文件运行时解析此脚本。 添加以下行以指定bash应执行此脚本:

去可执行-build.bash
#!/usr/bin/env bash

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

去可执行-build.bash
...
package=$1

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

去可执行-build.bash
...

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

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

注意 :如果要使此脚本与预定义的包一起使用,请将package变量更改为指向该导入路径:

去可执行-build.bash
...
package="github.com/user/hello"

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

去可执行-build.bash
package_split=(${package//\// })

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

去可执行-build.bash
...
package_name=${package_split[-1]}

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

去可执行-build.bash
...
platforms=("windows/amd64" "windows/386" "darwin/amd64")

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

去可执行-build.bash
...
for platform in "${platforms[@]}"
do
    ...
done

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

去可执行-build.bash
for platform in "${platforms[@]}"
do
    platform_split=(${platform//\// })
    GOOS=${platform_split[0]}
    GOARCH=${platform_split[1]}

done

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

去可执行-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关键字的上方:

去可执行-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关键字之上。

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

去可执行-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 outputcaddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe

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

结论

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

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

为确保您的应用程序正常运行,您可以查看Travis-CIAppVeyor的测试和持续集成 ,以便在Windows上进行测试。

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

赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏