Go 기능 binaries를 빌드 태그로 custtomizing

소개

Go에서는 빌드 태그 또는 빌드 제약이라는 식별자를 코드에 추가하여 파일이 build 과정에서 패키지에 포함되어야 하는지를 결정합니다. 이를 통해 같은 소스 코드에서 Go 애플리케이션의 여러 버전을 빠르고 조직된 방식으로 토글할 수 있습니다. 많은 개발자들은 빌드 태그를 사용하여 교차 플랫폼 호환 애플리케이션을 빌드하는 워크플로우를 개선합니다. 예를 들어, 여러 운영 체제 간의 차이를 고려해 코드를 변경해야 하는 프로그램들은 이러한 방식을 사용합니다. 빌드 태그는 또한 통합 테스트에 사용되며, 통합된 코드와 모의 서비스나 스텁 코드 간을 빠르게 전환할 수 있으며, 애플리케이션 내의 여러 기능 세트 간의 전환에도 사용됩니다.

고객의 특성 집합이 다를 때의 문제를 예로 들어보겠습니다. 일부 응용 프로그램을 작성할 때, 바이너리에 포함할 기능을 제어하고 싶을 수 있습니다. 예를 들어, 무료, 프로, 엔터프라이즈 수준을 제공하는 응용 프로그램에서 그렇습니다. 이러한 응용 프로그램에서 고객이 구독 수준을 높이면, 더 많은 기능이 잠금 해제되고 사용 가능해집니다. 이 문제를 해결하기 위해, 별도의 프로젝트를 유지하고 import 문을 통해 서로를 동기화하려고 할 수 있습니다. 이 접근 방식은 작동하지만, 시간이 지나면 지루하고 실수가 쉬워질 수 있습니다. 대안적인 접근 방식은 빌드 태그를 사용하는 것입니다.

이 기사에서는 Go에서 빌드 태그를 사용하여 무료, 프로, 엔터프라이즈 기능 세트를 제공하는 다른 실행 파일을 생성하는 방법을 설명합니다. 각각은 다른 기능 세트를 사용할 수 있으며, 기본적으로 무료 버전이 됩니다.

필수 조건

이 기사의 예제를 따를려면, 다음이 필요합니다:

무료 버전 빌드하기

우선 go build 명령어를 실행할 때 어떤 빌드 태그도 없이 기본으로 실행되는 무료 버전의 애플리케이션을 빌드해 보겠습니다. 나중에는 빌드 태그를 사용하여 프로그램에 다른 부분을 선택적으로 추가할 것입니다.

src 디렉토리에서 애플리케이션의 이름을 가진 폴더를 생성합니다. 이 튜토리얼에서는 app이라는 이름을 사용합니다:

  1. mkdir app

이 폴더로 이동합니다:

  1. cd app

다음으로, 사용하는 텍스트 편집기에서 main.go라는 이름의 새 텍스트 파일을 만듭니다:

  1. nano main.go

이제, 무료 버전의 애플리케이션을 정의해 보겠습니다. main.go 파일에 다음 내용을 추가합니다:

main.go
package main

import "fmt"

var features = []string{
  "Free Feature #1",
  "Free Feature #2",
}

func main() {
  for _, f := range features {
    fmt.Println(">", f)
  }
}

이 파일에서는 features라는 이름의 슬라이스를 선언하는 프로그램을 만듭니다. 이 슬라이스는 우리의 무료 애플리케이션의 기능을 나타내는 두 개의 문자열을 포함합니다. 애플리케이션의 main() 함수는 for 루프를 사용하여 range를 통해 features 슬라이스를 순환하고 모든 사용 가능한 기능을 화면에 출력합니다.

파일을 저장하고 종료하세요. 이제 이 파일을 저장했으므로, 이 글의 나머지 부분에서는 더 이상 편집할 필요가 없습니다. 대신 우리는 빌드 태그를 사용하여 이 파일에서 만들 특성을 변경할 것입니다.

프로그램을 빌드하고 실행하세요:

  1. go build
  2. ./app

다음과 같은 출력이 표시됩니다:

Output
> Free Feature #1 > Free Feature #2

프로그램이 우리 앱의 무료 버전을 완성하기 위해 두 가지 무료 기능을 출력했습니다.

지금까지, 매우 기본적인 기능 세트를 가진 애플리케이션을 생성했습니다. 다음으로, 빌드 시에 애플리케이션에 더 많은 기능을 추가하는 방법을 구축하겠습니다.

go build으로 Pro 기능 추가하기

지금까지 main.go에 변경을 가하지 않고 있었습니다. 주요 코드를 변경하고 그래서 망가뜨릴 수 있는 공통적인 제조 환경을 시뮬레이션하고 있었습니다. main.go 파일을 편집할 수 없으므로, 빌드 태그를 사용하여 features 슬라이스에 더 많은 기능을 주입하는 다른 메커니즘을 사용해야 합니다.

pro.go라는 새 파일을 만들어 init() 함수를 사용하여 features 슬라이스에 더 많은 기능을 추가하겠습니다:

  1. nano pro.go

편집기가 파일을 열 때, 다음 줄들을 추가하세요:

pro.go
package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

이 코드에서는 우리의 应用程序의 main() 함수 전에 코드를 실행하기 위해 init()를 사용하고, append()를 사용하여 features 슬라이스에 Pro 기능을 추가합니다. 파일을 저장하고 닫으십시오.

应用程序을 go build를 사용하여 编译하고 실행하십시오.:

  1. go build

이제 우리의 현재 디렉터리에 두 개의 파일이 있습니다 (pro.gomain.go), go build는 그들 모두에 대해 바이너리를 생성합니다. 이 바이너리를 실행하십시오.:

  1. ./app

이这将为您提供以下功能集:

Output
> Free Feature #1 > Free Feature #2 > Pro Feature #1 > Pro Feature #2

应用程序现在包括Pro和Free功能。 그러나 이것은 원하는 것이 아닙니다.: VERSION을 구분하는 것 없이, Free Version이 Pro 버전에 独占적으로 제공되어야 하는 기능을 포함합니다. 이를 修复하기 위해서는 应用程序의 다른 层를 관리하는 추가 코드를 포함하거나, Go 도구 체인에게 어떤 .go 파일을 编译하고 어떤 것을 忽视하는지 말고 编译 태그를 사용할 수 있습니다. 下一步에 编译 태그를 추가하겠습니다.

编译 태그 추가

이제 编译 태그를 사용하여 应用程序의 Pro 버전과 Free 버전을 구분할 수 있습니다.

우선 编译 태그가 어떻게 보입니다:

// +build tag_name

이 코드 줄을 패키지의 첫 번째 줄로 배치하고 tag_name를 빌드 태그의 이름으로 대체하면, 이 패키지를 최종 바이너리에 선택적으로 포함할 수 있는 코드로 태그할 수 있습니다. 빌드 태그를 pro.go 파일에 추가하여 go build 명령이 태그가 지정되지 않은 경우는 무시하도록 하는 방법을 살펴보겠습니다. 텍스트 편집기에서 파일을 엽니다:

  1. nano pro.go

그런 다음, 다음 강조된 줄을 추가합니다:

pro.go
// +build pro

package main

func init() {
  features = append(features,
    "Pro Feature #1",
    "Pro Feature #2",
  )
}

pro.go 파일의 맨 위에 // +build pro 뒤에 공백 줄을 추가했습니다. 이 훈련 줄은 필수적입니다. 그렇지 않으면 Go는 이를 주석으로 인식합니다. 빌드 태그 선언은 .go 파일의 맨 위에 와야 합니다. 주석조차도 빌드 태그 위에 오면 안 됩니다.

+build 선언은 go build 명령에 이것이 주석이 아니라 빌드 태그임을 알려줍니다. 두 번째 부분은 pro 태그입니다. pro.go 파일의 맨 위에 이 태그를 추가하면, go build 명령이 이제 pro 태그가 있을 때만 pro.go 파일을 포함합니다.

애플리케이션을 다시 컴파일하고 실행합니다:

  1. go build
  2. ./app

다음과 같은 출력을 받게 됩니다:

Output
> Free Feature #1 > Free Feature #2

pro.go 파일은 pro 태그가 있어야 하므로, 파일은 무시되고 애플리케이션이 그 없이 컴파일됩니다.

go build 명령을 실행할 때, -tags 플래그를 사용하여 컴파일된 소스에 태그 자체를 인수로 추가하여 코드를 조건부로 포함할 수 있습니다. pro 태그에 대해 이를 수행해 봅시다:

  1. go build -tags pro

다음과 같이 출력됩니다:

Output
> Free Feature #1 > Free Feature #2 > Pro Feature #1 > Pro Feature #2

이제 우리는 pro 빌드 태그를 사용하여 애플리케이션을 빌드할 때만 추가 기능을 얻습니다.

두 버전만 있으면 이렇게 괜찮지만, 더 많은 태그를 추가하면 일이 복잡해집니다. 다음 단계에서 우리 앱의_Enterprise_ 버전을 추가하려면, 여러 빌드 태그를 Boolean 논리로 연결한 것을 사용합니다.

빌드 태그 Boolean 논리

Go 패키지에 여러 빌드 태그가 있을 때, 태그들은 Boolean 논리를 사용하여 서로 상호작용합니다. 이를 보여주기 위해, 우리는 pro 태그와 enterprise 태그를 모두 사용하여 애플리케이션의_Enterprise_ 수준을 추가하겠습니다.

Enterprise 바이너리를 빌드하려면, 기본 기능, Pro 수준 기능, 그리고 Enterprise에 새로운 기능 세트를 모두 포함해야 합니다. 먼저, 편집기를 열고 enterprise.go라는 새 파일을 만들어 Enterprise의 새로운 기능을 추가합니다:

  1. nano enterprise.go

enterprise.go의 내용은 pro.go와 거의 동일하지만, 새로운 기능이 포함됩니다. 다음 줄을 파일에 추가하세요:

enterprise.go
package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

파일을 저장하고 나가세요.

현재 enterprise.go 파일은 어떠한 빌드 태그도 갖추고 있지 않습니다. 이제 pro.go를 추가하면 이러한 기능은 실행 시 go.build을 사용할 때 Free 버전에 기능을 추가할 것입니다. pro.go에서는 // +build pro를 추가하고 파일 상단에 一新行을 추가하여 go build이 이 것을 사용하여 어떠한 것을 compiler. 이 상황에서는 목표를 달성하기 위해 하나의 빌드 태그가 필요했습니다. 하지만 새로운 Enterprise 기능을 추가하는 것은 Pro 기능이 먼저 추가되어야 합니다.

우선 enterprise.gopro 빌드 태그 지원을 추가하겠습니다. 텍스트 에디터로 파일을 열고 다음을 执行합니다:

  1. nano enterprise.go

다음 빌드 태그를 package main 宣言 전에 추가하고 빌드 태그 다음에 一新行을 추가하십시오. :

enterprise.go
// +build pro

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

파일을 저장하고 닫으십시오.

태그 없이 应用程序을 컴파일하고 실행하십시오.

  1. go build
  2. ./app

다음 출력을 받을 것입니다.

Output
> Free Feature #1 > Free Feature #2

Enterprise 기능은 anymore. 이제 pro 빌드 태그를 추가하고 다시 应用程序을 빌드하고 실행하십시오.

  1. go build -tags pro
  2. ./app

다음 출력을 받을 것입니다.

Output
> Free Feature #1 > Free Feature #2 > Enterprise Feature #1 > Enterprise Feature #2 > Pro Feature #1 > Pro Feature #2

이제 정확히 해야 하는 것이 아니지만 Enterprise 기능이 Pro 버전에 编译될 때 보이는 것입니다. 이를 해결하기 위해서는 다른 빌드 태그를 사용해야 합니다. pro 태그와 다르게 이제는 함께 Pro 기능과 Enterprise 기능이 都应该 사용할 수 있도록 해야 합니다.

Go 빌드 시스템은 이러한 상황을 고려하여 빌드 태그 시스템에서 一些 기본적인 布尔逻辑을 가지고 있습니다.

enterprise.go 문서를 다시 열어봅니다.

  1. nano enterprise.go

pro 태그 同一行에 다른 빌드 태그 enterprise를 추가합니다.

enterprise.go

// +build pro enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

파일을 저장하고 닫습니다.

이제 enterprise 빌드 태그로 새로운 应用程序을 컴파일하고 실행해봅니다.

  1. go build -tags enterprise
  2. ./app

这将导致以下结果:

Output
> Free Feature #1 > Free Feature #2 > Enterprise Feature #1 > Enterprise Feature #2

이제 Pro 기능을 잃었습니다. 이는 우리가 .go файле에 同一行에 여러 빌드 태그를 넣었을 때 go build가 그들을 OR 논리로 해석하는 것을 때문입니다. // +build pro enterprise 行을 추가하면 enterprise.go 파일이 either pro 빌드 태그나 enterprise 빌드 태그가 存在하는 경우 빌드되는 것입니다. 우리는 correct build tags를 설정하여 both를 필요로하고 AND 논리를 사용하도록 하는 것이 필요합니다.

同一行에 두 태그를 모두 넣기 대신에, 여러 行에 分别하여, 그러면 go build가 그 태그들을 AND 논리로 해석하게 되ます.

다시 enterprise.go를 열어봅니다 并 빌드 태그를 여러 行으로 분리합니다.

enterprise.go
// +build pro
// +build enterprise

package main

func init() {
  features = append(features,
    "Enterprise Feature #1",
    "Enterprise Feature #2",
  )
}

이제 새로운 enterprise 빌드 태그로 应用程序을 컴파일하고 실행하십시오.

  1. go build -tags enterprise
  2. ./app

다음과 같은 输出이 나옵니다:

Output
> Free Feature #1 > Free Feature #2

まだ 정확하지 않습니다: AND 声明은 모두 truth를 만들 수 있는 요소를 필요로하므로, proenterprise 빌드 태그를 사용해야 합니다.

다시 시도하겠습니다:

  1. go build -tags "enterprise pro"
  2. ./app
Output
> Free Feature #1 > Free Feature #2 > Enterprise Feature #1 > Enterprise Feature #2 > Pro Feature #1 > Pro Feature #2

이제 我们的 应用程序可以从同一源树以多种方式构建,根据需要解锁应用程序的功能。

在这个例子中,我们使用了一个新的 // +build 标签来表示 AND 逻辑,但是还有其他方法可以用构建标签表示布尔逻辑。下面的表格包含了一些使用构建标签的其他语法格式示例,以及它们的布尔等价物:

Build Tag Syntax Build Tag Sample Boolean Statement
Space-separated elements // +build pro enterprise pro OR enterprise
Comma-separated elements // +build pro,enterprise pro AND enterprise
Exclamation point elements // +build !pro NOT pro

결론

在这篇教程中,您使用了构建标签来控制哪些代码被编译进二进制文件。首先,您声明了构建标签并将其与 go build 一起使用,然后您使用了布尔逻辑组合了多个标签。之后,您构建了一个程序,它代表了免费版、专业版和企业版的不同功能集合,展示了构建标签可以为您项目提供的强大控制级别。

如果您想了解更多关于构建标签的信息,请查看 Golang 有关该主题的文档,或者继续探索我们的 Go 编程系列教程

Source:
https://www.digitalocean.com/community/tutorials/customizing-go-binaries-with-build-tags