For most Bazel projects, I strongly recommend using a single Bazel workspace per source code repository. However, it can be occasionally useful to nest multiple workspaces within a single repository. For example, when I’m writing Bazel rulesets, I will often create test cases that contain own workspace with a slightly different configuration in order to test various workspace-level configuration settings for the ruleset, while maintaining a root workspace which is the primary workspace for the ruleset.
For example, let’s say I’m writing a ruleset named
compiling programs using a hypothetical programming language named
foo. I want to write tests for this ruleset to see if it can
successfully compile a program with a host-installed version of
the compiler as well as with a version of the compiler the ruleset
downloads itself. In order to do this, I’ll make one decision
in the root
WORKSPACE (usually to download the compiler) and then
include a test with a
WORKSPACE and a configuraiton that
uses a host-installed compiler.
To define a separate Bazel workspace, simply create a file named
WORKSPACE in the directory whcih denotes the root of the workspace.
Beware of the following caveats:
bazel build //...from the root workspace will build all targets, including the ones in the sub-workspaces. This means that all targets must build successfully with both the sub-workspace’s settings as well as the root workspace’s. When using this technique with Bazel rulesets, this means that the root workspace has the union of all settings necessary in order to build all targets, whereas sub-workspaces can have more specific or narrow settings.
- If you have paths in your
.bazelrc, they will be relative to the current workspace, where instead you probably want them relative to the root workspace. This can be fixed with a build script (see below).
To make building multiple workspaces from a single CI/CD pipeline easier, I typically use a variation of the below script: