简介
在GO中,a_Build Tag_或构建约束是添加到一段代码中的标识符,用于确定在Build
过程中何时应将文件包含在包中。这允许您从相同的源代码构建不同版本的Go应用程序,并以快速、有组织的方式在它们之间切换。许多开发人员使用构建标记来改进构建跨平台兼容应用程序的工作流程,例如需要更改代码以解决不同操作系统之间差异的程序。Build标签也用于集成testing,],允许您在集成代码和模拟服务或stub,以及应用程序内不同级别的功能集的代码之间快速切换。
让我们以不同客户功能集的问题为例。在编写一些应用程序时,您可能希望控制在二进制文件中包含哪些功能,例如提供免费 、** 专业** 和** 企业版** 级别的应用程序。随着客户在这些应用程序中提高他们的订阅级别,更多的功能将被解锁并可用。要解决这个问题,您可以维护单独的项目,并通过使用port
语句来保持它们之间的同步。虽然这种方法可以奏效,但随着时间的推移,它会变得单调乏味,容易出错。另一种方法是使用构建标记。
在本文中,您将使用Go中的构建标记来生成不同的可执行二进制文件,以提供示例应用程序的Free、Pro和Enterprise功能集。每个版本都有一组不同的功能可用,免费版本是默认的。
前提条件
要遵循本文中的示例,您将需要:
构建免费版本
让我们从构建应用程序的免费版本开始,因为在没有任何构建标签的情况下,它将是运行Go Build
时的默认版本。稍后,我们将使用构建标记有选择地将其他部分添加到我们的程序中。
在src目录中,创建一个以应用程序名称命名的文件夹。本教程将使用app
:
1mkdir app
移到此文件夹中:
1cd app
接下来,在您选择的文本编辑器中创建一个名为main.go
的新文本文件:
1nano main.go
现在,我们将定义应用程序的免费版本。在main.go
中添加以下内容:
1[label main.go]
2package main
3
4import "fmt"
5
6var features = []string{
7 "Free Feature #1",
8 "Free Feature #2",
9}
10
11func main() {
12 for _, f := range features {
13 fmt.Println(">", f)
14 }
15}
在这个文件中,我们创建了一个程序,它声明了一个名为Featureres
的slice,它包含两个strings,它们代表我们的自由应用程序的特性。应用程序中的``range](https://andsky.com/tech/tutorials/how-to-construct-for-loops-in-go looping-through-sequential-data-types-with-rangeclause)()
函数使用[for
循环来切片并打印屏幕上可用的所有功能。
保存并退出该文件。现在该文件已保存,我们将不再需要在本文的其余部分编辑它。相反,我们将使用构建标记来更改我们将从它构建的二进制文件的功能。
构建并运行程序:
1go build
2./app
您将收到以下输出:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
该程序已经打印出我们的两个免费功能,完成了我们的应用程序的免费版本。
到目前为止,您创建了一个具有非常基本的功能集的应用程序。接下来,您将构建一种在构建时向应用程序添加更多功能的方法。
使用go build
添加专业功能
到目前为止,我们避免了对main.go
进行更改,模拟了一个常见的生产环境,在这种环境中,需要添加代码而不更改,并且可能会破坏主代码。因为我们不能编辑main.go
文件,所以我们需要使用另一种机制来使用构建标记将更多特性注入到Featurees
切片中。
让我们创建一个名为pro.go
的新文件,该文件将使用init()
函数将更多功能附加到Featureres
切片:
1nano pro.go
在编辑器打开文件后,添加以下行:
1[label pro.go]
2package main
3
4func init() {
5 features = append(features,
6 "Pro Feature #1",
7 "Pro Feature #2",
8 )
9}
在这段代码中,我们使用init()
在应用程序的main()
函数之前运行代码,然后使用append()
将Pro功能添加到Featureres
切片中。保存并退出该文件。
使用go Build
编译并运行应用程序:
1go build
因为我们的当前目录中现在有两个文件(pro.go
和main.go
),所以go Build
将从这两个文件创建二进制文件。执行此二进制文件:
1./app
这将为您提供以下功能集:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
4> Pro Feature #1
5> Pro Feature #2
该应用程序现在包括Pro和Free功能。然而,这是不可取的:由于没有版本之间的区别,免费版本现在包括了应该只有专业版才能使用的功能。要解决这个问题,您可以包含更多代码来管理应用程序的不同层,或者您可以使用构建标记来告诉GO工具链应该构建和忽略哪些.go
文件。让我们在下一步中添加构建标记。
添加Build标签
您现在可以使用构建标签来区分您的应用程序的专业版和免费版。
让我们从检查构建标记的外观开始:
1// +build tag_name
通过将这行代码作为包的第一行,并将tag_name
替换为构建标记的名称,您将把这个包标记为可以选择性地包含在最终二进制文件中的代码。让我们通过在pro.go
文件中添加一个build标记来告诉gobuild
命令忽略它,除非指定了该标记。在文本编辑器中打开文件:
1nano pro.go
然后添加以下突出显示的行:
1[label pro.go]
2// +build pro
3
4package main
5
6func init() {
7 features = append(features,
8 "Pro Feature #1",
9 "Pro Feature #2",
10 )
11}
在pro.go
文件的顶部,我们添加了//+Build pro
,后跟一个空换行符。尾随的换行符是必需的,否则GO会将其解释为注释。构建标记声明还必须位于.go
文件的最顶端。任何内容,甚至包括注释,都不能位于构建标记之上。
+Build
声明告诉go Build
命令,这不是一个注释,而是一个构建标签。第二部分是pro
标签。通过在pro.go
文件的顶部添加此标记,go Build
命令现在将仅包含带有pro
标记的pro.go
文件。
再次编译并运行应用程序:
1go build
2./app
您将收到以下输出:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
由于pro.go
文件需要存在pro
标签,因此该文件将被忽略,应用程序将在没有该标签的情况下进行编译。
在运行go Build
命令时,我们可以使用-tag
标志,通过添加标签本身作为参数,有条件地将代码包含在编译后的源代码中。让我们为pro
标签这样做:
1go build -tags pro
这将输出以下内容:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
4> Pro Feature #1
5> Pro Feature #2
现在我们只有在使用pro
构建标签构建应用程序时才能获得额外的功能。
如果只有两个版本,这是很好的,但当您添加更多标记时,事情就会变得复杂。为了在下一步添加我们的应用程序的企业版,我们将使用多个构建标记并结合布尔逻辑。
构建标记布尔逻辑
当Go包中有多个构建标签时,这些标签使用boolean logic.]彼此交互为了演示这一点,我们将使用pro
标签和Enterprise
标签添加应用程序的企业级。
为了构建Enterprise二进制文件,我们需要包含默认特性、Pro级特性和一组新的Enterprise特性。首先,打开一个编辑器并创建一个新文件,enterprise.go
,它将添加新的Enterprise特性:
1nano enterprise.go
enterprise.go
的内容看起来与pro.go
几乎相同,但会包含新的功能。将以下行添加到文件中:
1[label enterprise.go]
2package main
3
4func init() {
5 features = append(features,
6 "Enterprise Feature #1",
7 "Enterprise Feature #2",
8 )
9}
保存并退出该文件。
目前enterprise.go
文件没有任何构建标签,正如您在添加pro.go
时了解到的,这意味着当执行go.Build
时,这些功能将被添加到免费版本中。对于pro.go
,您在文件的顶部添加了//+Build pro
和换行符,告诉go Build
只有在使用-tag pro
的情况下才应该包含它。在这种情况下,您只需要一个构建标记即可实现目标。但是,在添加新的企业功能时,您首先还必须具有Pro功能。
让我们先将对pro
build标记的支持添加到enterprise.go
中。使用文本编辑器打开文件:
1nano enterprise.go
接下来,在Package main
声明前添加构建标签,并确保在构建标签之后添加换行符:
1[label enterprise.go]
2// +build pro
3
4package main
5
6func init() {
7 features = append(features,
8 "Enterprise Feature #1",
9 "Enterprise Feature #2",
10 )
11}
保存并退出该文件。
编译并运行不带任何标记的应用程序:
1go build
2./app
您将收到以下输出:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
企业版的功能不再显示在免费版本中。现在,我们添加pro
构建标签,并重新构建并运行应用程序:
1go build -tags pro
2./app
您将收到以下输出:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
4> Enterprise Feature #1
5> Enterprise Feature #2
6> Pro Feature #1
7> Pro Feature #2
这仍然不是我们所需要的:现在当我们试图构建专业版时,企业版的功能就会出现。要解决这个问题,我们需要使用另一个构建标记。然而,与pro
标签不同的是,我们现在需要确保pro
和Enterprise
功能都可用。
Go构建系统通过允许在构建标记系统中使用一些基本的布尔逻辑来解决这种情况。
让我们再次打开进取号.前进号
:
1nano enterprise.go
在与pro
标签相同的一行添加另一个构建标签Enterprise
:
1[label enterprise.go]
2// +build pro enterprise
3
4package main
5
6func init() {
7 features = append(features,
8 "Enterprise Feature #1",
9 "Enterprise Feature #2",
10 )
11}
保存并关闭文件。
现在,让我们使用新的Enterprise
构建标签编译并运行应用程序。
1go build -tags enterprise
2./app
这将提供以下内容:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
4> Enterprise Feature #1
5> Enterprise Feature #2
现在我们已经失去了Pro功能。这是因为当我们将多个构建标记放在.go
文件中的同一行时,go build
会将它们解释为使用OR
逻辑。通过添加// +build pro enterprise
行,如果存在 * pro
build标记或enterprise
build标记,则将构建enterprise.go
文件。我们需要正确地设置构建标记,以要求 ** both 并使用AND
逻辑。
如果我们把两个标签放在不同的行上,而不是把它们放在同一行上,那么go build
将使用AND
逻辑解释这些标签。
再次打开enterprise.go
,让我们将构建标签分成多行。
1[label enterprise.go]
2// +build pro
3// +build enterprise
4
5package main
6
7func init() {
8 features = append(features,
9 "Enterprise Feature #1",
10 "Enterprise Feature #2",
11 )
12}
现在使用新的Enterprise
内部版本标记编译并运行应用程序。
1go build -tags enterprise
2./app
您将收到以下输出:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
还不是很好:因为AND
语句要求两个元素都被认为是true
,所以我们需要同时使用pro
和Enterprise
构建标签。
让我们再试一次:
1go build -tags "enterprise pro"
2./app
您将收到以下输出:
1[secondary_label Output]
2> Free Feature #1
3> Free Feature #2
4> Enterprise Feature #1
5> Enterprise Feature #2
6> Pro Feature #1
7> Pro Feature #2
现在,我们的应用程序可以通过多种方式从相同的源代码树构建,从而解锁应用程序的功能。
在本例中,我们使用了一个新的//+Build
标记来表示`AND‘逻辑,但也有用构建标记表示布尔逻辑的其他方法。下表列出了Build标记的其他语法格式的一些示例以及它们的布尔值等效项:
构建标记语法|构建标记示例|布尔语句
:-:|
空格分隔元素|//+构建PRO企业
|pro
或Enterprise
逗号分隔元素|//+Build PRO,Enterprise
|pro
和Enterprise
感叹号元素|//+Build!pro
|不是pro
结论
在本教程中,您使用了构建标记来控制将哪些代码编译为二进制代码。首先声明了构建标签并将其与go Build
一起使用,然后使用布尔逻辑将多个标签组合在一起。然后,您构建了一个程序,该程序代表了Free、Pro和Enterprise版本的不同功能集,显示了构建标记可以为您提供对项目的强大控制级别。
如果您想了解有关构建标记的更多信息,请查看subject](https://golang.org/pkg/go/build/# hdr-Build_Constraints),上的[Golang文档]或继续探索我们的如何在Go series.中编码