介绍
Go编程语言带有丰富的工具链,可以轻松获取软件包和构建可执行文件。 Go最强大的功能之一是能够为任何Go支持的国外平台交叉构建可执行文件。 这使得测试和包分发更容易,因为您不需要访问特定平台,以便为其分发包。
在本教程中,您将使用Go的工具从版本控制获取包,并自动安装其可执行文件。 然后,您将手动构建和安装可执行文件,以便您可以熟悉该过程。 然后,您将为不同的架构构建可执行文件,并自动化构建过程以创建多个平台的可执行文件。 完成后,您将了解如何为Windows和MacOS以及其他要支持的平台构建可执行文件。
先决条件
要遵循本教程,您将需要:
- 一个Ubuntu 16.04服务器通过遵循Ubuntu 16.04初始服务器设置指南设置 ,包括sudo非root用户和防火墙。
- 去安装,如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-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 get
, go build
和go install
工作以及它们的相关性,让我们探索一个最受欢迎的Go功能:为其他目标平台创建可执行文件。
第4步 - 构建不同架构的可执行文件
go build
命令允许您在平台上为任何Go支持的目标平台构建可执行文件。 这意味着您可以测试,发布和分发应用程序,而无需在要使用的目标平台上构建这些可执行文件。
交叉编译通过设置指定目标操作系统和体系结构的所需环境变量来起作用。 我们使用变量GOOS
作为目标操作系统, GOARCH
用于目标体系结构。 要构建可执行文件,命令将采用以下形式:
env GOOS=target-OS GOARCH=target-architecture go build package-import-path
env
命令在修改的env
运行程序。 这允许您仅使用环境变量来执行当前命令执行。 命令执行后,变量未设置或重置。
下表显示了您可以使用的GOOS
和GOARCH
的可能组合:
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的可执行文件并提供不同的名称时,请确保在设置可执行文件的名称时明确指定.exe
Postfix。
我们来看看这个过程的脚本,以便更容易地为多个目标环境发布软件。
第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
:
...
package=$1
接下来,确保用户提供了这个值。 如果未提供该值,请使用说明如何使用脚本的消息退出脚本:
...
if [[ -z "$package" ]]; then
echo "usage: $0 <package-name>"
exit 1
fi
这个if
语句检查$package
变量的值。 如果没有设置,我们使用echo
打印正确的用法,然后使用exit
终止脚本。 exit
将返回值作为参数,成功执行时应为0
,执行失败的任何非零值。 我们在这里使用1
,因为脚本不成功。
注意 :如果要使此脚本与预定义的包一起使用,请将package
变量更改为指向该导入路径:
...
package="github.com/user/hello"
接下来,我们要从路径中提取包名称。 包导入路径由/
字符分隔,包名称位于路径的末尾。 首先,我们将使用/
作为分隔符将包导入路径拆分为数组:
package_split=(${package//\// })
软件包名称应该是新的$package_split
数组的最后一个元素。 在Bash中,您可以使用负数组索引来从末尾而不是开始访问数组。 添加此行以从数组中获取包名称并将其存储在名为package_name
的变量中:
...
package_name=${package_split[-1]}
现在,您需要决定要构建可执行文件的平台和架构。 在本教程中,我们将为Windows 64位,Windows 32位和64位的MacOS构建可执行文件。 我们将这些目标放在一个格式为OS / Platform
的数组中,所以我们可以使用与从路径中提取软件包名称相同的方法将每一对分成GOOS
和GOARCH
变量。 将平台添加到脚本中:
...
platforms=("windows/amd64" "windows/386" "darwin/amd64")
接下来,我们将遍历平台数组,将每个平台条目分为GOOS
和GOARCH
环境变量的值,并使用它们构建可执行文件。 我们可以使用以下for
循环:
...
for platform in "${platforms[@]}"
do
...
done
platform
变量将在每次迭代中包含来自platforms
数组的条目。 我们需要将platform
分为两个变量 - GOOS
和GOARCH
。 将以下行添加到for
循环中:
for platform in "${platforms[@]}"
do
platform_split=(${platform//\// })
GOOS=${platform_split[0]}
GOARCH=${platform_split[1]}
done
接下来,我们将通过将包名称与操作系统和体系结构相结合来生成可执行文件的名称。 当我们构建Windows时,我们还需要将.exe
Postfix添加到文件名。 将此代码添加到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
创建可执行文件。 将此行添加到for
循环的正文,正好位于done
关键字的上方:
...
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*
你应该看到所有三个版本:
Example ls outputcaddy-darwin-amd64 caddy-windows-386.exe caddy-windows-amd64.exe
要更改目标平台,只需更改脚本中的platforms
变量即可。
结论
在本教程中,您学习了如何使用Go的工具从版本控制系统获取软件包,以及为不同平台构建和交叉编译可执行文件。
您还创建了一个可用于跨许多平台交叉编译单个软件包的脚本。
为确保您的应用程序正常运行,您可以查看Travis-CI和AppVeyor的测试和持续集成 ,以便在Windows上进行测试。
如果您对Caddy感兴趣,以及如何使用它,请查看如何在Ubuntu 16.04上使用Caddy托管网站 。