diff options
3 files changed, 98 insertions, 60 deletions
diff --git a/site/docs/skylark/rules.md b/site/docs/skylark/rules.md index ab38202feb..797c94ae47 100644 --- a/site/docs/skylark/rules.md +++ b/site/docs/skylark/rules.md @@ -150,22 +150,17 @@ the same as their rule, but suffixed with `_impl`. See [an example](https://github.com/bazelbuild/examples/blob/master/rules/attributes/printer.bzl) of declaring and accessing attributes. -## 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. - -A file is represented with the [File](lib/File.html) object. - ## Targets -Every call to a build rule corresponds to exactly one target. A target `y` -depends on target `x` if `y` has a label- or label-list-type attribute -that contains `x`'s label: +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`. ```python +# //mypkg:BUILD + my_rule( name = "x", ) @@ -173,42 +168,84 @@ my_rule( my_rule( name = "y", deps = [":x"], + srcs = [":z.foo"], ) ``` -In a rule's implementation function, the current target's dependencies can be -accessed like any other attribute value by using `ctx.attr`. However, each label -is replaced by a resolved [Target](lib/Target.html) object, which contains the -additional information obtained during that dependency's analysis step. In -particular, it contains the [providers](#providers) returned by that dependency. - -## <a name="output-files"></a> Output files +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). -A target can declare output files, which must be generated by the target's -actions. Each output file must have exactly one generating action. +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. -There are multiple ways to have declared outputs: - -* If the rule is marked `executable`, it creates an output file of the same name - as the rule's. [See example](https://github.com/bazelbuild/examples/blob/master/rules/executable/executable.bzl) - -* The rule can declare outputs using the `outputs` argument of the - [rule](lib/globals.html#rule) function. - [See example](https://github.com/bazelbuild/examples/blob/master/rules/default_outputs/extension.bzl) +## Files -* The rule can have [output](lib/attr.html#output) or [output_list](lib/attr.html#output_list) - attributes. In that case the output files come from the actual attribute values. +Files are represented by the [`File`](lib/File.html) type. Since Bazel does not +perform file I/O during the analysis phase, these objects cannot be used to +directly read or write file content. Rather, they are passed to action-emitting +functions to construct pieces of the action graph. See +[`ctx.actions`](lib/actions.html) for the available kinds of actions. + +A file can either be a source file or a generated file. Each generated file must +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 +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. + +During the analysis phase, a rule's implementation function can create +additional output files. Since all labels have to be known during the loading +phase, these additional output files are not associated with labels or +`Target`s. Generally these are intermediate files needed for a later compilation +step, or auxiliary outputs that don't need to be referenced in the target graph. +Even though these files don't have a label, they can still be passed along in a +[`provider`](#providers) to make them available to other depending targets at +analysis time. + +A file that is both a target and a generated file is called a *predeclared +output*. There are multiple ways for a rule to introduce a predeclared output: + +* The rule can have an attribute of type [`output`](lib/attr.html#output) or + [`output_list`](lib/attr.html#output_list). In this case the user explicitly + chooses the label for the output when they instantiate the rule. [See example](https://github.com/bazelbuild/examples/blob/master/rules/custom_outputs/extension.bzl) -We call them "declared outputs" because they are associated with a label. You -can refer to declared outputs using a label on the command-line or in a `BUILD` -file. In the implementation function, use [ctx.outputs](lib/ctx.html#outputs) -for accessing declared outputs. +* The rule can predeclare outputs using the [`outputs`](lib/globals.html#rule.outputs) + argument of the `rule()` function. The label for the output is chosen + automatically, usually by substituting into a template. + [See example](https://github.com/bazelbuild/examples/blob/master/rules/default_outputs/extension.bzl) -The rule can also create extra output files during the analysis phase using the -[ctx.actions.declare_file](lib/actions.html#declare_file) function. This is -more flexible, but those files are not declared outputs: they don't have any -associated labels. +* If the rule is marked [`executable`](lib/globals.html#rule.executable), an + output is created with the same name as the rule instance itself. + (Technically, the file has no label since it would clash with the rule + instance's own label, but it is still considered a predeclared output.) By + default, this file serves as the binary to run if the target appears on the + command line of a `bazel run` or `bazel test` command. Use the `executable` + argument of `DefaultInfo` to override this behavior. + [See example](https://github.com/bazelbuild/examples/blob/master/rules/executable/executable.bzl) + +All predeclared outputs can be accessed within the rule's implementation +function under the [`ctx.outputs`](lib/ctx.html#output) struct. Non-predeclared +outputs are created during 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. ## Default outputs @@ -224,7 +261,7 @@ Every rule has a set of default outputs. This is used: In the [`DefaultInfo`](lib/globals.html#DefaultInfo) provider, the `files` field specifies the default outputs of a rule. If left unspecified, it will contain -all the declared outputs. +all the predeclared outputs. ```python def _impl(ctx): @@ -235,8 +272,8 @@ def _impl(ctx): This can be useful for exposing files generated with [ctx.actions.declare_file](lib/actions.html#declare_file). -An "implicit output" is a declared output that is not in the default outputs. In -other words, it is not generated by default. Users can refer to its label to +An "implicit output" is a predeclared output that is not in the default outputs. +In other words, it is not generated by default. Users can refer to its label to build the file explicitly. Use the `files` mentioned above if you need implicit outputs (like `_deploy.jar` files generated by `java_binary`). [See example](https://github.com/bazelbuild/examples/blob/master/rules/implicit_output/hash.bzl) diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java index 85873b27a0..918c6b998c 100644 --- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java +++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java @@ -101,16 +101,14 @@ import javax.annotation.Nullable; */ @Immutable @SkylarkModule( - name = "File", - category = SkylarkModuleCategory.BUILTIN, - doc = - "<p>This type represents a file or directory used by the build system. It can be " - + "either a source file or a derived file produced by a rule.</p>" - + "<p>The File constructor is private, so you cannot call it directly to create new " - + "Files. You typically get a File object from a " - + "<a href='Target.html'>Target</a>, or using " - + "<a href='actions.html#declare_file'>ctx.actions.declare_file</a>, " - + "or <a href='actions.html#declare_directory'>ctx.actions.declare_directory</a>." + name = "File", + category = SkylarkModuleCategory.BUILTIN, + doc = "This object is created during the analysis phase to represent a file or directory that " + + "will be read or written during the execution phase. It is not an open file handle, and " + + "cannot be used to directly read or write file contents. Rather, you use it to construct " + + "the action graph in a rule implementation function by passing it to action-creating " + + "functions. See the <a href='../rules.$DOC_EXT#files'>Rules page</a> for more " + + "information." ) @AutoCodec public class Artifact diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java index d991f493f4..e14bfc0046 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkActionFactory.java @@ -103,14 +103,17 @@ public class SkylarkActionFactory implements SkylarkValue { @SkylarkCallable( name = "declare_file", doc = - "Declares that rule or aspect creates a file with the given filename. " - + "If <code>sibling</code> is not specified, file name is relative to " - + "package directory, otherwise the file is in the same directory as " - + "<code>sibling</code>. " - + "You must create an action that generates the file. <br>" - + "Files cannot be created outside of the current package. " - + "Files that are specified in rule's outputs do not need to be declared and are " - + "available through <a href=\"ctx.html#outputs\"><code>ctx.outputs</code></a>. " + "Declares that the rule or aspect creates a file with the given filename. " + + "If <code>sibling</code> is not specified, the file name is relative to the package" + + "directory, otherwise the file is in the same directory as <code>sibling</code>." + + "Files cannot be created outside of the current package." + + "<p>Remember that in addition to declaring a file, you must separately create an " + + "action that emits the file. Creating that action will require passing the returned " + + "<code>File</code> object to the action's construction function." + + "<p>Note that <a href='../rules.$DOC_EXT#files'>predeclared output files</a> do not " + + "need to be (and cannot be) declared using this function. You can obtain their " + + "<code>File</code> objects from <a href=\"ctx.html#outputs\"><code>ctx.outputs</code>" + + "</a> instead. " + "<a href=\"https://github.com/bazelbuild/examples/tree/master/rules/" + "computed_dependencies/hash.bzl\">See example of use</a>", parameters = { |