diff options
author | 2016-07-28 12:47:11 +0000 | |
---|---|---|
committer | 2016-07-29 10:09:06 +0000 | |
commit | 95a54b98368a1c680c14e13d841b14a27aba01ca (patch) | |
tree | 4a4f51e0d40ac2231b27054207ff838ef574a4fd /site/docs/skylark/aspects.md | |
parent | adc2d75bfb4bc7000b69183b6053a8ce6578748e (diff) |
Rollback of commit 3e8bcae69a0718cf6972be086706b1841e0ed6b7.
*** Reason for rollback ***
Breaks design docs links
*** Original change description ***
Move Bazel docs into versioned directory.
* Move all Bazel docs (excluding main page, search page, and blog)
into versions/master directory.
* Replace all original pages with redirects.
* Add Jekyll config with default_version setting to specify the default
version to redirect docs to.
* Add Jekyll config with version_prefix setting specific to pages under
each version directory.
* Update layouts to generate links to pages for the same version with the
version_prefix.
* Update Blaze rel...
***
--
MOS_MIGRATED_REVID=128690580
Diffstat (limited to 'site/docs/skylark/aspects.md')
-rw-r--r-- | site/docs/skylark/aspects.md | 191 |
1 files changed, 189 insertions, 2 deletions
diff --git a/site/docs/skylark/aspects.md b/site/docs/skylark/aspects.md index ba524f5cf6..6bafa20b65 100644 --- a/site/docs/skylark/aspects.md +++ b/site/docs/skylark/aspects.md @@ -1,4 +1,191 @@ --- -layout: redirect -redirect: docs/skylark/aspects.html +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. + +<img src="build-graph.png" alt="Build Graph" 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 definitions 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](rules.md#providers), can generate +[actions](rules.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 dependencies. +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 (similar to +what happens during aspect propagation). Thus implementation 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 `<extension file path>%<aspect top-level name>`. + + |