Список рассылки: bazel-go-discuss
Slack: #go on Bazel Slack, #bazel on Go Slack
Правила находятся на стадии бета-разработки. Они поддерживают:
В настоящее время они не поддерживают или имеют ограниченную поддержку:
Правила Go протестированы и поддерживаются на следующих хост-платформах:
Пользователи сообщили об успехе на нескольких других платформах, но правила тестируются только на перечисленных выше.
Примечание. Начиная с версии 0.38.0, для работы Rules_go требуется Bazel ≥ 5.4.0.
master
ветка гарантированно будет работать только с последней версией Bazel.
Чтобы создать код Go с помощью Bazel, вам понадобится:
patch
, cat
и несколько других инструментов Unix в PATH
.Обычно вам не требуется установка набора инструментов Go. Базель загрузит один.
Инструкции по настройке для конкретной Windows см. в разделе «Использование Rules_go в Windows». Необходимо установить и настроить несколько дополнительных инструментов.
Если вы используете новую систему управления внешними зависимостями Bzlmod от Bazel, вместо этого обратитесь к специальному руководству Go with Bzlmod.
Создайте файл в верхней части репозитория с именем WORKSPACE
и добавьте приведенный ниже фрагмент (или добавьте его в существующее WORKSPACE
). Это говорит Bazel о необходимости получить Rules_go и его зависимости. Bazel загрузит последнюю поддерживаемую цепочку инструментов Go и зарегистрирует ее для использования.
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "io_bazel_rules_go" ,
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
],
)
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
go_rules_dependencies ()
go_register_toolchains ( version = "1.23.1" )
Вы можете использовать Rules_go в master
, используя git_repository вместо http_archive и указывая на недавнюю фиксацию.
Добавьте файл с именем BUILD.bazel
в корневой каталог вашего проекта. Вам понадобится файл сборки в каждом каталоге с кодом Go, но вам также понадобится файл сборки в корневом каталоге, даже если в вашем проекте там нет кода Go. Для двоичного файла «Hello, world» файл должен выглядеть следующим образом:
load ( "@io_bazel_rules_go//go:def.bzl" , "go_binary" )
go_binary (
name = "hello" ,
srcs = [ "hello.go" ],
)
Вы можете построить эту цель с помощью bazel build //:hello
.
Если ваш проект можно собрать с помощью go build
, вы можете автоматически генерировать и обновлять файлы сборки с помощью gaselle.
Добавьте репозиторий bazel_gazelle
и его зависимости в свою WORKSPACE
. Это должно выглядеть так:
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" ) http_archive ( name = "io_bazel_rules_go" , integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" , urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" , "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" , ], ) http_archive ( name = "bazel_gazelle" , integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=" , urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" , "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" , ], ) load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" ) load ( "@bazel_gazelle//:deps.bzl" , "gazelle_dependencies" ) go_rules_dependencies () go_register_toolchains ( version = "1.23.1" ) gazelle_dependencies ()
Добавьте приведенный ниже код в файл BUILD.bazel
в корневом каталоге вашего проекта. Замените строку после prefix
префиксом пути импорта, соответствующим вашему проекту. Он должен совпадать с путем к вашему модулю, если у вас есть файл go.mod
.
load ( "@bazel_gazelle//:def.bzl" , "gazelle" )
# gazelle:prefix github.com/example/project
gazelle ( name = "gazelle" )
Это объявляет бинарное правило gazelle
, которое вы можете запустить с помощью команды ниже:
bazel run //:gazelle
При этом будет создан файл BUILD.bazel
с целевыми объектами go_library, go_binary и go_test для каждого пакета в вашем проекте. Вы можете запустить ту же команду в будущем, чтобы обновить существующие файлы сборки новыми исходными файлами, зависимостями и параметрами.
Если ваш проект не соответствует соглашениям go build
или вы предпочитаете не использовать gaselle, вы можете написать файлы сборки вручную.
В каждом каталоге, содержащем код Go, создайте файл с именем BUILD.bazel
Добавьте в начало файла оператор load
для используемых вами правил.
load ( "@io_bazel_rules_go//go:def.bzl" , "go_binary" , "go_library" , "go_test" )
Для каждой библиотеки добавьте правило go_library, как показано ниже. Исходные файлы указаны в атрибуте srcs
. Импортированные пакеты за пределами стандартной библиотеки перечислены в атрибуте deps
с использованием меток Bazel, которые ссылаются на соответствующие правила go_library. Путь импорта библиотеки должен быть указан с помощью атрибута importpath
.
go_library (
name = "foo_library" ,
srcs = [
"a.go" ,
"b.go" ,
],
importpath = "github.com/example/project/foo" ,
deps = [
"//tools" ,
"@org_golang_x_utils//stuff" ,
],
visibility = [ "//visibility:public" ],
)
Для тестов добавьте правило go_test, подобное приведенному ниже. Тестируемая библиотека должна быть указана в атрибуте embed
.
go_test (
name = "foo_test" ,
srcs = [
"a_test.go" ,
"b_test.go" ,
],
embed = [ ":foo_lib" ],
deps = [
"//testtools" ,
"@org_golang_x_utils//morestuff" ,
],
)
Для двоичных файлов добавьте правило go_binary, как показано ниже.
go_binary (
name = "foo" ,
srcs = [ "main.go" ],
)
Для каждого репозитория Go добавьте правило go_repository в WORKSPACE
, как показано ниже. Это правило взято из репозитория Gazelle, поэтому вам нужно будет его загрузить. Gazelle update-repos может автоматически генерировать или обновлять эти правила из файла go.mod или Gopkg.lock.
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
# Download the Go rules.
http_archive (
name = "io_bazel_rules_go" ,
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
],
)
# Download Gazelle.
http_archive (
name = "bazel_gazelle" ,
integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" ,
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" ,
],
)
# Load macros and repository rules.
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
load ( "@bazel_gazelle//:deps.bzl" , "gazelle_dependencies" , "go_repository" )
# Declare Go direct dependencies.
go_repository (
name = "org_golang_x_net" ,
importpath = "golang.org/x/net" ,
sum = "h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=" ,
version = "v0.23.0" ,
)
# Declare indirect dependencies and register toolchains.
go_rules_dependencies ()
go_register_toolchains ( version = "1.23.1" )
gazelle_dependencies ()
Чтобы генерировать код из буферов протокола, вам необходимо добавить зависимость от com_google_protobuf
в ваше WORKSPACE
.
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "com_google_protobuf" ,
sha256 = "535fbf566d372ccf3a097c374b26896fa044bf4232aef9cab37bd1cc1ba4e850" ,
strip_prefix = "protobuf-3.15.0" ,
urls = [
"https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v3.15.0.tar.gz" ,
"https://github.com/protocolbuffers/protobuf/archive/v3.15.0.tar.gz" ,
],
)
load ( "@com_google_protobuf//:protobuf_deps.bzl" , "protobuf_deps" )
protobuf_deps ()
Для создания протокола вам понадобится набор инструментов C/C++, зарегистрированный для платформы выполнения (платформы, на которой Bazel выполняет действия).
Правило proto_library предоставляется репозиторием rules_proto
. protoc-gen-go
, плагин компилятора протоколов Go, предоставляется репозиторием com_github_golang_protobuf
. Оба объявлены go_rules_dependenties. Вам не нужно будет объявлять явную зависимость, если вы специально не захотите использовать другую версию. Инструкции по использованию другой версии см. в разделе «Переопределение зависимостей».
Зависимости gRPC не объявлены по умолчанию (их слишком много). Вы можете объявить их в WORKSPACE, используя go_repository. Возможно, вы захотите использовать репозитории обновлений газели, чтобы импортировать их из go.mod
.
Дополнительные сведения см. в разделе Зависимости Proto и зависимости gRPC. См. также Как избежать конфликтов.
После регистрации всех зависимостей вы можете объявить правила proto_library и go_proto_library для генерации и компиляции кода Go из файлов .proto.
load ( "@rules_proto//proto:defs.bzl" , "proto_library" )
load ( "@io_bazel_rules_go//proto:def.bzl" , "go_proto_library" )
proto_library (
name = "foo_proto" ,
srcs = [ "foo.proto" ],
deps = [ "//bar:bar_proto" ],
visibility = [ "//visibility:public" ],
)
go_proto_library (
name = "foo_go_proto" ,
importpath = "github.com/example/protos/foo_proto" ,
protos = [ ":foo_proto" ],
visibility = [ "//visibility:public" ],
)
Цель go_proto_library
может быть импортирована и зависеть от нее, как и от обычной go_library
.
Обратите внимание, что последние версии Rules_go поддерживают как APIv1 ( github.com/golang/protobuf
), так и APIv2 ( google.golang.org/protobuf
). По умолчанию код генерируется с помощью github.com/golang/protobuf/cmd/protoc-gen-gen
для совместимости с обоими интерфейсами. Клиентский код может импортировать использование либо библиотеки времени выполнения, либо обеих.
Идти
Буферы протокола
Зависимости и тестирование
Да, но не напрямую.
Rules_go напрямую вызывает компилятор и компоновщик Go на основе целей, описанных в go_binary и других правилах. Bazel и Rules_go вместе выполняют ту же роль, что и команда go
, поэтому нет необходимости использовать команду go
в рабочей области Bazel.
Тем не менее, обычно все же рекомендуется следовать соглашениям, требуемым командой go
(например, один пакет на каталог, пути к пакетам совпадают с путями к каталогам). Инструменты, несовместимые с Bazel, по-прежнему будут работать, и от вашего проекта могут зависеть проекты, не принадлежащие Bazel.
Если вам нужно использовать команду go
для выполнения задач, которые не охватывает Bazel (например, добавления новой зависимости к go.mod
), вы можете использовать следующий вызов Bazel для запуска двоичного файла go
Go SDK, настроенного в Bazel:
bazel run @io_bazel_rules_go//go -- < args >
Предпочитайте этот вариант непосредственному запуску go
поскольку он гарантирует, что версия Go идентична той, которая используется Rules_go.
Да, но не напрямую. Bazel игнорирует файлы go.mod
, а все зависимости пакетов должны быть выражены через атрибуты deps
в целях, описанных с помощью go_library и других правил.
Вы можете загрузить модуль Go определенной версии в качестве внешнего репозитория, используя go_repository, правило рабочей области, предоставляемое gaselle. Это также создаст файлы сборки с использованием gaselle.
Вы можете импортировать правила go_repository из файла go.mod
используя репозиторий обновлений газели.
Это использовалось для обеспечения согласованности путей импорта в библиотеках, которые можно было собрать с помощью go build
до того, как атрибут importpath
стал доступен.
Для правильной компиляции и компоновки Rules_go должен знать путь импорта Go (строку, по которой можно импортировать пакет) для каждой библиотеки. Теперь это задается явно с помощью атрибута importpath
. До появления этого атрибута путь импорта определялся путем объединения строки из специального правила go_prefix
и имени пакета и метки библиотеки. Например, если go_prefix
был github.com/example/project
, для библиотеки //foo/bar:bar
Rules_go будет определять путь импорта как github.com/example/project/foo/bar/bar
. Заикание в конце несовместимо с go build
, поэтому, если имя метки было go_default_library
, путь импорта не будет ее включать. Итак, для библиотеки //foo/bar:go_default_library
путь импорта будет github.com/example/project/foo/bar
.
Поскольку go_prefix
был удален и атрибут importpath
стал обязательным (см. #721), имя go_default_library
больше не служит никакой цели. Мы можем решить прекратить его использование в будущем (см. № 265).
Вы можете выполнить кросс-компиляцию, установив флаг --platforms
в командной строке. Например:
$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 //cmd
По умолчанию cgo отключен при кросс-компиляции. Для кросс-компиляции с cgo добавьте суффикс _cgo
к целевой платформе. Чтобы это работало, вам необходимо зарегистрировать набор инструментов для кросс-компиляции C/C++ в Bazel.
$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64_cgo //cmd
Источники, специфичные для платформы, с тегами сборки или суффиксами имен файлов автоматически фильтруются во время компиляции. Вы можете выборочно включать зависимости, специфичные для платформы, с помощью выражений select
(Газель делает это автоматически).
go_library (
name = "foo" ,
srcs = [
"foo_linux.go" ,
"foo_windows.go" ,
],
deps = select ({
"@io_bazel_rules_go//go/platform:linux_amd64" : [
"//bar_linux" ,
],
"@io_bazel_rules_go//go/platform:windows_amd64" : [
"//bar_windows" ,
],
"//conditions:default" : [],
}),
)
Чтобы создать конкретную цель go_binary для целевой платформы или использовать конкретную версию golang SDK, используйте правило go_cross_binary. Это полезно для создания нескольких двоичных файлов для разных платформ в одной сборке.
Чтобы создать конкретную цель go_test для целевой платформы, установите атрибуты goos
и goarch
для этого правила.
Вы также можете зависеть от правила go_binary или go_test посредством перехода конфигурации Bazel на //command_line_option:platforms
(есть проблемы с этим подходом до Rules_go 0.23.0).
Bazel выполняет тесты в «песочнице», что означает, что тесты не имеют автоматического доступа к файлам. Вы должны включить тестовые файлы, используя атрибут data
. Например, если вы хотите включить все в каталог testdata
:
go_test (
name = "foo_test" ,
srcs = [ "foo_test.go" ],
data = glob ([ "testdata/**" ]),
importpath = "github.com/example/project/foo" ,
)
По умолчанию тесты запускаются в каталоге файла сборки, в котором они определены. Обратите внимание, что это соответствует соглашению о тестировании Go, а не соглашению Bazel, которому следуют другие языки, которые запускаются в корне репозитория. Это означает, что вы можете получить доступ к тестовым файлам, используя относительные пути. Вы можете изменить тестовый каталог, используя атрибут rundir
. См. go_test.
Gazelle автоматически добавит атрибут data
, подобный приведенному выше, если у вас есть каталог testdata
, если только он не содержит файлы .go для сборки или файлы сборки, и в этом случае testdata
обрабатывается как обычный пакет.
Обратите внимание, что в Windows файлы данных недоступны для тестов напрямую, поскольку файлы тестовых данных основаны на символических ссылках, и по умолчанию Windows не позволяет непривилегированным пользователям создавать символические ссылки. Вы можете использовать библиотеку github.com/bazelbuild/rules_go/go/tools/bazel для доступа к файлам данных.
Местоположение, в которое go_binary
записывает свой исполняемый файл, не является стабильным в разных версиях Rules_go, и от него не следует зависеть. Родительский каталог включает в себя некоторые данные конфигурации. Это предотвращает отравление кеша Bazel, когда один и тот же двоичный файл собирается в разных конфигурациях. Двоичное базовое имя также может зависеть от платформы: в Windows мы добавляем расширение .exe.
Чтобы зависеть от исполняемого файла в правиле go_test
, укажите ссылку на исполняемый файл в атрибуте data
(чтобы сделать его видимым), а затем разверните местоположение в args
. Реальное местоположение будет передано тесту в командной строке. Например:
go_binary (
name = "cmd" ,
srcs = [ "cmd.go" ],
)
go_test (
name = "cmd_test" ,
srcs = [ "cmd_test.go" ],
args = [ "$(location :cmd)" ],
data = [ ":cmd" ],
)
См. //tests/core/cross полный пример теста, обращающегося к двоичному файлу.
Альтернативно вы можете установить атрибут out
go_binary для конкретного имени файла. Обратите внимание: если установлен out
, двоичный файл не будет кэшироваться при изменении конфигурации.
go_binary (
name = "cmd" ,
srcs = [ "cmd.go" ],
out = "cmd" ,
)
go_test (
name = "cmd_test" ,
srcs = [ "cmd_test.go" ],
data = [ ":cmd" ],
)
См. раздел «Как избежать конфликтов» в документации по прототипу.
Это не поддерживается. При использовании go_proto_library с компилятором @io_bazel_rules_go//proto:go_grpc
к @org_golang_google_grpc//:go_default_library
добавляется неявная зависимость. Если вы свяжете другую копию того же пакета с //vendor/google.golang.org/grpc:go_default_library
или где-либо еще, у вас могут возникнуть конфликты во время компиляции или выполнения.
Если вы используете Gazelle с включенной генерацией прото-правил, импорт google.golang.org/grpc
будет автоматически разрешаться в @org_golang_google_grpc//:go_default_library
во избежание конфликтов. В этом случае следует игнорировать предоставленный поставщиком gRPC.
Если вам конкретно необходимо использовать пакет gRPC, предоставленный поставщиком, лучше вообще избегать использования go_proto_library
. Вы можете вернуть предварительно созданные файлы .pb.go и создать их с помощью правил go_library
. Gazelle будет генерировать эти правила, когда генерация прото-правил отключена (добавьте # gazelle:proto disable_global
в корневой файл сборки).
Инструкции по переопределению репозиториев, объявленных в go_rules_dependents, см. в разделе «Переопределение зависимостей».
Ссылки:
Чтобы запустить тесты Bazel на Travis CI, вам необходимо установить Bazel в сценарии before_install
. См. наш файл конфигурации, указанный выше.
Вам потребуется запустить Bazel с рядом флагов, чтобы предотвратить потребление огромного объема памяти в тестовой среде.
--host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m
: установите максимальный и начальный размер кучи JVM. Сохранение того же означает, что JVM не будет тратить время на увеличение кучи. Выбор размера кучи несколько произволен; в других файлах конфигурации рекомендуются ограничения до 2500 м. Более высокие значения означают более быструю сборку, но более высокий риск уничтожения OOM.--bazelrc=.test-bazelrc
: использовать файл конфигурации Bazel, специфичный для Travis CI. Сюда можно поместить большинство оставшихся опций.build --spawn_strategy=standalone --genrule_strategy=standalone
: отключить песочницу для сборки. Песочница может не работать внутри контейнеров Трэвиса, поскольку системный вызов mount
не разрешен.test --test_strategy=standalone
: также отключить песочницу для тестов.--local_resources=1536,1.5,0.5
: установить ограничения Bazel на доступную оперативную память в МБ, доступные ядра для вычислений и доступные ядра для ввода-вывода. Более высокие значения означают более быструю сборку, но более высокую конкуренцию и риск уничтожения OOM.--noshow_progress
: Подавить сообщения о ходе выполнения в выводе для очистки журналов.--verbose_failures
: получить более подробные сообщения об ошибках.--test_output=errors
: Показать тестовый поток stderr в журнале Travis. Обычно выходные данные теста представляют собой записанные файлы журналов, которые Трэвис не сохраняет и не сообщает. Загрузки на Travis происходят относительно медленно (сеть сильно конкурирует), поэтому вам следует минимизировать количество сетевых операций ввода-вывода в вашей сборке. Загрузка Bazel и Go SDK — огромная часть этого. Чтобы избежать загрузки Go SDK, вы можете запросить контейнер с предустановленной версией Go в файле .travis.yml
, а затем вызвать go_register_toolchains(go_version = "host")
в файле WORKSPACE
, специфичном для Travis.
У вас может возникнуть соблазн поместить кеш Базеля в кеш Трэвиса. Хотя это может значительно ускорить вашу сборку, Travis хранит свой кеш на Amazon, и его передача занимает очень много времени. На практике чистые сборки кажутся быстрее.
Rules_go поддерживает только официальные выпуски Go SDK. Однако вы все равно можете протестировать бета-версии и версии RC, передав version
типа "1.16beta1"
в go_register_toolchains. См. также go_download_sdk.
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
go_rules_dependencies ()
go_register_toolchains ( version = "1.17beta1" )