--- layout: documentation title: Aspects --- # Aspects **Status: Experimental**. We may make breaking changes to the API, but we will help you update your code. Aspects allow augmenting build dependency graphs with additional information and actions. Some typical scenarios when aspects can be useful: * IDEs that integrate Bazel can use aspects to collect information about the project * Code generation tools can leverage aspects to execute on their inputs in "target-agnostic" manner. As an example, BUILD files can specify a hierarchy of [protobuf](https://developers.google.com/protocol-buffers/) library definitions, and language-specific rules can use aspects to attach actions generating protobuf support code for a particular language ## Aspect basics Bazel BUILD files provide a description of a project’s source code: what source files are part of the project, what artifacts (_targets_) should be built from those files, what the dependencies between those files are, etc. Bazel uses this information to perform a build, that is, it figures out the set of actions needed to produce the artifacts (such as running compiler or linker) and executes those actions. Bazel accomplishes this by constructing a _dependency graph_ between targets and visiting this graph to collect those actions. Consider the following BUILD file: ```python java_library(name = 'W', ...) java_library(name = 'Y', deps = [':W'], ...) java_library(name = 'Z', deps = [':W'], ...) java_library(name = 'Q', ...) java_library(name = 'T', deps = [':Q'], ...) java_library(name = 'X', deps = [':Y',':Z'], runtime_deps = [':T'], ...) ``` This BUILD file defines a dependency graph shown in Fig 1. ![Build Graph](build-graph.png){width="250px"} Bazel analyzes this dependency graph by calling implementations of [rules](rules.md) (in this case "java_library" starting from leaves of the dependency graph). These implementations generate actions that build artifacts (such as Jar files), and provide information (such as locations and names of those artifacts) to their dependencies in providers that they return. Their dependencies can access those providers through the [Target object](lib/Target.html). In other words, every target defined in the BUILD file generates a node in the dependency graph, and the appropriate rule implementation function is called for every node. Aspects are similar to rules in that they have an implementation function that generates actions and returns providers. However, their power comes from the way the dependency graph is built for them. An aspect has an implementation and a list of all attributes it propagates along. Consider an aspect A that propagates along attributes named "deps". This aspect can be applied to a target X, yielding an aspect application node A(X). During its application, aspect A is applied recursively to all targets that X refers to in its "deps" attribute (all attributes in A's propagation list). Thus a single act of applying aspect A to a target X yields a "shadow graph" of the original dependency graph of targets (see Fig.2). ![Build Graph with Aspect](build-graph-aspects.png) The only edges that are shadowed are the edges along the attributes in the propagation set, thus the `runtime_deps` edge is not shadowed in this example. An aspect implementation function is then invoked on all nodes in the shadow graph similar to how rule implementations are invoked on the nodes of the original graph. ## Defining aspects Aspect defintions are similiar to rule definitions. Let's take a look at the example: ```python metal_proto_aspect = aspect(implementation = _metal_proto_aspect_impl, attr_aspects = ["deps"], attrs = { "_protoc" : attr.label( default=Label("//tools:metal_protoc"), executable = True ) } ) ``` Just like a rule, an aspect has an implementation function. ``attr_aspects`` specify the aspect's propagation set: a list of attributes of rules along which the aspect propagates. ``attrs`` defines a set of attributes for aspects. Aspects are only allowed to have private attributes of types ``label`` or ``label_list``. Attributes can be used to specify dependencies on tools or libraries that are needed for actions generated by aspects. ### Implementation functions Aspect implementation functions are similiar to the rule implementation functions. They return [providers](rule.md#providers), can generate [actions](rule.md#actions) and take two arguments: * `target`: the target the aspect is being applied to. * [`ctx`](lib/ctx.html): `ctx` object that can be used to access attributes and generate outputs and actions. Example: ```python def _metal_proto_aspect_impl(target, ctx): # For every `src` in proto_library, generate an output file proto_sources = [f for src in ctx.rule.attr.src for f in src.files] outputs = [ctx.new_file(f.short_path + ".metal") for f in proto_sources] ctx.action( executable = ctx.executable._protoc, argument = ... inputs = proto_sources outputs = outputs) transitive_outputs = set(outputs) for dep in ctx.attr.deps: transitive_outputs = transitive_outputs | dep.metal_proto.transitive_outputs return struct( metal_proto = struct(direct_outputs = outputs, transitive_outputs = transitive_outputs)) ``` The implementation function can access the attributes of the target rule via [`ctx.rule.attr`](lib/ctx.html#rule). It can examine providers that are provided by the target to which it is applied (via the `target` argument). Just like a rule implementation function, an aspect implementation function returns a struct of providers that are accessible to its dependencies. * The set of providers for an aspect application A(X) is the union of providers that come from the implementation of a rule for target X and from the implementation of aspect A. It is an error if a target and an aspect that is applied to it each provide a provider with the same name. * For the aspect implementation, the values of attributes along which the aspect is propagated (from the `attr_aspect` list) are replaced with the results of an application of the aspect to them. For example, if target X has Y and Z in its deps, `ctx.rule.attr.deps` for A(X) will be [A(Y), A(Z)]. In the `_metal_proto_aspect_impl` function above, ctx.rule.attr.deps will be Target objects that are the results of applying the aspect to the 'deps' of the original target to which the aspect has been applied. That allows the aspect to examine `metal_proto` provider on them. ## Applying aspects Aspect propagation can be initiated either from a rule or from the command line. ### Applying aspects to rule attributes Rules can specify that they want to apply aspects to their depenedencies. The aspects to be applied to a particular attribute can be specified using the `aspects` parameter to `attr.label` or `attr.label_list` function: ```python metal_proto_library = rule(implementation = _impl, attrs = { 'proto_deps' : attr.label_list(aspects = [metal_proto_aspect]), }, ) ``` If a rule specifies an aspect on its attributes, the values of that attribute will be replaced by the result of aspect application to them (similiar to what happens during aspect propagation). Thus implementaion of `metal_proto_library` will have access to `metal_proto` providers on the target objects representing its `proto_deps` attribute values. ### Applying aspects from command line. Aspects can also be applied on the command line, using the `--aspects` flag: ``` bazel build //java/com/company/example:main \ --aspects path/to/extension.bzl%metal_proto_aspect ``` `--aspects` flag takes one argument, which is a specification of the aspect in the format `%`.