diff options
-rw-r--r-- | site/docs/skylark/rules.md | 126 | ||||
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java | 96 |
2 files changed, 132 insertions, 90 deletions
diff --git a/site/docs/skylark/rules.md b/site/docs/skylark/rules.md index 8715a68574..4327199404 100644 --- a/site/docs/skylark/rules.md +++ b/site/docs/skylark/rules.md @@ -16,11 +16,30 @@ 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_). +to execute the actions (called _implicit dependencies_). Before creating or modifying any rule, make sure you are familiar with the -[evaluation model](concepts.md) (understand the three phases of execution and the -differences between macros and rules). +[evaluation model](concepts.md). You must understand the three phases of +execution and the differences between macros and rules. + +A few rules are built into Bazel itself. These *native rules*, such as +`cc_library` and `java_binary`, provide some core support for certain languages. +By defining your own rules, you can add similar support for languages and tools +that Bazel does not support natively. + +Rules defined in .bzl files work just like native rules. For example, their +targets have labels, can appear in `bazel query`, and get built whenever they +are needed for a `bazel build` command or similar. When defining your own rule, +you get to decide what attributes it supports and how it generates its outputs. + +The exact behavior of a rule during the +[analysis phase](concepts.md#evaluation-model) is governed by its +`implementation` function. This function does not run any external commands. +Rather, it registers [actions](#actions) that will be used later during the +execution phase to build the rule's outputs, if they are needed. Rules also +produce and pass along information that may be useful to other rules, in the +form of [providers](#providers). + <!-- [TOC] --> @@ -39,24 +58,13 @@ The rule can then be loaded in `BUILD` files: 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. - [See example](https://github.com/bazelbuild/examples/tree/master/rules/empty). ## 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. Create attributes using -the [attr](lib/attr.html) module. +An attribute is a rule argument, such as `srcs` or `deps`. You must list the +names and schemas of all attributes when you define a rule. Attribute schemas +are created using the [attr](lib/attr.html) module. ```python sum = rule( @@ -68,11 +76,6 @@ sum = rule( ) ``` -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`. - In a `BUILD` file, call the rule to create targets of this type: ```python @@ -86,10 +89,32 @@ sum( ) ``` -Label attributes like `deps` above are used to declare dependencies. The target -whose label is mentioned becomes a dependency of the target with the attribute. -Therefore, `other-target` will be analyzed before `my-target`. +Here `other-target` is a dependency of `my-target`, and therefore `other-target` +will be analyzed first. + +There are two special kinds of attributes: + +* *Dependency attributes*, such as `attr.label` and `attr.label_list`, + declare a dependency from the target that owns the attribute to the target + whose label appears in the attribute's value. This kind of attribute forms the + basis of the target graph. + +* *Output attributes*, such as `attr.output` and `attr.output_list`, declare an + output file that the target generates. Although they refer to the output file + by label, they do not create a dependency relationship between targets. Output + attributes are used relatively rarely, in favor of other ways of declaring + output files that do not require the user to specify a label. + +Both dependency attributes and output attributes take in label values. These may +be specified as either [`Label`](lib/Label.html) objects or as simple strings. +If a string is given, it will be converted to a `Label` using the +[constructor](lib/Label.html#Label). The repository, and possibly the path, will +be resolved relative to the defined target. +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`. ### <a name="private-attributes"></a> Private Attributes @@ -152,11 +177,11 @@ of declaring and accessing attributes. ## Targets -Each call to a build rule has the side effect of defining a new target (also -called instantiating the rule). The dependencies of the new target are any other -targets whose labels are mentioned in an attribute of type `attr.label` or -`attr.label_list`. In the following example, the target `//mypkg:y` depends on -the targets `//mypkg:x` and `//mypkg:z.foo`. +Each call to a build rule returns no value but has the side effect of defining a +new target; this is called instantiating the rule. The dependencies of the new +target are any other targets whose labels are mentioned in its dependency +attributes. In the following example, the target `//mypkg:y` depends on the +targets `//mypkg:x` and `//mypkg:z.foo`. ```python # //mypkg:BUILD @@ -165,6 +190,8 @@ my_rule( name = "x", ) +# Assuming that my_rule has attributes "deps" and "srcs", +# of type attr.label_list() my_rule( name = "y", deps = [":x"], @@ -172,16 +199,11 @@ my_rule( ) ``` -Targets are represented at analysis time as [`Target`](lib/Target.html) objects. -These objects contain the information produced by analyzing a target -- in -particular, its [providers](#providers). - -In a rule's implementation function, the current target's dependencies are -accessed using `ctx.attr`, just like any other attribute's value. However, -unlike other types, attributes of type `attr.label` and `attr.label_list` have -the special behavior that each label value is replaced by its corresponding -`Target` object. This allows the current target being analyzed to consume the -providers of its dependencies. +Dependencies are represented at analysis time as [`Target`](lib/Target.html) +objects. These objects contain the information produced by analyzing a target -- +in particular, its [providers](#providers). The current target can access its +dependencies' `Target` objects within its rule implementation function by using +`ctx.attr`. ## Files @@ -196,9 +218,9 @@ be an output of exactly one action. Source files cannot be the output of any action. Some files, including all source files, are addressable by labels. These files -have `Target` objects associated with them. If a file's label is used in a -`attr.label` or `attr.label_list` attribute (for example, in a `srcs` -attribute), the `ctx.attr.<attr_name>` entry for it will contain the +have `Target` objects associated with them. If a file's label appears within a +dependency attribute (for example, in a `srcs` attribute of type +`attr.label_list`), the `ctx.attr.<attr_name>` entry for it will contain the corresponding `Target`. The `File` object can be obtained from this `Target`'s `files` field. This allows the file to be referenced in both the target graph and the action graph. @@ -241,12 +263,12 @@ analysis using the [`ctx.actions.declare_file`](lib/actions.html#declare_file) and [`ctx.actions.declare_directory`](lib/actions.html#declare_directory) functions. Both kinds of outputs may be passed along in providers. -Although the input files of a target -- those files passed through attributes of -`attr.label` and `attr.label_list` type -- can be accessed indirectly via -`ctx.attr`, it is more convenient to use `ctx.file` and `ctx.files`. For output -files that are predeclared using attributes of `attr.output` or -`attr.output_list` type, `ctx.attr` will only return the label, and you must use -`ctx.outputs` to get the actual `File` object. +Although the input files of a target -- those files passed through dependency +attributes -- can be accessed indirectly via `ctx.attr`, it is more convenient +to use `ctx.file` and `ctx.files`. For output files that are predeclared using +output attributes (attributes of type `attr.output` or `attr.output_list`), +`ctx.attr` will only return the label, and you must use `ctx.outputs` to get the +actual `File` object. [See example of predeclared outputs](https://github.com/bazelbuild/examples/blob/master/rules/predeclared_outputs/hash.bzl) @@ -327,9 +349,9 @@ 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 +For each dependency attribute, you can decide whether the dependency target +should be built in the same configuration, or transition to the host +configuration (using `cfg`). If a dependency attribute has the flag `executable=True`, the configuration must be set explicitly. [See example](https://github.com/bazelbuild/examples/blob/master/rules/actions_run/execute.bzl) diff --git a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java index edc3fb8165..1da54ba761 100644 --- a/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java +++ b/src/main/java/com/google/devtools/build/lib/skylarkbuildapi/SkylarkAttrApi.java @@ -39,17 +39,44 @@ import com.google.devtools.build.lib.syntax.UserDefinedFunction; namespace = true, category = SkylarkModuleCategory.BUILTIN, doc = - "Module for creating new attributes. " - + "They are only for use with <a href=\"globals.html#rule\">rule</a> or " - + "<a href=\"globals.html#aspect\">aspect</a>. " - + "<a href=\"https://github.com/bazelbuild/examples/tree/master/rules/" - + "attributes/printer.bzl\">See example of use</a>.") + "This is a top-level module for defining the attribute schemas of a rule or aspect. Each " + + "function returns an object representing the schema of a single attribute. These " + + "objects are used as the values of the <code>attrs</code> dictionary argument of " + + "<a href=\"globals.html#rule\"><code>rule()</code></a> and " + + "<a href=\"globals.html#aspect\"><code>aspect()</code></a>." + + "" + + "<p>See the Rules page for more on " + + "<a href='../rules.$DOC_EXT#attributes'>defining</a> and " + + "<a href='../rules.$DOC_EXT#implementation-function'>using</a> attributes.") public interface SkylarkAttrApi extends SkylarkValue { + // dependency and output attributes + static final String LABEL_PARAGRAPH = + "<p>This attribute contains <a href='Label.html'><code>Label</code></a> values. If a string " + + "is supplied in place of a <code>Label</code>, it will be converted using the " + + "<a href='Label.html#Label'>label constructor</a>. The relative parts of the label " + + "path, including the (possibly renamed) repository, are resolved with respect to the " + + "instantiated target's package."; + + // attr.label, attr.label_list, attr.label_keyed_string_dict + static final String DEPENDENCY_ATTR_TEXT = + LABEL_PARAGRAPH + + "<p>At analysis time (within the rule's implementation function), when retrieving the " + + "attribute value from <code>ctx.attr</code>, labels are replaced by the corresponding " + + "<a href='Target.html'><code>Target</code></a>s. This allows you to access the " + + "providers of the currrent target's dependencies."; + + // attr.output, attr.output_list + static final String OUTPUT_ATTR_TEXT = + LABEL_PARAGRAPH + + "<p>At analysis time, the corresponding <a href='File.html'><code>File</code></a> can " + + "be retrieved using <code>ctx.outputs</code>."; + static final String ALLOW_FILES_ARG = "allow_files"; static final String ALLOW_FILES_DOC = - "Whether File targets are allowed. Can be True, False (default), or a list of file " - + "extensions that are allowed (for example, <code>[\".cc\", \".cpp\"]</code>)."; + "Whether <code>File</code> targets are allowed. Can be <code>True</code>, <code>False</code> " + + "(default), or a list of file extensions that are allowed (for example, " + + "<code>[\".cc\", \".cpp\"]</code>)."; static final String ALLOW_RULES_ARG = "allow_rules"; static final String ALLOW_RULES_DOC = @@ -62,6 +89,7 @@ public interface SkylarkAttrApi extends SkylarkValue { + "attribute."; static final String CONFIGURATION_ARG = "cfg"; + // TODO(bazel-team): Update when new Skylark-based configuration framework is implemented. static final String CONFIGURATION_DOC = "<a href=\"../rules.$DOC_EXT#configurations\">Configuration</a> of the attribute. It can be " + "either <code>\"host\"</code> or <code>\"target\"</code>."; @@ -76,7 +104,7 @@ public interface SkylarkAttrApi extends SkylarkValue { static final String EXECUTABLE_ARG = "executable"; static final String EXECUTABLE_DOC = - "True if the label has to be executable. This means the label must refer to an " + "True if the dependency has to be executable. This means the label must refer to an " + "executable file, or to a rule that outputs an executable file. Access the label " + "with <code>ctx.executable.<attribute_name></code>."; @@ -88,7 +116,7 @@ public interface SkylarkAttrApi extends SkylarkValue { static final String NON_EMPTY_ARG = "non_empty"; static final String NON_EMPTY_DOC = - "True if the attribute must not be empty. Deprecated: Use allow_empty instead."; + "True if the attribute must not be empty. Deprecated: Use <code>allow_empty</code> instead."; static final String ALLOW_EMPTY_ARG = "allow_empty"; static final String ALLOW_EMPTY_DOC = "True if the attribute can be empty."; @@ -110,7 +138,7 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "int", - doc = "Creates an attribute of type int.", + doc = "Creates a schema for an integer attribute.", parameters = { @Param( name = DEFAULT_ARG, @@ -158,7 +186,7 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "string", - doc = "Creates an attribute of type <a href=\"string.html\">string</a>.", + doc = "Creates a schema for a string attribute.", parameters = { @Param( name = DEFAULT_ARG, @@ -206,11 +234,8 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "label", doc = - "Creates an attribute of type <a href=\"Target.html\">Target</a> which is the target " - + "referred to by the label. " - + "It is the only way to specify a dependency to another target. " - + "If you need a dependency that the user cannot overwrite, " - + "<a href=\"../rules.$DOC_EXT#private-attributes\">make the attribute private</a>.", + "Creates a schema for a label attribute. This is a dependency attribute." + + DEPENDENCY_ATTR_TEXT, parameters = { @Param( name = DEFAULT_ARG, @@ -335,8 +360,7 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "string_list", doc = - "Creates an attribute which is a <a href=\"list.html\">list</a> of " - + "<a href=\"string.html\">strings</a>.", + "Creates a schema for a list-of-strings attribute.", parameters = { @Param( name = MANDATORY_ARG, @@ -388,7 +412,7 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "int_list", - doc = "Creates an attribute which is a <a href=\"list.html\">list</a> of ints.", + doc = "Creates a schema for a list-of-integers attribute.", parameters = { @Param( name = MANDATORY_ARG, @@ -441,9 +465,8 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "label_list", doc = - "Creates an attribute which is a <a href=\"list.html\">list</a> of type " - + "<a href=\"Target.html\">Target</a> which are specified by the labels in the list. " - + "See <a href=\"attr.html#label\">label</a> for more information.", + "Creates a schema for a list-of-labels attribute. This is a dependency attribute." + + DEPENDENCY_ATTR_TEXT, parameters = { @Param( name = ALLOW_EMPTY_ARG, @@ -556,10 +579,9 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "label_keyed_string_dict", doc = - "Creates an attribute which is a <a href=\"dict.html\">dict</a>. Its keys are type " - + "<a href=\"Target.html\">Target</a> and are specified by the label keys of the " - + "input dict. Its values are <a href=\"string.html\">strings</a>. See " - + "<a href=\"attr.html#label\">label</a> for more information.", + "Creates a schema for an attribute holding a dictionary, where the keys are labels and " + + "the values are strings. This is a dependency attribute." + + DEPENDENCY_ATTR_TEXT, parameters = { @Param( name = ALLOW_EMPTY_ARG, @@ -672,7 +694,7 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "bool", - doc = "Creates an attribute of type bool.", + doc = "Creates a schema for a boolean attribute.", parameters = { @Param( name = DEFAULT_ARG, @@ -708,9 +730,8 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "output", doc = - "Creates an attribute of type output. " - + "The user provides a file name (string) and the rule must create an action that " - + "generates the file.", + "Creates a schema for an output (label) attribute." + + OUTPUT_ATTR_TEXT, parameters = { @Param( name = DEFAULT_ARG, @@ -747,8 +768,8 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "output_list", doc = - "Creates an attribute which is a <a href=\"list.html\">list</a> of outputs. " - + "See <a href=\"attr.html#output\">output</a> for more information.", + "Creates a schema for a list-of-outputs attribute." + + OUTPUT_ATTR_TEXT, parameters = { @Param( name = ALLOW_EMPTY_ARG, @@ -803,8 +824,8 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "string_dict", doc = - "Creates an attribute of type <a href=\"dict.html\">dict</a>, mapping from " - + "<a href=\"string.html\">string</a> to <a href=\"string.html\">string</a>.", + "Creates a schema for an attribute holding a dictionary, where the keys and values are " + + "strings.", parameters = { @Param( name = ALLOW_EMPTY_ARG, @@ -859,9 +880,8 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "string_list_dict", doc = - "Creates an attribute of type <a href=\"dict.html\">dict</a>, mapping from " - + "<a href=\"string.html\">string</a> to <a href=\"list.html\">list</a> of " - + "<a href=\"string.html\">string</a>.", + "Creates a schema for an attribute holding a dictionary, where the keys are strings and " + + "the values are lists of strings.", parameters = { @Param( name = ALLOW_EMPTY_ARG, @@ -915,7 +935,7 @@ public interface SkylarkAttrApi extends SkylarkValue { @SkylarkCallable( name = "license", - doc = "Creates an attribute of type license.", + doc = "Creates a schema for a license attribute.", // TODO(bazel-team): Implement proper license support for Skylark. parameters = { // TODO(bazel-team): ensure this is the correct default value |