blob: caaffb5c3cd299b1fb8751768a91fbd6b42e9c4d [file] [view] [edit]
<!-- This file was previously generated by Stardoc but is now maintained
by humans. -->
Extending Gazelle
=================
Gazelle started out as a build file generator for Go projects, but it can be
extended to support other languages and custom sets of rules.
To extend Gazelle, you must do three things:
* Write a [go_library] with a function named `NewLanguage` that provides an
implementation of the [Language] interface. This interface provides hooks for
generating rules, parsing configuration directives, and resolving imports
to Bazel labels. By convention, the library's package name should match
the language (for example, `proto` or `bzl`).
* Write a [gazelle_binary](reference.md#gazelle_binary) rule. Include your library in the `languages`
list.
* Write a [gazelle] rule that points to your `gazelle_binary`. When you run
`bazel run //:gazelle`, your binary will be built and executed instead of
the default binary.
Tests
-----
To write tests for your gazelle extension, you can use [gazelle_generation_test](reference.md#gazelle_generation_test),
which will run a gazelle binary of your choosing on a set of test workspaces.
Supported languages
-------------------
Moved to [/README.rst](/README.rst#supported-languages)
Example
-------
Gazelle itself is built using the model described above, so it may serve as
an example.
[//language/proto:go_default_library] and [//language/go:go_default_library]
both implement the [Language]
interface. There is also [//internal/gazellebinarytest:go_default_library],
a stub implementation used for testing.
`//cmd/gazelle` is a `gazelle_binary` rule that includes both of these
libraries through the `DEFAULT_LANGUAGES` list (you may want to use
`DEFAULT_LANGUAGES` in your own rule).
```starlark
load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle_binary")
gazelle_binary(
name = "my_gazelle_binary",
languages = [
"@rules_python_gazelle_plugin//python", # Use gazelle from rules_python.
"@bazel_gazelle//language/go", # Built-in rule from gazelle for Golang.
"@bazel_gazelle//language/proto", # Built-in rule from gazelle for Protos.
# Any languages that depend on Gazelle's proto plugin must come after it.
"@external_repository//language/gazelle", # External languages can be added here.
],
visibility = ["//visibility:public"],
)
```
This binary can be invoked using a `gazelle` rule like this:
```starlark
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix example.com/project
gazelle(
name = "gazelle",
gazelle = ":my_gazelle_binary",
)
```
You can run this with `bazel run //:gazelle`.
Lazy indexing
-------------
Lazy indexing lets Gazelle run quickly without needing to read all build files
in a repo while still supporting index-based dependency resolution. This allows
Gazelle to update build files for specific directories in milliseconds rather
than seconds or minutes.
Lazy indexing requires a small amount of user configuration, pointing to
directories that may contain libraries based on import strings read from source
files. It also requires support from language extensions to interpret that
configuration. Most language extensions should implement this, though the
implementation will be a bit different for each language.
As an extended example, suppose a Go user has copied their module dependency
`example.com/b` into the directory `replace/b`. From some other directory `a`,
they import the package `example.com/b/c`. They then run
`gazelle update -r=false -index=lazy a` to generate a build file for `a` with
lazy indexing enabled.
In this configuration, Gazelle doesn't automatically index `replace/b`, so
the user must add a directive to their top-level build file:
```starlark
# gazelle:go_search replace/b example.com/b
```
This directive is interpreted by the Go extension. The user is telling Gazelle
to index the directory `replace/b/<suffix>` when it sees a Go package imported
with the string `example.com/b/<suffix>`. So in our example, when Gazelle sees
`example.com/b/c`, it indexes `replace/b/c` and makes all library targets
available for dependency resolution, including non-Go libraries that happen to
be there.
To support this, the Go extension needs to:
1. Support the `go_search` directive in the `KnownDirectives` and `Configure`
methods of the
[`Configurer`](https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/config#Configurer)
implementation. This directive may be repeated and applies in subdirectories.
1. Convert an import string like `example.com/b/c` into a list of directory
paths like `replace/b/c`.
1. Return the directory paths through
[`GenerateResult.RelsToIndex`](https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/language#GenerateResult)
in the
[`Language.GenerateRules`](https://pkg.go.dev/github.com/bazelbuild/bazel-gazelle/language#Language)
method.
Other extensions should follow a similar approach, though there are likely to
be differences in how `*_search` directives and import strings are interpreted.
For example, the protobuf and C++ extensions have `proto_search` and `cc_search`
directives which are similar to each other but not to Go: both languages
import libraries by file name and have similar conventions.
Interacting with protos
-----------------------
The proto extension ([//language/proto:go_default_library]) gathers metadata
from .proto files and generates `proto_library` rules based on that metadata.
Extensions that generate language-specific proto rules (e.g.,
`go_proto_library`) may use this metadata.
For API reference, see the [proto godoc].
To get proto configuration information, call [proto.GetProtoConfig]. This is
mainly useful for discovering the current proto mode.
To get information about `proto_library` rules, examine the `OtherGen`
list of rules passed to `language.GenerateRules`. This is a list of rules
generated by other language extensions, and it will include `proto_library`
rules in each directory, if there were any. For each of these rules, you can
call `r.PrivateAttr(proto.PackageKey)` to get a [proto.Package] record. This
includes the proto package name, as well as source names, imports, and options.
[Language]: https://godoc.org/github.com/bazelbuild/bazel-gazelle/language#Language
[//internal/gazellebinarytest:go_default_library]: https://github.com/bazelbuild/bazel-gazelle/tree/master/internal/gazellebinarytest
[//language/go:go_default_library]: https://github.com/bazelbuild/bazel-gazelle/tree/master/language/go
[//language/proto:go_default_library]: https://github.com/bazelbuild/bazel-gazelle/tree/master/language/proto
[gazelle]: https://github.com/bazelbuild/bazel-gazelle#bazel-rule
[go_binary]: https://github.com/bazelbuild/rules_go/blob/master/go/core.rst#go-binary
[go_library]: https://github.com/bazelbuild/rules_go/blob/master/go/core.rst#go-library
[proto godoc]: https://godoc.org/github.com/bazelbuild/bazel-gazelle/language/proto
[proto.GetProtoConfig]: https://godoc.org/github.com/bazelbuild/bazel-gazelle/language/proto#GetProtoConfig
[proto.Package]: https://godoc.org/github.com/bazelbuild/bazel-gazelle/language/proto#Package