bazel tips and tricks

2023/07/30

Often needed little bits of bazel knowledge that I tend to forget.

Print errors inline

By default bazel prints the path to error logs. In development it is often more useful to see the error printed right away.

bazel test --test_output=errors //...

You can add:

test --test_output=errors

into your $HOME/.bazelrc as well.

Use an alternate repository

build --override_repository=com_google_protobuf=/abs/path/to/repo

This allows you to use an alternate source repository from the one declared in WORKSPACE, or worse, in dependencies. You can use that to generate a quick patch, or to provide a fix to upstream.

User bazelrc

in .bazelrc:

try-import %workspace%/user.bazelrc

Then create user.bazelrc in your workspace root and add it to .gitignore if you use git, so that it remains unique to you.

But, don’t forget that you have it.

Use rules_rust

Not sure why, but various bazel rules don’t seem to be documented well. While there are examples, there’s minimal explanation on how rules work. And the way rules work changes substantially across rules releases.

To fix this, I made a small but complete example of using rules_rust and its IDE integration via rust-project.json.

See it at: http://github.com/filmil/rust-bazel-example, refer to README.md for details.

Expand locations in a build rule

ctx.expand_location(val, ctx.attr.deps)

This expands any appearances of $(location <label>) in deps.

Examples of some of the above https://github.com/filmil/bazel-bats/blob/main/rules.bzl#L69

Template expansion

Generate a file based on a template.

Example: https://github.com/bazelbuild/examples/blob/main/rules/expand_template/hello.bzl

Release an archive with GitHub actions and Bazel

Here’s an example: https://github.com/filmil/bazoekt/blob/main/.github/workflows/release.yml

Packaging

Here is how to make a distribution zip archive.

With: https://github.com/bazelbuild/rules_pkg/tree/main/examples/rich_structure

pkg_files(
    name = "share_doc",
    srcs = [
        "//docs",
    ],
    # Where it should be in the final package
    prefix = "usr/share/doc/foo",
    # Required, but why?: see #354
    strip_prefix = strip_prefix.from_pkg(),
)

pkg_filegroup(
    name = "manpages",
    srcs = [
        "//src/client:manpages",
        "//src/server:manpages",
    ],
    prefix = "/usr/share",
)

pkg_tar(
    name = "foo_tar",
    srcs = [
        "README.txt",
        ":manpages",
        ":share_doc",
        "//resources/l10n:all",
        "//src/client:arch",
        "//src/server:arch",
    ],
)

pkg_zip(
    name = "foo_zip",
    srcs = [
        "README.txt",
        ":manpages",
        ":share_doc",
        "//resources/l10n:all",
        "//src/client:arch",
        "//src/server:arch",
    ],
)