11

I want a Bazel rule that is able to build multiple targets at once. So basically something like this:

build_all(
  name = "build_all",
  targets = [
    "//services/service1:build",
    "//services/service2:build",
    "//services/service3:build",
  ]
)

So I would just run

bazel build //:build_all

to build all my services with one simple command (and the same for testing). But I couldn't find any current solutions.

Is there a way to achieve this?

3
  • I googled and found this. Maybe it helps: github.com/atlassian/bazel-tools/tree/master/multirun
    – Héctor
    Commented Feb 1, 2020 at 21:40
  • Yeah, I've tried it a few minutes ago, but it seems only to work for "runnable" targets. Tests and builds gave me an error. But maybe you can prove me wrong :) Commented Feb 1, 2020 at 21:45
  • You should set your services as dependencies of build_all. Generally, "data" is the most flexible attribute for doing that. But also know that bazel build //... will build everything and bazel build //services/... will build everything under services. Commented Feb 1, 2020 at 22:03

5 Answers 5

16

It would appear that filegroup would be a ready made rule that could be abused for the purpose:

filegroup(
  name = "build_all",
  srcs = [
    "//services/service1:build",
    "//services/service2:build",
    "//services/service3:build",
  ]
)

It otherwise allows you to give a collective name to bunch of files (labels) to be passed conveniently along, but seems to work just as well as a summary target to use on the command line.

2
  • This does not work for me when py_binary rules are listed in srcs. It will silently not rebuild them when their sources are updated. So then I need to go back and call bazel build directly on the py_binary rules.
    – LolPython
    Commented Jun 8, 2021 at 20:54
  • What if I have to pass arguments for the build targets? ex: "bazel build //services/service1:build -- -arg1 -arg2"
    – Starfish
    Commented Mar 29, 2022 at 18:24
3

If you only want a subset of the build targets the other answers are probably better, but you could also try bazel build :all and bazel test :all

1
  • This also works with a specific package, see the Bazel docs for all scenarios.
    – ub_marco
    Commented Sep 20, 2023 at 8:29
2

Because I was trying to deploy multiple Kubernetes configurations I ended up using Multi-Object Actions for rules_k8s which then looks like:

load("@io_bazel_rules_k8s//k8s:objects.bzl", "k8s_objects")

k8s_objects(
   name = "deployments",
   objects = [
      "//services/service1:build",
      "//services/service2:build",
      "//services/service3:build",
   ]
)
1

You can also use --build_tag_filters to selectively build multiple targets with a given tags.

EDIT: --build_tag_filters is using OR logic. If you want to build target that satisfy multiple tags, I would suggest you to query it first, and then build the resulting target.

e.g.

QUERY="attr(tags, 'tag1', attr(tags, 'tag2', ...))"
BUILD_TARGETS=$(bazel query "$QUERY")
bazel build "$BUILD_TARGETS"
0

The suggestion to use a file group rule as a build-in rule to collect a bunch of dependencies works well if the dependencies are single files (like a cc_binary), but will not trigger creation and collection of auxiliary runfiles (like the labels under "data" in a py_binary) needed for some types of targets.

If you do want to build multiple targets at once, including their runfiles, the sh_binary built in rule with a simple no-opt script is also quite flexible, and you can specify an arbitrary list of targets in its data attribute. These targets will be considered runnable inputs to the sh_binary, and thus will trigger creation of the indirect targets themselves as well as all of their supplementary runtime data.

Not the answer you're looking for? Browse other questions tagged or ask your own question.