RSSAmplifier

Blog

Adin Ćebić

adincebic.comRSS feed ↗26 posts

Latest posts

Profiling Starlark Memory Usage in Bazel

When using Bazel within a large monorepo, there comes a time when memory starts becoming a problem, and it is important to be aware of the available tools that can help with diagnosis. Fortunately, Bazel offers Starlark memory profiling, which we can utilize to see how much memory is being swallowed by the analysis phase. Setting up Surprisingly, it is a little tedious to set this up, but in the…

Testing Bazel Remote Build Execution Locally with actiond

When configuring remote build execution, it is very important to test changes locally so you don’t waste time on CI. A lot of the time, people don’t even have access to an RBE environment. Yes, BuildBuddy offers their service for free for open-source projects, but I feel like having access to an RBE environment locally is invaluable. I only recently started utilizing RBE more…

Less Boilerplate for Bazel Transitions

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…

Pruning Unused Action Inputs in Bazel

Bazel has grown significantly since its initial open-source release, and it is hard to keep up with every release. One useful feature that may have slipped past you is unused_inputs_list , a parameter of ctx.actions.run(...) that lets an action report which of its declared inputs it did not actually use. After the action executes successfully, Bazel can prune those files from the action’s…

A Note on Bazel’s config.exec()

When writing a rule that executes in the exec configuration, we need to communicate that to Bazel so it doesn’t attempt to build it for the target configuration: generator = rule( implementation = _generator_impl, ..., cfg = "exec", ) While there is nothing wrong with cfg = "exec" , my opinion is that we should use the newer transition object API. This means that instead of: cfg = "exec" we use:…

Making Bazel Module Extensions Work Together with override_repo

Recently, I have noticed more rulesets adopting Bzlmod-specific features. With Bazel 6 no longer supported and Bzlmod adoption continuing across the ecosystem, rulesets can increasingly rely on newer module APIs. One feature that caught my attention while I was setting up a hermetic Android toolchain is the ability to override a repository generated by a module extension. override_repo requires…

Stamping iOS Builds with Bazel

Stamping is the act of embedding build metadata into the product that we ship to customers. It can help with issue diagnosis, analytics, and so on. Conveniently, Bazel offers us a first-class solution, and it is very easy to take advantage of it in the context of iOS apps. Workspace status script The first step in enabling stamping is to create a workspace status script. For example, we can create…

Making Developer Tools Available Through Bazel

Traditionally, when setting up a developer machine, instructions include something like “install the following tools using Homebrew”. What if we could always have tools available without asking developers to install anything but Bazel? This is easily achievable with Bazel since it gives us a way to download and execute binaries. Before diving into the implementation, let’s first…

Avoiding .DS_Store Cache Misses in Bazel

It is well known that macOS Finder .DS_Store files should never be checked in to a repo, or leave the single machine for that matter. Fairly recently, I noticed that a lot of my iOS resource processing actions were missing the cache for seemingly no reason. That is, until I looked at the Bazel action inputs. There, I noticed that every action that missed the cache had an extra input. Of course, it…

External Repo File Checks In Bazel 9

In a quest to speed up Bazel builds we tend to pick every available low-hanging fruit once somebody discovers it. One of those used to be telling Bazel not to check external repos for file changes, since that can take a while in a dependency-heavy repo. Prior Art Historically we used --noexperimental_check_external_repository_files to skip checks for files in external repositories. That flag still…

Cleaning up old Bazel patterns

From time to time, it is worth cleaning up old Bazel stuff in your repositories. This is especially useful before a major Bazel upgrade, because it reduces the amount of migration noise you need to deal with. Most of these cleanups are not difficult, but they make the codebase a little easier to deal with. The suggestions below are relevant if you are on Bazel 8.1.0 or newer. Sets Starting with…

Running Multiple Bazel Targets in a Single Invocation

There are many instances where it would be really convenient to run multiple targets at once. By default, Bazel will not execute all targets even if you pass multiple ones: bazel run //:lint //:format In this case, only one of them would be executed. Enter rules_multirun rules_multirun is a set of rules that helps with running multiple targets either sequentially or in parallel. It is developed…

Suppressing Warnings in External Swift Dependencies with Bazel

It’s very common to want to apply some Bazel feature only to your first-party repo while omitting external dependencies. A common case in the Swift world is suppressing warnings for external dependencies brought in by rules_swift_package_manager , since we usually can’t do much about third-party code. There are countless other examples too, like treating warnings as errors for our own code while…

Hot Reloading a Bazel-Based iOS App with InjectionNext

When working on a medium to large iOS app, it can be daunting to constantly rebuild and manually go through app screens just to test your changes. Yes, Xcode previews exist, but in my experience, they can be slow on larger projects. They also require real code in the preview setup, which can be tricky to get right if you use dependency injection, since the code that registers all the dependencies…

A Practical Introduction to Bazel Persistent Workers

Typically, Bazel rules execute actions that usually correspond to tool processes on the host OS. Sometimes this behavior can incur startup costs, like bootstrapping a JVM or initializing a compiler. To work around that, Bazel has the concept of persistent workers . A persistent worker is essentially a long-lived process that accepts work requests and responds with work responses. Imagine a process…

Why My Xcode Extension Kept Asking for File Permissions

Recently, I worked on developing an Xcode source editor extension that needed to run some of our internal code formatters. These formatters are driven by configuration files that define how the tools should be executed. Because Xcode extensions must be sandboxed, they can’t directly access arbitrary file locations, including these configuration files. To work around this, we used a container app…

Centralizing Dependency Fetching in Bazel with the Remote Asset API

It has become increasingly common for major providers to experience outages—from Git servers being unavailable to failures when downloading external dependencies. There are several ways to work around this, such as internal mirrors, vendoring dependencies, and similar approaches. While effective, these solutions can feel somewhat heavy-handed. Bazel Remote Asset API The Bazel Remote Asset API…

A Better Way to Ignore Files in Bazel with repo.bazel

In the Bazel world, we don’t always want it to track all the files in our repository. A typical example is ignoring the .git directory, as it can grow quite large over time. Additionally, some IDE integrations like rules_xcodeproj don’t work particularly well when it is present. Traditionally, to instruct Bazel to ignore directories and files, we used the .bazelignore file, which requires…

Reconfiguring bazel downloader

There are many security as well as practical reasons why one might need to reconfigure Bazel’s downloading behavior. One concrete case that I ran into fairly recently was Google rate-limiting our CI for an unknown reason. To work around that, I needed to redirect the downloader to a mirror. There are many ways to achieve that, like patching individual rules (tedious), using an internal…

Bazel Output Groups: Producing Outputs on Demand

Typically, when writing a Bazel rule, we produce outputs using the DefaultInfo provider. However, there are cases where we want to produce additional outputs only on demand. Enter output groups Simply put, output groups are a way to tell Bazel to produce different sets of outputs instead of—or in addition to—the default outputs. For example, we might want to generate debug symbols, but we don’t…

What Bazel Really Runs (and How to See It)

There comes a time when working with Bazel when we want to understand the command-line flags used to build our code. For example, you might want to see what flags are being passed to swiftc . Up until Bazel 9, we would typically rely on --subcommands , but it could get quite verbose. Action graph query In addition to the standard bazel query command, there are also bazel cquery (configurable…

Bazel split transitions

A couple of articles ago, I touched on Bazel transitions. In that context, I was referring to 1:1 transitions—transitions that change the single configuration of a target. Split transitions, on the other hand, are 1:N, meaning they build the same target in multiple configurations. Multi-arch build An obvious example where split transitions are useful is multi-platform (or multi-architecture)…

How to Fix Xcode Source Editor Extensions That Don’t Appear in the Editor Menu

Recently I needed to develop my own Xcode source editor extension. The reasons for doing so aren’t relevant here, but the process quickly led me into an unexpected roadblock. TL;DR: In your extension target settings, set XcodeKit.framework → “Embed without signing” under the General tab. Extension not showing up in Xcode After following Apple’s official guide for creating a source editor extension…

Managing Bazel Flags in Monorepos with Flagsets (PROJECT.scl)

Bazel’s flagsets, or PROJECT.scl , are an approach aimed at solving project-specific flags in a monorepo. It leverages Starlark as its language, or more precisely, a subset of Starlark. This is in contrast to the traditional .bazelrc , which uses its own line-based language and has no formal specification. Current state of the art At the time of writing this, we are almost certainly all…

Composing Bazel rules with subrules

Bazel subrules are a lesser-known mechanism for splitting rule functionality into smaller, reusable building blocks. They are designed to improve rule architecture by encapsulating implicit dependencies, toolchains, and action logic — without passing the entire ctx (“god object”) around. In the past, we achieved similar reuse through plain Starlark helper functions. While that works, it often…

Applying Bazel Transitions to Third-Party Rules the Right Way

Historically, it has been tedious to apply transitions to rules we don’t control. You either had to maintain a fork, apply a patch, or wrap the rule — which is particularly annoying because you then have to manually forward the providers of the underlying rule. Enter Rule Extensions Bazel 8 introduced rule extensions, which allow you to augment an existing rule — somewhat similar to subclassing in…