I’ve written about Bazel transitions multiple times: first when demonstrating rule extensions, and then when explaining split transitions.

Now I want to showcase a community-built way to apply transitions more easily.

Enter with_cfg.bzl

with_cfg.bzl is a convenient way to apply Bazel transitions. It was created by well-known community member Fabian, and I can’t recommend it enough.

Applying a transition to a plain swift_library

Say we want to ensure that our swift_library is always built with --compilation_mode=opt. We can achieve that quite easily with the following .bzl file:

load("@rules_swift//swift:swift_library.bzl", "swift_library")
load("@with_cfg.bzl", "with_cfg")

opt_swift_library, _opt_swift_library_internal = (
    with_cfg(swift_library)
        .set("compilation_mode", "opt")
        .build()
)

That’s it.

NOTE: You can ignore _opt_swift_library_internal. It needs to be assigned to a global variable because of Bazel’s restrictions on rule definitions, but you aren’t supposed to use it directly. Instead, use the generated opt_swift_library macro.

Finally, load opt_swift_library from the .bzl file containing the code above and use it just like a regular swift_library. The target and all its transitive dependencies will be built with the opt compilation mode.

Prior art

I won’t go into detail about what this would look like without with_cfg.bzl, as that’s already covered in my earlier articles.

Conclusion

Unfortunately, I discovered this way too late, but I’m glad it exists. It makes transitions much less tedious to write and reason about.