| Rules |
| ===== |
| |
| **Status: Experimental**. Expect some breaking changes in the API. |
| |
| Rule creation |
| ------------- |
| |
| In a Skylark extension, use the `rule` function to create a new rule and store |
| it in a global variable. [See example](cookbook.md#empty). |
| |
| Attributes |
| ---------- |
| |
| An attribute is a rule argument, such as `srcs` or `deps`. You must list |
| the attributes and their type when you define a rule. |
| |
| ```python |
| sum = rule( |
| implementation=impl, |
| attrs = { |
| "number": attr.int(default = 1), |
| "deps": attr.label_list(), |
| }, |
| ) |
| ``` |
| |
| If an attribute 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). |
| |
| 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`. |
| |
| To access an attribute, use `ctx.attr.<attribute_name>`. The name and the |
| package of a rule are available with `ctx.label.name` and `ctx.label.package`. |
| |
| [See example.](cookbook.md#attr) |
| |
| The rule implementation function |
| -------------------------------- |
| |
| Every rule has to have an implementation function. This 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 ore more output files. Otherwise |
| Bazel will throw an error. |
| |
| 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` is depending 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 in Skylark: |
| |
| * 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) |
| |
| All output files 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 to 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`. |
| |
| To decide what goes in the default outputs of a rule, use the `files` provider. |
| If 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` |
| * `ctx.file_action` |
| * `ctx.template_action` |
| |
| Actions take a set (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 a command generates a file that is not listed in the outputs**: It is fine. |
| The file will be ignored and cannot be used by other rules. |
| |
| **If a command does not generate a file that is listed in the outputs**: It is an |
| execution error and the build will fail. This happens for instance when a |
| compilation fails. |
| |
| **If a command generates an unknown number of outputs and you want to keep them |
| all**, you may group them in a zip file. This way, you will be able to declare |
| your output. |
| |
| **If a command 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 a coincidence or error. |
| |
| **If a command lists a file as an input, but does not use it**: It is fine. However |
| it can affect the 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_CFG` |
| in the attribute. |
| |
| `DATA_CFG` 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 have to 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, |
| please use `ctx.host_fragments` instead. |
| |
| Providers |
| --------- |
| |
| Providers are used to access information from another rule. 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. |
| |
| Only the following data types are allowed to pass 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 dependent_rule_implementation(ctx): |
| ... |
| return struct( |
| transitive_data = set(["a", "b", "c"]) |
| ) |
| ``` |
| |
| A depending rule might access these data as struct fields of the depending |
| `target`: |
| |
| ```python |
| def depending_rule_implementation(ctx): |
| ... |
| s = set() |
| for dep_target in ctx.attr.deps: |
| 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). |
| Bazel creates a directory tree containing symlinks pointing to the |
| runfiles during execution, to stage this environment for the binary which can |
| thus access them during runtime. |
| |
| Runfiles can be added manually during rule creation and/or collected |
| transitively from dependent rules: |
| |
| ```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 depending |
| binary should know about it. |
| |
| Also note that if an action uses an executable, the executable's runfiles can |
| be used when the action executes. |
| |
| Executable rules |
| ---------------- |
| |
| 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) |
| |
| When the rule is executable, users can run it using `bazel run`. |
| |
| Test rules |
| ---------- |
| |
| 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`. |
| |
| Test rules are run using `bazel test`. |