//python/private:rule_builders.bzl

Builders for creating rules, aspects et al.

When defining rules, Bazel only allows creatingimmutable objects that can’tbe introspected. This makes it difficult to perform arbitrary customizations ofhow a rule is defined, which makes extending a rule implementation prone tocopy/paste issues and version skew.

These builders are, essentially, mutable and inspectable wrappers for thoseBazel objects. This allows defining a rule where the values are mutable andcallers can customize them to derive their own variant of the rule while stillinheriting everything else about the rule.

To that end, the builders are not strict in how they handle values. Theygenerally assume that the values provided are valid and provide ways tooverride their logic and force particular values to be used when they areeventually converted to the args for calling e.g.rule().

Important

When using builders, most lists, dicts, et al passed into themmust belocally created values, otherwise they won’t be mutable. This is due to Bazel’simplicit immutability rules: after evaluating a.bzl file, its globalvariables are frozen.

Tip

To aid defining reusable pieces, many APIs accept no-arg callable functionsthat create a builder. For example, common attributes can be storedin adict[str,lambda], e.g.ATTRS={"srcs":lambda:LabelList(...)}.

Example usage:

load(":rule_builders.bzl","ruleb")load(":attr_builders.bzl","attrb")# File: foo_binary.bzl_COMMON_ATTRS={"srcs":lambda:attrb.LabelList(...),}defcreate_foo_binary_builder():foo=ruleb.Rule(executable=True,)foo.implementation.set(_foo_binary_impl)foo.attrs.update(COMMON_ATTRS)returnfoodefcreate_foo_test_builder():foo=create_foo_binary_build()binary_impl=foo.implementation.get()deffoo_test_impl(ctx):binary_impl(ctx)...foo.implementation.set(foo_test_impl)foo.executable.set(False)foo.test.test(True)foo.attrs.update(_coverage=attrb.Label(default="//:coverage"))returnfoofoo_binary=create_foo_binary_builder().build()foo_test=create_foo_test_builder().build()# File: custom_foo_binary.bzlload(":foo_binary.bzl","create_foo_binary_builder")defcreate_custom_foo_binary():r=create_foo_binary_builder()r.attrs["srcs"].default.append("whatever.txt")returnr.build()custom_foo_binary=create_custom_foo_binary()

Added in version 1.3.0.

typedefAttributeBuilder

An abstract base typedef for builder for a BazelAttribute

Instances of this are a builder for a particularAttribute type,e.g.attr.label,attr.string, etc.

typedefAttrsDict

Builder for the dictionary of rule attributes.

AttrsDict.map:dict[str,AttributeBuilder]

The underlying dict of attributes. Directly accessible so that regulardict operations (e.g.xiny) can be performed, if necessary.

AttrsDict.get(key,default=None)

Get an entry from the dict. Convenience wrapper for.map.get(...)

AttrsDict.items()list[tuple[str,object]]

Returns a list of key-value tuples. Convenience wrapper for.map.items()

AttrsDict.pop(key,default)object

Removes a key from the attr dict

AttrsDict.build()

Build an attribute dict for passing torule().

Returns:

dict[str,Attribute] where the values areattr.XXX objects

AttrsDict.new(initial)

Creates a builder for therule.attrs dict.

Args:
Returns:

AttrsDict

AttrsDict.update(other)

Mergeother into this object.

Args:
  • other(dict[str,callable|AttributeBuilder])

    the values tomerge into this object. If the value a function, it is calledwith no args and expected to return an attribute builder. Thisallows defining dicts of common attributes (where the values arefunctions that create a builder) and merge them into the rule.

typedefExecGroup

Builder forexec_group

ExecGroup.toolchains()list[ToolchainType]
ExecGroup.exec_compatible_with()list[str|Label]
ExecGroup.kwargs:dict[str,Any]

Additional kwargs to use when building. This is to allow manipulations thataren’t directly supported by the builder’s API. The state of this dictmay or may not reflect prior API calls, and subsequent API calls maymodify this dict. The general contract is that modifications to this willbe respected whenbuild() is called, assuming there were no API callsin between.

ExecGroup.build()
ExecGroup.new(**kwargs)

Creates a builder forexec_group.

Args:
Returns:

ExecGroup

typedefRule

A builder to accumulate state for constructing arule object.

Rule.attrs:AttrsDict
Rule.cfg:RuleCfg
Rule.doc()str
Rule.exec_groups()dict[str,ExecGroup]
Rule.executable()bool
Rule.kwargs:dict[str,Any]

Additional kwargs to use when building. This is to allow manipulations thataren’t directly supported by the builder’s API. The state of this dictmay or may not reflect prior API calls, and subsequent API calls maymodify this dict. The general contract is that modifications to this willbe respected whenbuild() is called, assuming there were no API callsin between.

Rule.fragments()list[str]
Rule.implementation()callable|None
Rule.provides()list[provider|list[provider]]
Rule.set_doc(v)
Rule.set_executable(v)
Rule.set_implementation(v)
Rule.set_test(v)
Rule.test()bool
Rule.toolchains()list[ToolchainType]
Rule.build(debug='')

Builds arule object

Args:
  • debug(str)(default“”)

    If set, prints the args used to create the rule.

Returns:

rule

Rule.new(**kwargs)

Builder for creating rules.

Args:
  • kwargs – The same as therule() function, but using builders ordicts to specify sub-objects instead of the immutable Bazelobjects.

Rule.to_kwargs()

Builds the arguments for callingrule().

This is added as an escape hatch to construct the final valuesrule()kwarg values in case callers want to manually change them.

Returns:

dict

ruleb.ExecGroup(**kwargs)

Creates a builder forexec_group.

Args:
Returns:

ExecGroup

ruleb.Rule(**kwargs)

Builder for creating rules.

Args:
  • kwargs – The same as therule() function, but using builders ordicts to specify sub-objects instead of the immutable Bazelobjects.

ruleb.ToolchainType(name=None,**kwargs)

Creates a builder forconfig_common.toolchain_type.

Args:
Returns:

ToolchainType

typedefRuleCfg

Wrapper forrule.cfg arg.

RuleCfg.implementation()str|callable|None|config.target|config.none
RuleCfg.inputs()list[Label]

See also

Theadd_inputs() andupdate_inputs methods for adding uniquevalues.

RuleCfg.outputs()list[Label]

See also

Theadd_outputs() andupdate_outputs methods for adding uniquevalues.

RuleCfg.set_implementation(v)

The string values “target” and “none” are supported.

RuleCfg.add_inputs(*inputs)

Adds an input to the list of inputs, if not present already.

See also

Theupdate_inputs() method for adding a collection ofvalues.

Args:
  • inputs(Label)

    the inputs to add. Note that aLabel,notstr, should be passed to ensure different apparent labelscan be properly de-duplicated.

RuleCfg.add_outputs(*outputs)

Adds an output to the list of outputs, if not present already.

See also

Theupdate_outputs() method for adding a collection ofvalues.

Args:
  • outputs(Label)

    the outputs to add. Note that aLabel,notstr, should be passed to ensure different apparent labelscan be properly de-duplicated.

RuleCfg.build()

Builds the rule cfg into the value rule.cfg arg value.

Returns:

transition the transition object to apply to the rule.

RuleCfg.new(rule_cfg_arg)

Creates a builder for therule.cfg arg.

Args:
Returns:

RuleCfg

RuleCfg.update_inputs(*others)

Add a collection of values to inputs.

Args:
  • others(list[Label])

    collection of labels to add toinputs. Only values not already present are added. Note that aLabel, notstr, should be passed to ensure different apparentlabels can be properly de-duplicated.

RuleCfg.update_outputs(*others)

Add a collection of values to outputs.

Args:
  • others(list[Label])

    collection of labels to add tooutputs. Only values not already present are added. Note that aLabel, notstr, should be passed to ensure different apparentlabels can be properly de-duplicated.

typedefToolchainType

Builder forconfig_common.toolchain_type

ToolchainType.kwargs:dict[str,Any]

Additional kwargs to use when building. This is to allow manipulations thataren’t directly supported by the builder’s API. The state of this dictmay or may not reflect prior API calls, and subsequent API calls maymodify this dict. The general contract is that modifications to this willbe respected whenbuild() is called, assuming there were no API callsin between.

ToolchainType.mandatory()bool
ToolchainType.name()str|Label|None
ToolchainType.set_name(v)
ToolchainType.set_mandatory(v)
ToolchainType.build()

Builds aconfig_common.toolchain_type

Returns:

toolchain_type

ToolchainType.new(name=None,**kwargs)

Creates a builder forconfig_common.toolchain_type.

Args:
Returns:

ToolchainType