| --- |
| layout: documentation |
| title: Rules |
| --- |
| # Rules |
| |
| **Status: Experimental**. We may make breaking changes to the API, but we will |
| help you update your code. |
| |
| A rule defines a series of [actions](#actions) that Bazel should perform on |
| inputs to get a set of outputs. For example, a C++ binary rule might take a set |
| of `.cpp` files (the inputs), run `g++` on them (the action), and return an |
| executable file (the output). |
| |
| Note that, from Bazel's perspective, `g++` and the standard C++ libraries are |
| also inputs to this rule. As a rule writer, you must consider not only the |
| user-provided inputs to a rule, but also all of the tools and libraries required |
| to execute the actions (called _implicit inputs_). |
| |
| Before creating or modifying any rule, make sure you are familiar with the |
| [extensibility model](concepts.md) (understand the three phases and the |
| differences between macros and rules). |
| |
| ## Rule creation |
| |
| In a `.bzl` file, use the [rule](lib/globals.html#rule) |
| function to create a new rule and store it in a global variable: |
| |
| ```python |
| my_rule = rule(...) |
| ``` |
| |
| See [the cookbook](cookbook.md#empty) for examples. The rule can then be |
| loaded by BUILD files: |
| |
| ```python |
| load('//some/pkg:whatever.bzl', 'my_rule') |
| ``` |
| |
| A custom rule can be used just like a native rule. It has a mandatory `name` |
| attribute, you can refer to it with a label, and you can see it in |
| `bazel query`. |
| |
| The rule is analyzed when you explicitly build it, or if it is a dependency of |
| the build. In this case, Bazel will execute its `implementation` function. This |
| function decides what the outputs of the rule are and how to build them (using |
| [actions](#actions)). During the [analysis phase](concepts.md#evaluation-model), |
| no external command can be executed. Instead, actions are registered and |
| will be run in the execution phase, if their output is needed for the build. |
| |
| ## Attributes |
| |
| An attribute is a rule argument, such as `srcs` or `deps`. You must list |
| the attributes and their types when you define a rule. |
| |
| ```python |
| sum = rule( |
| implementation = _impl, |
| attrs = { |
| "number": attr.int(default = 1), |
| "deps": attr.label_list(), |
| }, |
| ) |
| ``` |
| |
| The following attributes are implicitly added to every rule: `deprecation`, |
| `features`, `name`, `tags`, `testonly`, `visibility`. Test rules also have the |
| following attributes: `args`, `flaky`, `local`, `shard_count`, `size`, |
| `timeout`. |
| |
| Labels listed in `attr` will be inputs to the rule. |
| |
| To access an attribute in a rule's implementation, use |
| `ctx.attr.<attribute_name>`. The name and the package of a rule are available |
| with `ctx.label.name` and `ctx.label.package`. |
| |
| See [an example](cookbook.md#attr) of using `attr` in a rule. |
| |
| ### <a name="private-attributes"></a> Private Attributes |
| |
| In Python, we use one leading underscore(`_`) for non-public methods and |
| instance variables (see [PEP-8][1]). |
| |
| Similarly, if an attribute name starts with `_` it is private and users cannot |
| set it. |
| It is useful in particular for label attributes (your rule will have an |
| implicit dependency on this label). |
| |
| ```python |
| metal_compile = rule( |
| implementation = _impl, |
| attrs = { |
| "srcs": attr.label_list(), |
| "_compiler": attr.label( |
| default = Label("//tools:metalc"), |
| allow_single_file = True, |
| executable = True, |
| ), |
| }, |
| ) |
| ``` |
| |
| ## Implementation function |
| |
| Every rule requires an `implementation` function. It contains the actual logic |
| of the rule and is executed strictly in the |
| [analysis phase](concepts.md#evaluation-model). The function has exactly one |
| input parameter, `ctx`, and it may return the [runfiles](#runfiles) |
| and [providers](#providers) of the rule. The input parameter `ctx` can be used |
| to access attribute values, outputs and dependent targets, and files. It also |
| has some helper functions. See [the library](lib/ctx.html) for more context. |
| Example: |
| |
| ```python |
| def _impl(ctx): |
| ... |
| return [DefaultInfo(runfiles=...), MyInfo(...)] |
| |
| my_rule = rule( |
| implementation = _impl, |
| ... |
| ) |
| ``` |
| |
| ## Files |
| |
| There are two kinds of files: files stored in the file system and generated |
| files. For each generated file, there must be one and only one generating |
| action, and each action must generate one or more output files. Bazel will throw |
| an error otherwise. |
| |
| ## Targets |
| |
| Every build rule corresponds to exactly one target. A target can create |
| [actions](#actions), can have dependencies (which can be files or |
| other build rules), [output files](#output-files) (generated by |
| its actions), and [providers](#providers). |
| |
| A target `y` depends on target `x` if `y` has a label or label list type |
| attribute where `x` is declared: |
| |
| ```python |
| my_rule( |
| name = "x", |
| ) |
| |
| my_rule( |
| name = "y", |
| deps = [":x"], |
| ) |
| ``` |
| |
| In the above case, it's possible to access targets declared in `my_rule.deps`: |
| |
| ```python |
| def _impl(ctx): |
| for dep in ctx.attr.deps: |
| # Do something with dep |
| ... |
| |
| my_rule = rule( |
| implementation = _impl, |
| attrs = { |
| "deps": attr.label_list(), |
| }, |
| ... |
| ) |
| ``` |
| |
| ## <a name="output-files"></a> Output files |
| |
| A target can declare output files, which must be generated by the target's |
| actions. There are three ways to create output files: |
| |
| * If the rule is marked `executable`, it creates an output file of the same name |
| as the rule's. [See example](https://github.com/bazelbuild/examples/blob/master/rules/executable/executable.bzl) |
| |
| * The rule can declare default `outputs`, which are always generated. |
| [See example](https://github.com/bazelbuild/examples/blob/master/rules/default_outputs/extension.bzl) |
| |
| * The rule can have output or output list type attributes. In that case the |
| output files come from the actual attribute values. |
| [See example](https://github.com/bazelbuild/examples/blob/master/rules/custom_outputs/extension.bzl) |
| |
| Each output file must have exactly one generating action. See the |
| [library](lib/ctx.html#outputs) for more context. |
| |
| ## Default outputs |
| |
| Every rule has a set of default outputs. This is used: |
| |
| * When the user runs `bazel build` on your target. Bazel will build the default |
| outputs of the rule. |
| |
| * When the target is used as a dependency of another rule. A rule can access |
| the default outputs by using [target.files](lib/Target.html#files). |
| This is the case, for example, if you use a rule in the `srcs` attribute of a |
| `genrule`. |
| |
| Use the `files` provider to specify the default outputs of a rule. |
| If left unspecified, it will contain all the declared outputs. |
| |
| ```python |
| def _impl(ctx): |
| # ... |
| return DefaultInfo(files=depset([file1, file2])) |
| ``` |
| |
| This can be useful for exposing files generated with |
| [ctx.actions.declare_file](lib/actions.html#declare_file). You can also |
| have "implicit outputs", i.e., files that are declared in the rule, but |
| not in the default outputs (like `_deploy.jar` in `java_binary`). |
| |
| ## Actions |
| |
| An action describes how to generate a set of outputs from a set of inputs, for |
| example "run gcc on hello.c and get hello.o". When an action is created, Bazel |
| doesn't run the command immediately. It registers it in a graph of dependencies, |
| because an action can depend on the output of another action (e.g. in C, |
| the linker must be called after compilation). In the execution phase, Bazel |
| decides which actions must be run and in which order. |
| |
| All functions that create actions are defined in [`ctx.actions`](lib/actions.html): |
| |
| * [ctx.actions.run](lib/actions.html#run), to run an executable. |
| * [ctx.actions.run_shell](lib/actions.html#run_shell), to run a shell command. |
| * [ctx.actions.write](lib/actions.html#write), to write a string to a file. |
| * [ctx.actions.expand_template](lib/actions.html#expand_template), to generate a file from a template. |
| |
| Actions take a set (which can be empty) of input files and generate a (non-empty) |
| set of output files. |
| The set of input and output files must be known during the |
| [analysis phase](concepts.md#evaluation-model). It might depend on the value |
| of attributes and information from dependencies, but it cannot depend on the |
| result of the execution. For example, if your action runs the unzip command, you |
| must specify which files you expect to be inflated (before running unzip). |
| |
| Actions are comparable to pure functions: They should depend only on the |
| provided inputs, and avoid accessing computer information, username, clock, |
| network, or I/O devices (except for reading inputs and writing outputs). This is |
| important because the output will be cached and reused. |
| |
| **If an action generates a file that is not listed in its outputs**: This is |
| fine, but the file will be ignored and cannot be used by other rules. |
| |
| **If an action does not generate a file that is listed in its outputs**: This is |
| an execution error and the build will fail. This happens for instance when a |
| compilation fails. |
| |
| **If an action generates an unknown number of outputs and you want to keep them |
| all**, you must group them in a single file (e.g., a zip, tar, or other |
| archive format). This way, you will be able to deterministically declare your |
| outputs. |
| |
| **If an action does not list a file it uses as an input**, the action execution |
| will most likely result in an error. The file is not guaranteed to be available |
| to the action, so if it **is** there, it's due to coincidence or error. |
| |
| **If an action lists a file as an input, but does not use it**: This is fine. |
| However, it can affect action execution order, resulting in sub-optimal |
| performance. |
| |
| Dependencies are resolved by Bazel, which will decide which actions are |
| executed. It is an error if there is a cycle in the dependency graph. Creating |
| an action does not guarantee that it will be executed: It depends on whether |
| its outputs are needed for the build. |
| |
| ## Configurations |
| |
| Imagine that you want to build a C++ binary and target a different architecture. |
| The build can be complex and involve multiple steps. Some of the intermediate |
| binaries, like the compilers and code generators, have to run on your machine |
| (the host); some of the binaries such the final output must be built for the |
| target architecture. |
| |
| For this reason, Bazel has a concept of "configurations" and transitions. The |
| topmost targets (the ones requested on the command line) are built in the |
| "target" configuration, while tools that should run locally on the host are |
| built in the "host" configuration. Rules may generate different actions based on |
| the configuration, for instance to change the cpu architecture that is passed to |
| the compiler. In some cases, the same library may be needed for different |
| configurations. If this happens, it will be analyzed and potentially built |
| multiple times. |
| |
| By default, Bazel builds the dependencies of a target in the same configuration |
| as the target itself, i.e. without transitioning. When a target depends on a |
| tool, the label attribute will specify a transition to the host configuration. |
| This causes the tool and all of its dependencies to be built for the host |
| machine, assuming those dependencies do not themselves have transitions. |
| |
| For each [label attribute](lib/attr.html#label), you can decide whether the |
| dependency should be built in the same configuration, or transition to the host |
| configuration (using `cfg`). If a label attribute has the flag |
| `executable=True`, the configuration must be set explicitly. |
| [See example](cookbook.md#execute-a-binary) |
| |
| In general, sources, dependent libraries, and executables that will be needed at |
| runtime can use the same configuration. |
| |
| Tools that are executed as part of the build (e.g., compilers, code generators) |
| should be built for the host configuration. In this case, specify `cfg="host"` |
| in the attribute. |
| |
| Otherwise, executables that are used at runtime (e.g. as part of a test) should |
| be built for the target configuration. In this case, specify `cfg="target"` in |
| the attribute. |
| |
| The configuration `"data"` is present for legacy reasons and should be used for |
| the `data` attributes. |
| |
| ## <a name="fragments"></a> Configuration Fragments |
| |
| Rules may access [configuration fragments](lib/skylark-configuration-fragment.html) |
| such as `cpp`, `java` and `jvm`. However, all required fragments must be |
| declared in order to avoid access errors: |
| |
| ```python |
| def _impl(ctx): |
| # Using ctx.fragments.cpp would lead to an error since it was not declared. |
| x = ctx.fragments.java |
| ... |
| |
| my_rule = rule( |
| implementation = _impl, |
| fragments = ["java"], # Required fragments of the target configuration |
| host_fragments = ["java"], # Required fragments of the host configuration |
| ... |
| ) |
| ``` |
| |
| `ctx.fragments` only provides configuration fragments for the target |
| configuration. If you want to access fragments for the host configuration, |
| use `ctx.host_fragments` instead. |
| |
| ## Providers |
| |
| Providers are pieces of information that a rule exposes to other rules that |
| depend on it. This data can include output files, libraries, parameters to pass |
| on a tool's command line, or anything else the depending rule should know about. |
| Providers are the only mechanism to exchange data between rules, and can be |
| thought of as part of a rule's public interface (loosely analogous to a |
| function's return value). |
| |
| A rule can only see the providers of its direct dependencies. If there is a rule |
| `top` that depends on `middle`, and `middle` depends on `bottom`, then we say |
| that `middle` is a direct dependency of `top`, while `bottom` is a transitive |
| dependency of `top`. In this case, `top` can see the providers of `middle`. The |
| only way for `top` to see any information from `bottom` is if `middle` |
| re-exports this information in its own providers; this is how transitive |
| information can be accumulated from all dependencies. In such cases, consider |
| using [depsets](depsets.md) to hold the data more efficiently without excessive |
| copying. |
| |
| Providers can be declared using the [provider()](lib/globals.html#provider) function: |
| |
| ```python |
| TransitiveDataInfo = provider() |
| ``` |
| |
| Rule implementation function can then construct and return provider instances: |
| |
| ```python |
| def rule_implementation(ctx): |
| ... |
| return [TransitiveDataInfo(value = ["a", "b", "c"])] |
| ``` |
| |
| `TransitiveDataInfo` acts both as a constructor for provider instances and as a key to access them. |
| A [target](lib/Target.html) serves as a map from each provider that the target supports, to the |
| target's corresponding instance of that provider. |
| A rule can access the providers of its dependencies using the square bracket notation (`[]`): |
| |
| ```python |
| def dependent_rule_implementation(ctx): |
| ... |
| s = depset() |
| for dep_target in ctx.attr.deps: |
| s += dep_target[TransitiveDataInfo].value |
| ... |
| ``` |
| |
| All targets have a [`DefaultInfo`](lib/globals.html#DefaultInfo) provider that can be used to access |
| some information relevant to all targets. |
| |
| Providers are only available during the analysis phase. Examples of usage: |
| |
| * [mandatory providers](cookbook.md#mandatory-providers) |
| * [optional providers](cookbook.md#optional-providers) |
| |
| > *Note:* |
| > Historically, Bazel also supported provider instances that are identified by strings and |
| > accessed as fields on the `target` object instead of as keys. This style is deprecated |
| > but still supported. Return legacy providers as follows: |
| > |
| ```python |
| def rule_implementation(ctx): |
| ... |
| modern_provider = TransitiveDataInfo(value = ["a", "b", "c"]) |
| # Legacy style. |
| return struct(legacy_provider = struct(...), |
| another_legacy_provider = struct(...), |
| # The `providers` field contains provider instances that can be accessed |
| # the "modern" way. |
| providers = [modern_provider]) |
| ``` |
| > To access legacy providers, use the dot notation. |
| > Note that the same target can define both modern and legacy providers: |
| > |
| ```python |
| def dependent_rule_implementation(ctx): |
| ... |
| s = depset() |
| for dep_target in ctx.attr.deps: |
| x = dep_target.legacy_provider # legacy style |
| s += dep_target[TransitiveDataInfo].value # modern style |
| ... |
| ``` |
| > **We recommend using modern providers for all future code.** |
| |
| ## Runfiles |
| |
| Runfiles are a set of files used by the (often executable) output of a rule |
| during runtime (as opposed to build time, i.e. when the binary itself is |
| generated). |
| During the [execution phase](concepts.md#evaluation-model), Bazel creates a |
| directory tree containing symlinks pointing to the runfiles. This stages the |
| environment for the binary so it can access the runfiles during runtime. |
| |
| Runfiles can be added manually during rule creation and/or collected |
| transitively from the rule's dependencies: |
| |
| ```python |
| def _rule_implementation(ctx): |
| ... |
| transitive_runfiles = depset() |
| for dep in ctx.attr.special_dependencies: |
| transitive_runfiles += dep.transitive_runtime_files |
| |
| runfiles = ctx.runfiles( |
| # Add some files manually. |
| files = [ctx.file.some_data_file], |
| # Add transitive files from dependencies manually. |
| transitive_files = transitive_runfiles, |
| # Collect runfiles from the common locations: transitively from srcs, |
| # deps and data attributes. |
| collect_default = True, |
| ) |
| # Add a field named "runfiles" to the DefaultInfo provider in order to actually |
| # create the symlink tree. |
| return [DefaultInfo(runfiles=runfiles)] |
| ``` |
| |
| Note that non-executable rule outputs can also have runfiles. For example, a |
| library might need some external files during runtime, and every dependent |
| binary should know about them. |
| |
| Also note that if an action uses an executable, the executable's runfiles can |
| be used when the action executes. |
| |
| Normally, the relative path of a file in the runfiles tree is the same as the |
| relative path of that file in the source tree or generated output tree. If these |
| need to be different for some reason, you can specify the `root_symlinks` or |
| `symlinks` arguments. The `root_symlinks` is a dictionary mapping paths to |
| files, where the paths are relative to the root of the runfiles directory. The |
| `symlinks` dictionary is the same, but paths are implicitly prefixed with the |
| name of the workspace. |
| |
| ```python |
| ... |
| runfiles = ctx.runfiles( |
| root_symlinks = {"some/path/here.foo": ctx.file.some_data_file2} |
| symlinks = {"some/path/here.bar": ctx.file.some_data_file3} |
| ) |
| # Creates something like: |
| # sometarget.runfiles/ |
| # some/ |
| # path/ |
| # here.foo -> some_data_file2 |
| # <workspace_name>/ |
| # some/ |
| # path/ |
| # here.bar -> some_data_file3 |
| ``` |
| |
| If `symlinks` or `root_symlinks` is used, be careful not to map two different |
| files to the same path in the runfiles tree. This will cause the build to fail |
| with an error describing the conflict. To fix, you will need to modify your |
| `ctx.runfiles` arguments to remove the collision. This checking will be done for |
| any targets using your rule, as well as targets of any kind that depend on those |
| targets. |
| |
| ## Output groups |
| |
| By default Bazel builds a target's |
| [default outputs](#default-outputs). However, a rule can also create |
| other outputs that are not part of a typical build but might still be useful, |
| such as debug information files. The facility for this is _output groups_. |
| |
| A rule can declare that a certain file belongs to a certain output group by returning |
| the [OutputGroupInfo](lib/globals.html#OutputGroupInfo) provider. Fields of |
| that provider are output group names: |
| |
| ```python |
| def _impl(ctx): |
| name = ... |
| binary = ctx.actions.declare_file(name) |
| debug_file = ctx.actions.declare_file(name + ".pdb") |
| # ... add actions to generate these files |
| return [DefaultInfo(files = depset([binary])), |
| OutputGroupInfo(debug_files = depset([debug_file]), |
| all_files = depset([binary, debug_file]))] |
| ``` |
| |
| By default, only the `binary` file will be built. |
| The user can specify an [`--output_groups=debug_files`](../command-line-reference.html#build) |
| flag on the command line. In that case, only `debug_file` will be built. If the user |
| specifies `--output_groups=all_files`, both `binary` and `debug_file` will be build. |
| |
| > Note: [OutputGroupInfo](skylark/lib/globals.html#OutputGroupInfo) is a regular |
| > [provider](#providers), and dependencies of a target can examine it using |
| > the `target[OutputGroupInfo]` syntax. |
| |
| ## Code coverage instrumentation |
| |
| A rule can use the `instrumented_files` provider to provide information about |
| which files should be measured when code coverage data collection is enabled: |
| |
| ```python |
| def _rule_implementation(ctx): |
| ... |
| return struct(instrumented_files = struct( |
| # Optional: File extensions used to filter files from source_attributes. |
| # If not provided, then all files from source_attributes will be |
| # added to instrumented files, if an empty list is provided, then |
| # no files from source attributes will be added. |
| extensions = ["ext1", "ext2"], |
| # Optional: Attributes that contain source files for this rule. |
| source_attributes = ["srcs"], |
| # Optional: Attributes for dependencies that could include instrumented |
| # files. |
| dependency_attributes = ["data", "deps"])) |
| ``` |
| |
| [ctx.config.coverage_enabled](lib/configuration.html#coverage_enabled) notes |
| whether coverage data collection is enabled for the current run in general |
| (but says nothing about which files specifically should be instrumented). |
| If a rule implementation needs to add coverage instrumentation at |
| compile-time, it can determine if its sources should be instrumented with |
| [ctx.coverage_instrumented](lib/ctx.html#coverage_instrumented): |
| |
| ```python |
| # Are this rule's sources instrumented? |
| if ctx.coverage_instrumented(): |
| # Do something to turn on coverage for this compile action |
| ``` |
| |
| Note that function will always return false if `ctx.config.coverage_enabled` is |
| false, so you don't need to check both. |
| |
| If the rule directly includes sources from its dependencies before compilation |
| (e.g. header files), it may also need to turn on compile-time instrumentation |
| if the dependencies' sources should be instrumented. In this case, it may |
| also be worth checking `ctx.config.coverage_enabled` so you can avoid looping |
| over dependencies unnecessarily: |
| |
| ```python |
| # Are this rule's sources or any of the sources for its direct dependencies |
| # in deps instrumented? |
| if ctx.config.coverage_enabled: |
| if (ctx.coverage_instrumented() or |
| any(ctx.coverage_instrumented(dep) for dep in ctx.attr.deps): |
| # Do something to turn on coverage for this compile action |
| ``` |
| |
| ## Executable rules |
| |
| An executable rule is a rule that users can run using `bazel run`. |
| |
| To make a rule executable, set `executable=True` in the |
| [rule function](lib/globals.html#rule). The `implementation` function of the |
| rule must generate the output file `ctx.outputs.executable`. |
| [See example](https://github.com/bazelbuild/examples/blob/master/rules/executable/executable.bzl) |
| |
| ## Test rules |
| |
| Test rules are run using `bazel test`. |
| |
| To create a test rule, set `test=True` in the |
| [rule function](lib/globals.html#rule). The name of the rule must |
| also end with `_test`. Test rules are implicitly executable, which means that |
| the `implementation` function of the rule must generate the output file |
| `ctx.outputs.executable`. |
| |
| [See example](https://github.com/bazelbuild/examples/blob/master/rules/test_rule/line_length.bzl) |
| |
| Test rules inherit the following attributes: `args`, `flaky`, `local`, |
| `shard_count`, `size`, `timeout`. The defaults of inherited attributes cannot be |
| changed, but you can use a macro with default arguments: |
| |
| ```python |
| def example_test(size="small", **kwargs): |
| _example_test(size=size, **kwargs) |
| |
| _example_test = rule( |
| ... |
| ) |
| ``` |
| |
| [1]: https://www.python.org/dev/peps/pep-0008/#id46 |