diff options
author | Dmitry Lomov <dslomov@google.com> | 2017-04-25 11:14:05 +0200 |
---|---|---|
committer | Vladimir Moskva <vladmos@google.com> | 2017-04-25 14:48:16 +0200 |
commit | 3b5f9bd49d4e891aa3ca07e30a28158f1184c3db (patch) | |
tree | aad59c7c520ba071483b5d350104d1fa0ea8f4f1 /site | |
parent | 3d37b4c4924b07c2245fcbb149e5ce5788b5ddea (diff) |
Document declared providers.
Change-Id: Ifdc1773fb1439c16327bb84961998793a942e666
PiperOrigin-RevId: 154151084
Diffstat (limited to 'site')
-rw-r--r-- | site/designs/index.md | 4 | ||||
-rw-r--r-- | site/versions/master/docs/skylark/cookbook.md | 28 | ||||
-rw-r--r-- | site/versions/master/docs/skylark/rules.md | 72 |
3 files changed, 67 insertions, 37 deletions
diff --git a/site/designs/index.md b/site/designs/index.md index 67656da97f..6792ee2449 100644 --- a/site/designs/index.md +++ b/site/designs/index.md @@ -18,6 +18,10 @@ ongoing changes as designs are implemented. Always go to the [documentation](/versions/master/docs/bazel-overview.md) for descriptions of current Bazel functionality. +## Bazel Code Style and Best Practices + +* [Implementing Native Declared Provders](https://docs.google.com/document/d/1BKCBuYvf6fwmMnFu3KMWdRFysDgGCzdMiNxY_foosAM/preview) 12 April 2017 + ## Bazel Design Documents <ul> diff --git a/site/versions/master/docs/skylark/cookbook.md b/site/versions/master/docs/skylark/cookbook.md index 4e173645d4..b71ce51c78 100644 --- a/site/versions/master/docs/skylark/cookbook.md +++ b/site/versions/master/docs/skylark/cookbook.md @@ -503,7 +503,7 @@ def _impl(ctx): content=command, executable=True) - return struct( + return [DefaultInfo( # Create runfiles from the files specified in the data attribute. # The shell executable - the output of this rule - can use them at runtime. # It is also possible to define data_runfiles and default_runfiles. @@ -513,7 +513,7 @@ def _impl(ctx): # to have a field named "runfiles" in order to create the actual runfiles # symlink tree. runfiles=ctx.runfiles(files=ctx.files.data) - ) + )] execute = rule( implementation=_impl, @@ -661,14 +661,16 @@ to its dependents. `sum.bzl`: ```python +NumberInfo = provider() + def _impl(ctx): result = ctx.attr.number - for i in ctx.attr.deps: - result += i.number + for dep in ctx.attr.deps: + result += dep[NumberInfo].number ctx.file_action(output=ctx.outputs.out, content=str(result)) - # Fields in the struct will be visible by other rules. - return struct(number=result) + # Return the provider with result, visible to other rules. + return [NumberInfo(number=result)] sum = rule( implementation=_impl, @@ -709,15 +711,17 @@ This is a similar example, but dependencies may not provide a number. `sum.bzl`: ```python +NumberInfo = provider() + def _impl(ctx): result = ctx.attr.number - for i in ctx.attr.deps: - if hasattr(i, "number"): - result += i.number + for dep in ctx.attr.deps: + if NumberInfo in dep: + result += dep[NumberInfo].number ctx.file_action(output=ctx.outputs.out, content=str(result)) - # Fields in the struct will be visible by other rules. - return struct(number=result) + # Return the provider with result, visible to other rules. + return [NumberInfo(number=result)] sum = rule( implementation=_impl, @@ -864,7 +868,7 @@ def _impl(ctx): files = depset() files += ctx.attr.dep_rule_1.files files += ctx.attr.dep_rule_2.files - return struct(files=files) + return [DefaultInfo(files=files)] # This rule binds the depending rules together master_rule = rule( diff --git a/site/versions/master/docs/skylark/rules.md b/site/versions/master/docs/skylark/rules.md index 5db62cf5e0..56ef328b85 100644 --- a/site/versions/master/docs/skylark/rules.md +++ b/site/versions/master/docs/skylark/rules.md @@ -114,11 +114,7 @@ Example: ```python def _impl(ctx): ... - return struct( - runfiles = ..., - my_provider = ..., - ... - ) + return [DefaultInfo(runfiles=...), MyInfo(...)] my_rule = rule( implementation = _impl, @@ -350,46 +346,72 @@ information can be accumulated from all dependencies. In such cases, consider using [depsets](depsets.md) to hold the data more efficiently without excessive copying. -The following data types can be passed using providers: +Providers can be declared using the [provider()](lib/globals.html#provider) function: -* [bool](lib/bool.html) -* [integer](lib/int.html) -* [string](lib/string.html) -* [file](lib/File.html) -* [label](lib/Label.html) -* [None](lib/globals.html#None) -* anything composed of these types and [lists](lib/list.html), - [dicts](lib/dict.html), [depsets](lib/depset.html) or - [structs](lib/struct.html). +```python +TransitiveDataInfo = provider() +``` -Providers are created from the return value of the rule implementation function: +Rule implementation function can then construct and return provider instances: ```python def rule_implementation(ctx): ... - return struct( - transitive_data = depset(["a", "b", "c"]) - ) + return [TransitiveDataInfo(value = ["a", "b", "c"])] ``` -A dependent rule might access these data as struct fields of the `target` being -depended upon: +`TransitiveDataInfo` acts both as a constructor for provider instances and as a key to access them. +A [target](lib/Target.html) serves as a map from each provider that the target supports, to the +target's corresponding instance of that provider. +A rule can access the providers of its dependencies using the square bracket notation (`[]`): ```python def dependent_rule_implementation(ctx): ... s = depset() for dep_target in ctx.attr.deps: - # Use `print(dir(dep_target))` to see the list of providers. - s += dep_target.transitive_data + s += dep_target[TransitiveDataInfo].value ... ``` +All targets have a [`DefaultInfo`](lib/globals.html#DefaultInfo) provider that can be used to access +some information relevant to all targets. + Providers are only available during the analysis phase. Examples of usage: * [mandatory providers](cookbook.md#mandatory-providers) * [optional providers](cookbook.md#optional-providers) +> *Note:* +> Historically, Bazel also supported provider instances that are identified by strings and +> accessed as fields on the `target` object instead of as keys. This style is deprecated +> but still supported. Return legacy providers as follows: +> +```python +def rule_implementation(ctx): + ... + modern_provider = TransitiveDataInfo(value = ["a", "b", "c"]) + # Legacy style. + return struct(legacy_provider = struct(...), + another_legacy_provider = struct(...), + # The `providers` field contains provider instances that can be accessed + # the "modern" way. + providers = [modern_provider]) +``` +> To access legacy providers, use the dot notation. +> Note that the same target can define both modern and legacy providers: +> +```python +def dependent_rule_implementation(ctx): + ... + s = depset() + for dep_target in ctx.attr.deps: + x = dep_target.legacy_provider # legacy style + s += dep_target[TransitiveDataInfo].value # modern style + ... +``` +> **We recommend using modern providers for all future code.** + ## Runfiles Runfiles are a set of files used by the (often executable) output of a rule @@ -418,9 +440,9 @@ def _rule_implementation(ctx): # deps and data attributes. collect_default = True, ) - # Add a field named "runfiles" to the return struct in order to actually + # Add a field named "runfiles" to the DefaultInfo provider in order to actually # create the symlink tree. - return struct(runfiles = runfiles) + return [DefaultInfo(runfiles=runfiles)] ``` Note that non-executable rule outputs can also have runfiles. For example, a |