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 Skylark

Information exchange between skylark 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 skylark 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()
  1. 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 skylark, the fragment must be declared in the rule definition:

def __impl(ctx):
    cpu = ctx.fragments.apple.ios_cpu()
my_rule = rule(
  implementation = __impl
  fragments = ['apple']
)
  1. 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 skylark 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 skylark 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 skylark 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)