Macros

Macro creation

A macro is a function called from the BUILD file that can instantiate rules.
Macros don’t give additional power, they are just used for encapsulation and
code reuse. By the end of the loading phase,
macros don’t exist anymore, and Bazel sees only the set of rules they created.

Native rules (i.e. rules that don’t need a load() statement) can be
instantiated from the native module, e.g.

If you need to know the package name (i.e. which BUILD file is calling the
macro), use the function native.package_name().

Debugging

bazel query --output=build //my/path:all will show you how the BUILD file
looks after evaluation. All macros, globs, loops are expanded. Known
limitation: select expressions are currently not shown in the output.

You may filter the output based on generator_function (which function
generated the rules) or generator_name (the name attribute of the macro),
e.g.

To find out where exactly the rule foo is generated in a BUILD file, you
can try the following trick. Insert this line near the top of the BUILD
file: cc_library(name = "foo"). Run Bazel. You will get an exception when
the rule foo is created (due to a name conflict), which will show you the
full stack trace.

You can also use print for debugging. It displays
the message as a warning during the loading phase. Except in rare cases,
either remove print calls, or make them conditional under a debugging
parameter that defaults to False before submitting the code to the depot.

Errors

If you want to throw an error, use the fail function.
Explain clearly to the user what went wrong and how to fix their BUILD file. It
is not possible to catch an error.

In BUILD files, the name argument of the macros must be a keyword argument
(not a positional argument).

The name attribute of rules generated by a macro should include the name
argument as a prefix. For example, macro(name = "foo") can generate a
cc_libraryfoo and a genrule foo_gen.

In most cases, optional parameters should have a default value of None.
None can be passed directly to native rules, which treat it the same as if
you had not passed in any argument. Thus, there is no need to replace it
with 0, False, or [] for this purpose. Instead, the macro should defer
to the rules it creates, as their defaults may be complex or may change over
time. Additionally, a parameter that is explicitly set to its default value
looks different than one that is never set (or set to None) when accessed
through the query language or build-system internals.

Macros should have an optional visibility argument.

Full example

The typical use-case for a macro is when you want to reuse a genrule, e.g.