---
layout: documentation
title: Declared Providers
---

# Declared Providers

Authors: [Dmitry Lomov](mailto:dslomov@google.com),
[Laurent Le Brun](mailto:laurentlb@google.com)

Status: Approved

Date: 2016-06-06

## Motivation

Skylark rules use simple Skylark structs as their providers. Skylark providers
are identified as simple names, such as 'java' or 'files'. This approach has the
advantage of simplicity, but as the number and complexity of Skylark rules grow,
we run into engineering scalability problems:

*   Using simple names for providers might lead to name conflicts (when
    unrelated rules call their providers the same simple name).
*   There is no clear formal way to add documentation for those providers; if
    any, the documentation is in prose in rule's doc comment, where it tends to
    become obsolete/incomplete; most existing providers have no documentation
    explaining their contracts at all.
*   It’s hard to know which fields to expect in a provider.
*   It’s hard to know which rule can depend on which rule.

## Goals

*   Solve name-conflict problem for providers
*   Allow to specify providers in Skylark rules with the same level of
    robustness as other components of the language, such as rules and aspects
*   Enable the same or better documentability of Skylark providers as native
    providers allow
*   Improve providers interoperability with native code.

## Proposal

We propose a redesign of how Skylark rules deal with providers to address the
above concerns. The redesign can occur in stages; those stages represent
implementation stages, but allow Skylark users to gradually opt for "more and
more engineering" as their custom rules progress from a small project on the
side to a public release.

Our proposal is backwards compatible with the existing providers in Bazel and
allows easy, gradual piecemeal replacement of them.

### Stage 1: Solving the Naming Problem

Under the new proposal, a minimum implementation of a custom provider looks like
this:

```
# rust.bzl

# Introduces a provider. `rust_provider` is now both a function
# that can be used to construct the provider instance,
# and a "symbol" that can be used to access it.
rust_provider = provider()

def _impl(ctx):
  # `rust_provider` is used as struct-like constructor
  # it accepts the same arguments as a standard `struct` function
  rust = rust_provider(defines = "-DFOO", ...)
  # return value of rule implementation function
  # is just a list of providers; their "names" are specified
  # by their constructors, see below
  return [ctx.provider(files = ...), rust]
rust_library = rule(implementation = _impl,
  # Optional declaration; the rule MUST provide all the
  # providers in this list
  providers = [rust_provider])
```

```
# Example of how to access the provider

load(":rust.bzl", "rust_provider")

def _impl(ctx):
  dep = ctx.attr.deps[0] # Target object
  # `rust_provider` is used as a key to access a particular
  # provider
  defines = dep[rust_provider].defines ...
```

#### The provider function

*   We introduce two new kinds of Skylark values, a *provider declaration* and a
    *provider*.
*   Provider declaration (`rust_provider` in the example) is created using the
    `provider` function.
*   Provider declaration can be used to construct a *provider* (`rust` in the
    example). Provider is a struct-like Skylark value, with the only difference
    that every provider is associated with its declaration (it is a different
    type). Arguments of a provider declaration when used as a function are
    exactly the same as that of a built-in `struct` function.
*   [Target](http://www.bazel.build/docs/skylark/lib/Target.html) objects become
    dictionaries of providers indexed by their declaration. Bracket notation can
    be used to retrieve a particular provider. Thus, provider declarations are
    [symbol-like](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Symbol)
    values.
*   Providers can be private to an extension file; in that case the provider
    cannot be accessed outside that file.

#### Default providers (ctx.provider)

There is a set of default providers (`files`, `runfiles`, `data_runfiles`,
`executable`, `output_groups`, etc.). We group them in a single provider,
`ctx.provider`:

```
defaults = ctx.provider(files = set(), runfiles = ...)
```

The current set of APIs on Target objects that access these providers
(`target.files`, `target.output_group("name")` etc.) will continue to work.

#### Return value

The implementation function can return either a provider, or a list of
providers. It is an error to return two providers of the same type.

```
return [defaults, rust, cc]
return ctx.provider(files = set())
```

#### Declaring providers returned by a rule

Users need to know which rules provide which providers. This is important for
documentation and for knowing which dependencies are allowed (e.g. we want to
find easily what can go in the deps attribute of cc_library).

We allow rules to declare the providers they intend to return with a `providers`
argument of a
<code>[rule](http://www.bazel.build/docs/skylark/lib/globals.html#rule)</code>
function. It is an error if the rule implementation function does not return all
the providers listed in `providers`. It may however return additional providers.

```
rust_provider = provider()

rust_library = rule(implementation = _impl,
  # Optional declaration; the rule MUST provide all the
  # providers in this list
  providers = [rust_provider])
```

#### Migration path and support for "legacy" providers

To support current model of returning providers, where they are identified by a
simple name, we continue to allow providers name in the return struct:

```
def _impl(ctx):
  ...
  return struct(
    legacy_provider = struct(...),
    files = set(...),
    providers = [rust])
```

This also works for “default” providers, such as “files”, “runfiles” etc.
However if one of those legacy names is specified, it is an error to have
ctx.provider instance in the list of `providers`.

We also allow returning a declared provider both directly and with a simple
name:

```
def _impl(ctx):
  ...
  return struct(rust = rust, providers = [rust])
```

This allows the rules to mix old and new style, and migrate rule definition to a
new style without changing all the uses of that rule.

Old-style providers with simple names can still be accessed with dot-notation on
Target object, so all of the following is valid.

Old-style usage:

*   `target.rust` (=> rust)
*   `getattr(target, "rust")` (=> rust)
*   `hasattr(target, "rust")` (=> True)

New-style usage:

*   `target[rust_provider]` (=> rust)
*   `rust_provider in target` (=> True)
*   `target.keys` (=> [rust_provider])
*   `target.values` (=> [rust])
*   `target.items` (=> [(rust_provider, rust)])

#### type function

Type function on providers returns a string `"provider"`. Type function on a
provider instance returns a string `"struct"`.

### Stage 2: Documentation and Fields

Provider declarations are a convenient place to add more annotations to
providers. We propose 2 specific things there:

```
rust_provider = provider(
  doc = "This provider contains Rust information ...",
  fields = ["defines", "transitive_deps"]
)
```

This specifies documentation for the provider and a list of fields that the
provider can have.

If `fields` argument is present, extra, undeclared fields are not allowed.

Both `doc` and `fields` arguments to `provider` function are optional.

`fields` argument can also be a dictionary (from string to string), in that case
the keys are names of fields, and the values are documentation strings about
individual fields

```
rust_provider = provider(
  doc = "This provider contains Rust information ...",
  fields = {
    "defines": "doc for define",
    "transitive_deps": "doc for transitive deps,
  })
```

### Native Providers

Providers (as Skylark values) can be also declared natively. A set of
annotations can be developed to facilitate declaring them with little effort.

As a strawman example:

```
/**
 * Hypothetical implementation of Skylark provider value (result of
 * provider(..) function.
 */
class SkylarkProviderValue extends SkylarkValue {
  ...
  /**
   * Creates a SkylarkProviderValue for a native provider
   * `native` must be annotated with @SkylarkProvider annotation.
   * Field accessors and constructor function appear magically.
   */
  static <T> SkylarkProviderValue forNative(Class<T> native) { ... }
}

@SkylarkProvider(builder = Builder.class)
// A class with this annotation can be used as provider declaration
class rustProvider implements TransitiveInfoProvider {
  @SkylarkProviderField(doc = ...)
  // Skylark name is 'defines'
  String getDefines() { ... }

  @SkylarkProviderField(doc = ...)
  // Skylark name is 'transitive_deps'
  NestedSet<Artifact> getTransitiveDeps() { ... }

  @SkylarkProviderField(doc = ...)
  // Not allowed, the set of types exposed to Skylark is restricted
  DottedVersion getVersion() { ... }

  // Automatically used to provide an implementation for
  // construction function.
  static class Builder {
    // a setter for 'defines' field, based on name.
    void setDefines(String defines) { ... }
    // a setter for 'transitive_deps' field, based on name.
    void setTransitiveDeps(...) {...}
    rustProvider build() { ... }
  }
}
```
