When running a binary through Bazel with bazel run, we might find ourselves in a situation where it is desirable to wrap it in a “parent” binary or script. This could be to profile the running binary, fiddle with its environment, run it through a debugger, or any sort of thing really.

To achieve this, we could build the binary and then manually wrap it with whatever we want, but that is a bit tedious and perhaps prone to errors.

Using –run_under

Bazel has a flag specifically for this use case: --run_under. Simply put, it prepends a command to the executable being run.

It is a rather old Bazel feature — --run_under was already around in 2015, during the early days of the public Bazel project.

For example, if we wanted to measure the CPU time of a rules_xcodeproj executable target, we could do something like this:

bazel run //:xcodeproj --run_under="time"

This effectively results in Bazel running something along the lines of:

time <path-to-xcodeproj>

and we get the timing summary once the executable finishes.

The wrapper does not have to be a single command either. --run_under accepts a command prefix, so arguments can be passed to the wrapper as well. For example:

bazel run //:xcodeproj --run_under="time -p"

It is worth noting that --run_under is not specific to bazel run — it can also be used with bazel test.

Going further

Fortunately, this flag is not only able to wrap the binary with something available on the host OS. It can also refer to another executable Bazel target.

This means we can have a *_binary target in our repo and, by referring to it using normal Bazel target label syntax, Bazel will build both targets and use one to wrap the other:

bazel run //:xcodeproj --run_under="//tools:my_wrapper"

Conceptually, this becomes something like:

my_wrapper xcodeproj

This is particularly useful when the wrapper itself is part of the repository and we want Bazel to take care of building it rather than relying on some separately installed host tool.

Conclusion

In my opinion, this is yet another somewhat obscure Bazel feature that can come in handy in certain situations, as it did for me quite recently.