Patching Bazel external dependencies

Posted

When using Bazel you might find that you need to patch one of your external dependencies, be it source code for a third-party library or a Starlark rule set. The simple way to approach this is to fork the dependency, push your changes, and point to your fork instead of the source. While this is simple, I would argue it’s not easy, as you now have to maintain a fork, which has some downsides:

Using patches

Instead of forking your dependency, I recommend using the patches attribute on the http_archive and git_repository rules. The attribute takes a list of labels for the patches to apply, in the order provided.

If you use git diff or git format-patch to produce your patches, you’ll also need to supply -p1 to patch_args.

Using patches addresses the issues I mentioned above:

Creating patches

My preferred way of creating patches involves checking out the dependency locally and using the --override_repository flag (e.g. ‑‑override_repository=build_bazel_rules_swift=/Users/bj/dev/rules_swift). This allows you to iterate on your patch without having to produce patch files or adjust your WORKSPACE file.

Once your changes are finalized, I recommend committing them to your checked out dependency’s repository. This will make updating the patch in the future easier. You’ll be able to rebase your commits with relative ease and generate new patches.

If you committed your changes, then running git format-patch --keep-subject --no-stat --zero-commit origin/main will produce a patch file for each commit that differs from origin/main. Move these into your workspace somewhere and reference them in the patches attribute.

I recommend publishing these commits to a private fork. This allows your teammates to easily update the patches (following the steps in the next section).

.bazelrc

If you find yourself editing your external dependencies a lot (e.g. if you are a maintainer of some Starlark rule sets 😬), you can add the --override_repository flags to your ~/.bazelrc:

~/.bazelrc
build:ora --override_repository=build_bazel_rules_apple=/Users/bj/dev/rules_apple
build:ors --override_repository=build_bazel_rules_swift=/Users/bj/dev/rules_swift

And then whenever you want to use your locally checked out dependency, just pass the corresponding --config:

$ bazel build --config=ors -- //Foo:Bar

Updating patches

If you committed your patches to your locally checked out dependency, then updating them is as easy as rebasing.

After rebasing, check that your changes work with --override_repository. Once your commits are in a good state, regenerate your patches, override the ones you already have in your workspace, and update your WORKSPACE file to point to the commit that you rebased onto.