| --- | |
| 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 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_). | |
| ## 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`). During analysis, no external command can be executed: actions will | |
| be run in the execution phase. | |
| ## 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 | |
| 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. 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 struct( | |
| runfiles=..., | |
| my_provider=..., | |
| ... | |
| ) | |
| 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](cookbook.md#outputs-executable) | |
| * The rule can declare default `outputs`, which are always generated. | |
| [See example](cookbook.md#outputs-default) | |
| * The rule can have output or output list type attributes. In that case the | |
| output files come from the actual attribute values. | |
| [See example](cookbook.md#outputs-custom) | |
| 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 struct(files=set([file1, file2])) | |
| ``` | |
| This can be useful for exposing files generated with | |
| [ctx.new_file](lib/ctx.html#new_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 | |
| There are three ways to create actions: | |
| * [ctx.action](lib/ctx.html#action), to run a command. | |
| * [ctx.file_action](lib/ctx.html#file_action), to write a string to a file. | |
| * [ctx.template_action](lib/ctx.html#template_action), 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. 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). | |
| **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 | |
| By default, a target is built in the target configuration. For each label | |
| attribute, you can decide whether the dependency should be built in the same | |
| configuration, or in the host configuration. | |
| 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. | |
| 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 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 used to access information from other rules. A rule depending on | |
| another rule has access to the data the latter provides. These data can be e.g. | |
| output files, the libraries the dependent rule is using to link or compile, or | |
| anything the depending rule should know about. Using providers is the only way | |
| to exchange data between rules. | |
| A rule can only access data provided by its direct dependencies, not that of | |
| transitive dependencies: if rule `top` depends on `middle`, and `middle` depends | |
| on `bottom`, then `middle` is a direct dependency of `top` and `bottom` is a | |
| transitive dependency of `top`. In this scenario `top` can only access data | |
| provided by `middle`. If `middle` also provides the data that `bottom` provided | |
| to it, then and only then can `top` access it. | |
| The following data types can be passed using providers: | |
| * `bool` | |
| * `integer` | |
| * `string` | |
| * `file` | |
| * `label` | |
| * `None` | |
| * anything composed of these types and `lists`, `dicts`, `sets` or `structs` | |
| Providers are created from the return value of the rule implementation function: | |
| ```python | |
| def rule_implementation(ctx): | |
| ... | |
| return struct( | |
| transitive_data=set(["a", "b", "c"]) | |
| ) | |
| ``` | |
| A dependent rule might access these data as struct fields of the `target` being | |
| depended upon: | |
| ```python | |
| def dependent_rule_implementation(ctx): | |
| ... | |
| s = set() | |
| for dep_target in ctx.attr.deps: | |
| # Use `print(dir(dep_target))` to see the list of providers. | |
| s += dep_target.transitive_data | |
| ... | |
| ``` | |
| Providers are only available during the analysis phase. Examples of usage: | |
| * [mandatory providers](cookbook.md#mandatory-providers) | |
| * [optional providers](cookbook.md#optional-providers) | |
| ## 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 execution, Bazel creates a directory tree containing symlinks pointing to | |
| the runfiles, staging 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 = set() | |
| 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 return struct in order to actually | |
| # create the symlink tree. | |
| return struct(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. | |
| ## Instrumented files | |
| Instrumented files are a set of files used by the coverage command. A rule can | |
| use the `instrumented_files` provider to provide information about which files | |
| should be used for measuring coverage. | |
| ```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"])) | |
| ``` | |
| ## 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). During the analysis | |
| phase, the rule must generate the output file `ctx.outputs.executable`. | |
| [See example](cookbook.md#outputs-executable) | |
| ## 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 they | |
| must generate the output file `ctx.outputs.executable`. | |
| Test rules inherit the following attributes: `args`, `flaky`, `local`, | |
| `shard_count`, `size`, `timeout`. |