# The Apple Rule Implementations:
The packages `devtools/build/lib/rules/objc` and
`devtools/build/lib/rules/apple` implement the objc and ios Bazel rules.

## Interfacing from Starlark

Information exchange between Starlark rules and native objc_* or ios_* rules
occurs by three mechanisms:

1) **`AppleToolchain:`**

`AppleToolchain.java` houses constants and static methods for use in rule
implementations.  It is accessed in Starlark through the global `apple_common`
namespace:

```
def __impl(ctx):
    platform_dir = apple_common.apple_toolchain().platform_dir('iphoneos')
    sdk_dir = apple_common.apple_toolchain().sdk_dir()
```

2) **`AppleConfiguration` and `ObjcConfiguration`**:

In Bazel, configuration fragments are used as containers for invocation-specific
build information (that is, information that cannot always be derived strictly
from BUILD files).  The contents of these configurations can be inspected by
looking at `rules/objc/ObjcConfiguration.java` and
`rules/apple/AppleConfiguration.java`.  To access a configuration fragment from
Starlark, the fragment must be declared in the rule definition:

```
def __impl(ctx):
    cpu = ctx.fragments.apple.single_arch_cpu
my_rule = rule(
  implementation = __impl
  fragments = ['apple']
)
```

3) **`ObjcProvider`**:

The ObjcProvider maps "keys" to NestedSet instances, where "keys" are singleton
objects defined in ObjcProvider that identify a category of transitive
information to be communicated between targets in a dependency chain.

Native objc/ios rules export ObjcProvider instances, which are made available
to Starlark dependants:

```
def __impl(ctx):
    dep = ctx.attr.deps[0]
    objc_provider = dep.objc
```

The provider can be queried by accessing fields that correspond to ObjcProvider
keys.

```
    libraries = objc_provider.library  # A Depset of Artifacts
```

A Starlark rule that is intended to be a dependency of native objc rules should
export an ObjcProvider itself.  An ObjcProvider is constructed using a
constructor exposed on the apple_common namespace.

```
def __impl(ctx):
    define = 'some_define'
    objc_provider = apple_common.new_objc_provider(define=define)
    return struct(objc = objc_provider)
```

Arguments to `new_objc_provider` should correspond to ObjcProvider keys, and
values should be Starlark sets that should be added to the provider. Other
instances of ObjcProvider can also be used in provider construction.

```
def __impl(ctx):
    dep = ctx.attr.deps[0]
    define = 'some_define'
    objc_provider = apple_common.new_objc_provider(providers=[dep.objc], define=define)
    return struct(objc = objc_provider)
```
