カスタマイズ Go バイナリーを Build Tags

Введение

В Go тегом сборки, или ограничением сборки, является идентификатор, добавленный к кусочку кода, который определяет, когда файл должен быть включен в пакет Durante процесса build. Это позволяет вам сборку различных версий вашего Go приложения из одного исходного кода и быстро и организованно переключаться между ними. Многие разработчики используют теги сборки, чтобы улучшить работу по сборке приложений跨платформенные совместимые приложения, такие как программы, требующие изменения кода для учета различий между различными операционными системами. Tagi sbytki sosblyvayutsya dlya integration testing, pozvolyayuschihsya vam schno peremenyat’sya mezhdu integrirovannyym kodom i kodom s mok service ili stub, i dlya razlichnyh urovney featury vnutri aplikatsii.

Давайте возьмем проблему различных наборов функций для клиентов в качестве примера. При написании некоторых приложений вы можете захотеть контролировать, какие функции включать в двоичный файл, например, приложение, которое предлагает уровни Free, Pro и Enterprise. По мере как клиент увеличивает свой уровень подписки в этих приложениях, становятся доступными больше функций. Чтобы решить эту проблему, вы могли бы поддерживать отдельные проекты и пытаться синхронизировать их друг с другом с помощью использования import выражений. Хотя этот подход бы работал, со временем он станет утомительным и подверженным ошибкам. Альтернативным подходом было бы использовать теги сборки.

В этой статье вы будете использовать теги сборки в Go для создания различных исполняемых двоичных файлов, которые предлагают наборы функций Free, Pro и Enterprise образца приложения. Каждое из них будет иметь различный набор доступных функций, при этом версия Free будет стандартной.

Предварительные требования

Чтобы следовать примеру в этой статье, вам понадобится:

Создание бесплатной версии

Давайте начнем с создания бесплатной версии приложения, поскольку это будет версией по умолчанию при выполнении 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

До сих пор мы избегали вносить изменения в 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",
  )
}

В этом коде мы использовали init(), чтобы выполнить код перед функцией main() нашего приложения, а затем append(), чтобы добавить Pro-функции в срез features. Сохраните и выйдите из файла.

Компилируйте и запустите приложение с помощью go build:

  1. go build

Так как теперь в нашем текущем каталоге есть два файла (pro.go и main.go), go build создаст бинарник из обоих. Выполните этот бинарник:

  1. ./app

Это даст вам следующий набор функций:

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

Приложение теперь включает как Pro-, так и Free-функции. Однако это не желательно: так как нет различия между версиями, Free-версия теперь включает функции, которые должны быть доступны только в Pro-версии. Чтобы исправить это, вы можете добавить больше кода для управления различными уровнями приложения или использовать теги сборки, чтобы сообщить инструментам Go, какие .go файлы следует собирать, а какие игнорировать. Давайте добавим теги сборки в следующем шаге.

Добавление тегов сборки

Теперь вы можете использовать теги сборки, чтобы различать Pro-версию вашего приложения и Free-версию.

Начнем с изучения, как выглядит тег сборки:

// +build tag_name

При добавлении этой строки кода в начале вашего пакета и замене tag_name на имя вашего тэга построения, вы помечаете этот пакет как код, который может быть выборно включен в конечный бинарник.债 clicks here to edit the code

  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.go только при наличии тэга pro.

Сompile and run the application again:

  1. go build
  2. ./app

Вы получите следующий вывод:

Output
> Free Feature #1 > Free Feature #2

Т.к. файл pro.go требует наличия тэга pro, для включения, тогда этот файл игнорируется и при компиляции приложения его не используется.

При запуске комманды go build, мы можем использовать флаг -tags, чтобы условно включать код в скомпилированный исходник, добавив сам тэг как аргумент. Let’s do this for the pro tag:

  1. go build -tags pro

Это выведет следующее:

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

Теперь мы получаем дополнительные функции только при сборке приложения с использованием тега pro.

Это нормально, если есть только две версии, но дело усложняется, когда добавляется больше тегов. Чтобы добавить корпоративную версию нашего приложения на следующем шаге, мы будем использовать несколько тегов сборки, объединенных логикой BOOLEAN.

Логика BOOLEAN тегов сборки

Когда в пакете Go есть несколько тегов сборки, теги взаимодействуют друг с другом с использованием логики BOOLEAN. Для демонстрации этого мы добавим уровень Enterprise нашего приложения с использованием как тега pro, так и тега 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. Для pro.go вы добавили // +build pro и новую строку в начало файла, чтобы сообщить go build, что он должен включаться только при использовании -tags pro. В этой ситуации вам нужен был только один тег сборки, чтобы достичь цели. Однако, добавляя новые функции для Entreprise, вам сначала также нужно иметь функции Pro.

Давайте сначала добавим поддержку тега сборки pro в enterprise.go. Откройте файл с помощью вашего текстового редактора:

  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 больше не отображаются в бесплатной версии. Теперь добавьте тег сборки 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

Добавьте еще один тег сборки, enterprise, на ту же строку, что и тег pro:

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 интерпретирует их как использование логики ИЛИ. С добавлением строки // +build pro enterprise, файл enterprise.go будет собираться, если либо тег сборки pro, либо тег сборки enterprise присутствует. Нам нужно настроить теги сборки правильно, чтобы требовать оба и использовать логику И вместо этого.

Вместо того чтобы ставить оба тега на одной строке, если мы разместим их на отдельных строках, то go build будет интерпретировать эти теги с использованием логики И.

Откройте снова 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

Все еще не совсем так: Поскольку оператор И требует, чтобы оба элемента считались true, нам нужно использовать оба тега сборки pro и enterprise.

Попробуем еще раз:

  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 для обозначения логики И, но существуют и другие способы представления логики Булева с тегами сборки. В следующей таблице приведены примеры других синтаксических форматирований для тегов сборки, вместе с их эквивалентами Булева логики:

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, затем комбинировали несколько тегов с логикой Булева. Затем вы собрали программу, представляющую различные наборы функций версий Free, Pro и Enterprise, показывая высокий уровень контроля, который теги сборки могут дать вам над вашим проектом.

Если вы хотите узнать больше о тегах сборки, обратитесь к документации Golang по этой теме, или продолжайте исследовать нашу серию Как программировать на Go.

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