Skip to content
EN

Back to the catalog

adincebic.com
jsonEnglish

Adin Ćebić

adincebic.com · English

json indieweb blogroll

Open the feed

https://adincebic.com/feed.json

Last post
Sep 20, 2026
Posts in 24 h · 7 days · 30 days
0 · 1 · 4
Our last check
Answering
Served from
United States
Site title
Adin Ćebić —
Text score at discovery
3,794
Format
json
Community
indieweb, blogroll

Posts

What our queue read from this feed. Open one to read it here, or go to the site that published it.

  1. Tree Artifacts Over ZIP Files in Bazel
    Sep 20, 2026 · original
    Typically, when writing Bazel rules, we output files as the final step, and that is what we need most of the time. However, today I want to make a case for outputting directories—or, as Bazel calls them, “tree artifacts.” There are many reasons to reach for a tree artifact instead of, say, a ZIP file. For one, zipping can be expensive and time-consuming, depending on the size and contents of the output. Every downstream action that needs the directory then has to unzip it again, adding more CPU work, disk I/O, and temporary files. Archives are also opaque blobs. By contrast, Bazel represents a tree artifact as a directory whose individual files are stored in the content-addressable store. The tree is still treated as a single declared output for dependency and action-cache purposes, but remote caching and remote execution can deduplicate the files it contains instead of repeatedly storin
  2. Exploring map_directory in Bazel 9
    Sep 13, 2026 · original
    In the world of Bazel, we prefer to be explicit as much as possible and register actions ahead of time. In fact, this is not just a preference but a strongly enforced rule that enables all the good stuff Bazel gives us. However, there is a world where a bit of dynamism is useful—or, in some cases, unavoidable. Today I am exploring the little-known map_directory API that was introduced in Bazel 9. Registering actions dynamically Say we write a rule that generates a couple of files and then want to register a separate Bazel action for each of those files. The Bazel API did not facilitate this use case before version 9. Sure, we could have resorted to all sorts of tricks and hacks, but there was no nice native way to register actions based on the contents of a generated directory. This is where map_directory comes in. It allows part of action registration to be deferred until execution time
  3. Bazel, APFS Clones, and Disk Space
    Sep 6, 2026 · original
    I was recently writing about the problem of disk space usage when building with Bazel due to its many caches. That led me to pay more attention to the work being done in this area, and I discovered that Bazel 9.3.0 is expected to make better use of copy-on-write cloning on macOS #30776 to avoid unnecessarily duplicating files between the disk cache and the output base. On APFS, this essentially means copy-on-write: the cloned files initially share the same underlying data blocks, so they don t immediately take up twice the physical disk space. If either copy is modified, the filesystem only needs to allocate storage for the changed blocks. Using APFS clones from Swift Naturally, I got interested in learning how this feature works, and it turns out to be pretty simple. There is a low-level API function, clonefile(...) , which does exactly what you would expect: it creates a copy-on-write
  4. How to Reduce Bazel Disk Space Usage Across Git Worktrees
    Aug 30, 2026 · original
    Ever since the advent of coding agents, a lot of engineers have started utilizing Git worktrees and, by extension, multiple Bazel output bases. We all know the story: Bazel caches tend to take up a lot of disk space when working with large projects. Manual deletion and garbage collection can only take you so far. Enter bb-clientd bb-clientd is a daemon that runs on your machine and can act as a local remote cache and proxy for Bazel. More importantly, it also implements Bazel s Output Service protocol , introduced in Bazel 7.2. This allows bb_clientd to manage Bazel s output tree through a virtual filesystem—FUSE on Linux and NFSv4 on macOS—and lazily materialize files when they are actually accessed. Combined with its content-addressed local cache, this means that multiple Bazel output bases can reuse the same cached content instead of each storing their own copies of identical files. T
  5. Preventing Transitive Swift Imports with Bazel
    Aug 23, 2026 · original
    Swift s permissive nature when it comes to module dependencies has always annoyed me and made my life a bit harder than I expected. Of course, I m talking about transitive module imports. You know the situation: there is a ModuleA which is a dependency of ModuleB , and if you declare ModuleB as a dependency of ModuleC , ModuleC can import ModuleA even though it never declared ModuleA as its own direct dependency. There are a lot of reasons why you might not want that, from making dependencies harder to visualize to enforcing a certain module structure, and so on. Unfortunately, Swift itself does not provide a mechanism to enforce direct module dependencies—or at least I don t know of one. Layering check via rules_swift One of the reasons I like working with Bazel is the flexibility it provides. One example of that is a feature in rules_swift called layering check , which prevents importi
  6. Profiling Starlark Memory Usage in Bazel
    Aug 16, 2026 · original
    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 end, it is not that difficult either. First, we need to download the allocation instrumenter JAR from Maven Central . Once that s on disk, we can start Bazel in memory tracking mode like so: bazel --host_jvm_args=-javaagent:/path/to/java-allocation-instrumenter-3.3.4.jar \ --host_jvm_args=-DRULE_MEMORY_TRACKER=1 \ build --nobuild //path/to/target Here, we start Bazel with memory tracking enabled and pass --nobuild so that only analysis is performed, which is what we want to measure. After analysi
  7. Testing Bazel Remote Build Execution Locally with actiond
    Aug 9, 2026 · original
    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 seriously, and while working through that setup I accidentally discovered actiond . I really wish I had known about it earlier. Having a remote executor that you can run locally makes experimenting with RBE, debugging issues, and checking whether your targets actually execute remotely much easier. actiond from hermeticbuild actiond is a full-fledged remote build executor that you can spin up easily simply by downloading it: curl -L \ https://github.com/hermeticbuild/actiond/releases/latest/download/darwin-actiond_ma
  8. Less Boilerplate for Bazel Transitions
    Aug 2, 2026 · original
    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 globa
  9. Pruning Unused Action Inputs in Bazel
    Jul 26, 2026 · original
    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 effective input set. On subsequent incremental builds, changing only one of the reported unused files will not cause the action to run again. This is post-execution dependency pruning , not pre-execution input discovery. The action still starts with all of its declared inputs. It reports unused inputs only after it has run. If the action later needs to execute again, Bazel restores the original input set first, because a previously unused input may be needed during the new execution. A natural use case
  10. A Note on Bazel’s config.exec()
    Jul 19, 2026 · original
    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: cfg = config.exec() Why? Apart from legitimate use cases such as transition composition and passing an exec group , I think using the object form is better for readability and discoverability. "exec" is a special string. You need to already know what it means and where it is supported. config.exec() , on the other hand, looks like an API. It is easier to discover, easier to search for, and makes it clearer that we are applying an execution transition. Passing the "exec" string is not deprecated,
  11. Making Bazel Module Extensions Work Together with override_repo
    Jul 12, 2026 · original
    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 Bazel 7.4.0 or newer and can only be used by the root module. Overriding a repository There are several reasons to override a repository generated by a module extension. It can simplify migrations by allowing existing call sites to keep using the same repository name. It can also avoid introducing multiple similarly named repositories. Most importantly, it gives module authors a way to provide a smoother developer experience when integrating with other rulesets. A good example is Keith’s hermetic
  12. Stamping iOS Builds with Bazel
    Jul 5, 2026 · original
    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 a script that emits the current Git commit hash: #!/usr/bin/env bash set -eu -o pipefail echo "STABLE_GIT_COMMIT $(git rev-parse HEAD)" Now we need to tell Bazel to execute the script: --workspace_status_command=./tools/workspace_status.sh Reading the value at build time For iOS apps, or really any Apple platform app, it is usually best to embed this data in a plist file so we can read it at runtime. First, we use a genrule to read the workspace status data and materialize a plist file: genrule
  13. Making Developer Tools Available Through Bazel
    Jun 28, 2026 · original
    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 explore the downsides of asking developers to install tools on their own. Problems with Homebrew for developer tools brew install … When developing on macOS, the default package manager is Homebrew, so we install tools like linters and formatters using it. However, it is not great for versioning in this use case. By default, we usually end up installing whatever version Homebrew currently resolves, unless we specifically do extra work to avoid that. This is the first problem: we can t expect people to ensure that
  14. Avoiding .DS_Store Cache Misses in Bazel
    Jun 21, 2026 · original
    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 was the .DS_Store file. The problem The problem popped up because of the act of balancing developer convenience and build correctness. Given the following glob pattern: resources = glob(["Assets.xcassets/**"]), we allow engineers to freely add or remove files in an iOS asset catalog without needing to constantly modify the list in the BUILD.bazel file. This, of course, means that .DS_Store files can get picked up if the engineer ever opened a Finder window at the given path. One might say that
  15. External Repo File Checks In Bazel 9
    Jun 14, 2026 · original
    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 exists in Bazel ( source ), and bazelrc-preset.bzl still sets it ( source ). Bazel 9 gained the repo contents cache via --repo_contents_cache . Cacheable external repos can now be served out of that cache. That matters because Bazel does not treat repo-contents-cache-backed files as the old EXTERNAL_REPO case. In the source they are tracked as EXTERNAL_OTHER instead. Bazel 9 also added --experimental_check_external_other_files to control checks for those paths.. Conclusion If you have repo cont
  16. Cleaning up old Bazel patterns
    Jun 7, 2026 · original
    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 Bazel 8.1, Starlark has native support for sets, which removes the need to use sets from bazel_skylib . So instead of: sets.make([1, 2, 3]) you can write: set([1, 2, 3]) Native sets support the usual set algebra, such as union, intersection, difference, and symmetric difference, so this should cover most use cases where you previously reached for bazel_skylib . Remove function_transition_allowlist when creating transitions The conventional wisdom used to be that you needed to create a private _all
  17. Running Multiple Bazel Targets in a Single Invocation
    May 31, 2026 · original
    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 and maintained by Keith Smiley . Running multiple targets It is extremely easy to get started. First, load the multirun rule and use it like this: load("@rules_multirun//:defs.bzl", "multirun") multirun( name = "xcodeproj", testonly = True, commands = ["//apps/app1:xcodeproj", "//apps/app2:xcodeproj"], jobs = 0, ) Here, I used the multirun rule to create a single runnable target that generates Xcode projects for two of my apps: bazel run //:xcodeproj Execution modes The jobs attribute specifies wh
  18. Suppressing Warnings in External Swift Dependencies with Bazel
    May 24, 2026 · original
    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 avoiding that for third-party deps. REPO.bazel to the rescue I wrote about REPO.bazel in an earlier article , where I explained how to replace .bazelignore with glob semantics. For the use cases described in the intro of this article, REPO.bazel is extremely useful. It lets us apply Bazel features, which I’ve also written about before , only to our own repo. Suppressing warnings in external Swift libraries To achieve this, we need to do two things. First, suppress warnings globally in .bazelrc :
  19. Hot Reloading a Bazel-Based iOS App with InjectionNext
    May 17, 2026 · original
    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 probably will not run, often leading to crashes. Enter InjectionNext InjectionNext is an app that uses the -interposable linker feature to dynamically swap classes so that changes are reflected without rebuilding the app. To set it up in a Bazel-based iOS project, I recommend the following: Integrate the InjectionNext Swift package using rules_swift_package_manager . Make sure to set the -interposable linker flag in debug mode only on your ios_application target: linkopts = select({ # InjectionN
  20. A Practical Introduction to Bazel Persistent Workers
    May 10, 2026 · original
    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 that keeps a compiler alive and dispatches sources to compile without paying the startup cost every time. Creating a rule that leverages workers Because this is a fairly advanced concept in Bazel, and usually only rule authors deal with it, I tried to come up with a simple example that demonstrates it. An uppercase rule We will write a rule that simply uppercases the text in a given file. To begin, we need to meet a few requirements. The first one is adding dependencies in our MODULE.bazel : ba

Discovered by the rss-feed-index crawler, which checks each feed at most once a month.

Same record as JSON: https://api.agentalog.com/api/feeds/fd_adincebic_com_549fad12b80335f2. More from this site: adincebic.com in the Feeds tab.