[docs/toolchains] Fix typo that prevents example from building
Closes #7955.
PiperOrigin-RevId: 243664124
diff --git a/site/docs/toolchains.md b/site/docs/toolchains.md
index 510c279..998f623 100644
--- a/site/docs/toolchains.md
+++ b/site/docs/toolchains.md
@@ -230,7 +230,7 @@
attrs = {
"compiler_path": attr.string(),
"system_lib": attr.string(),
- "arch_flags": attr.string(),
+ "arch_flags": attr.string_list(),
},
)
```
diff --git a/site/docs/toolchains.md.orig b/site/docs/toolchains.md.orig
new file mode 100644
index 0000000..a74e803
--- /dev/null
+++ b/site/docs/toolchains.md.orig
@@ -0,0 +1,463 @@
+---
+layout: documentation
+title: Toolchains
+---
+
+# Toolchains
+
+- [Overview](#overview)
+- [Motivation](#motivation)
+- [Writing rules that use toolchains](#writing-rules-that-use-toolchains)
+- [Defining toolchains](#defining-toolchains)
+- [Registering and building with toolchains](#registering-and-building-with-toolchains)
+- [Toolchain resolution](#toolchain-resolution)
+- [Debugging toolchains](#debugging-toolchains)
+
+## Overview
+
+This page describes the toolchain framework -- a way for rule authors to
+decouple their rule logic from platform-based selection of tools. It is
+recommended to read the
+<!-- begin-block:external
+[rules](skylark/rules.html)
+end-block -->
+<!-- begin-block:internal -->
+[rules](https://g3doc.corp.google.com/devtools/blaze/rules/g3doc/rules.md)
+<!-- begin-block:shared -->
+and
+<!-- begin-block:external
+[platforms](platforms.html)
+end-block -->
+<!-- begin-block:internal -->
+[platforms](https://g3doc.corp.google.com/devtools/blaze/subteams/configurability/g3doc/platforms.md)
+<!-- begin-block:shared -->
+pages before continuing. This page covers why toolchains are needed, how to
+define and use them, and how Bazel selects an appropriate toolchain based on
+platform constraints.
+
+## Motivation
+
+Let's first look at the problem toolchains are designed to solve. Suppose you
+were writing rules to support the "bar" programming language. Your `bar_binary`
+rule would compile `*.bar` files using the `barc` compiler, a tool that itself
+is built as another target in your workspace. Since users who write `bar_binary`
+targets shouldn't have to specify a dependency on the compiler, you make it an
+implicit dependency by adding it to the rule definition as a private attribute.
+
+```python
+bar_binary = rule(
+ implementation = _bar_binary_impl,
+ attrs = {
+ "srcs": attr.label_list(allow_files = True),
+ ...
+ "_compiler": attr.label(
+ default = "//bar_tools:barc_linux", # the compiler running on linux
+ providers = [BarcInfo],
+ ),
+ },
+)
+```
+
+`//bar_tools:barc_linux` is now a dependency of every `bar_binary` target, so
+it'll be built before any `bar_binary` target. It can be accessed by the rule's
+implementation function just like any other attribute:
+
+```python
+BarcInfo = provider(
+ doc = "Information about how to invoke the barc compiler.",
+ # In the real world, compiler_path and system_lib might hold File objects,
+ # but for simplicity we'll make them strings instead. arch_flags is a list
+ # of strings.
+ fields = ["compiler_path", "system_lib", "arch_flags"],
+)
+
+def _bar_binary_impl(ctx):
+ ...
+ info = ctx.attr._compiler[BarcInfo]
+ command = "%s -l %s %s" % (
+ info.compiler_path,
+ info.system_lib,
+ " ".join(info.arch_flags),
+ )
+ ...
+```
+
+The issue here is that the compiler's label is hardcoded into `bar_binary`, yet
+different targets may need different compilers depending on what platform they
+are being built for and what platform they are being built on -- called the
+*target platform* and *execution platform*, respectively. Furthermore, the rule
+author does not necessarily even know all the available tools and platforms, so
+it is not feasible to hardcode them in the rule's definition.
+
+A less-than-ideal solution would be to shift the burden onto users, by making
+the `_compiler` attribute non-private. Then individual targets could be
+hardcoded to build for one platform or another.
+
+```python
+bar_binary(
+ name = "myprog_on_linux",
+ srcs = ["mysrc.bar"],
+ compiler = "//bar_tools:barc_linux",
+)
+
+bar_binary(
+ name = "myprog_on_windows",
+ srcs = ["mysrc.bar"],
+ compiler = "//bar_tools:barc_windows",
+)
+```
+
+We can improve on this solution by using `select` to choose the `compiler`
+[based on the platform](configurable-attributes.html):
+
+```python
+config_setting(
+ name = "on_linux",
+ constraint_values = [
+ "@bazel_tools//platforms:linux",
+ ],
+)
+
+config_setting(
+ name = "on_windows",
+ constraint_values = [
+ "@bazel_tools//platforms:windows",
+ ],
+)
+
+bar_binary(
+ name = "myprog",
+ srcs = ["mysrc.bar"],
+ compiler = select({
+ ":on_linux": "//bar_tools:barc_linux",
+ ":on_windows": "//bar_tools:barc_windows",
+ }),
+)
+```
+
+But this is tedious and a bit much to ask of every single `bar_binary` user.
+If this style is not used consistently throughout the workspace, it leads to
+builds that work fine on a single platform but fail when extended to
+multi-platform scenarios. It also does not address the problem of adding support
+for new platforms and compilers without modifying existing rules or targets.
+
+The toolchain framework solves this problem by adding an extra level of
+indirection. Essentially, you declare that your rule has an abstract dependency
+on *some* member of a family of targets (a toolchain type), and Bazel
+automatically resolves this to a particular target (a toolchain) based on the
+applicable platform constraints. Neither the rule author nor the target author
+need know the complete set of available platforms and toolchains.
+
+## Writing rules that use toolchains
+
+Under the toolchain framework, instead of having rules depend directly on tools,
+they instead depend on *toolchain types*. A toolchain type is a simple target
+that represents a class of tools that serve the same role for different
+platforms. For instance, we can declare a type that represents the bar compiler:
+
+```python
+# By convention, toolchain_type targets are named "toolchain_type" and
+# distinguished by their package path. So the full path for this would be
+# //bar_tools:toolchain_type.
+toolchain_type(name = "toolchain_type")
+```
+
+The rule definition in the previous section is modified so that instead of
+taking in the compiler as an attribute, it declares that it consumes a
+`//bar_tools:toolchain_type` toolchain.
+
+```python
+bar_binary = rule(
+ implementation = _bar_binary_impl,
+ attrs = {
+ "srcs": attr.label_list(allow_files = True),
+ ...
+ # No `_compiler` attribute anymore.
+ },
+ toolchains = ["//bar_tools:toolchain_type"]
+)
+```
+
+The implementation function now accesses this dependency under `ctx.toolchains`
+instead of `ctx.attr`, using the toolchain type as the key.
+
+```python
+def _bar_binary_impl(ctx):
+ ...
+ info = ctx.toolchains["//bar_tools:toolchain_type"].barcinfo
+ # The rest is unchanged.
+ command = "%s -l %s %s" % (
+ info.compiler_path,
+ info.system_lib,
+ " ".join(info.arch_flags),
+ )
+ ...
+```
+
+`ctx.toolchains["//bar_tools:toolchain_type"]` returns the
+<!-- begin-block:external
+[`ToolchainInfo` provider](skylark/lib/platform_common.html#ToolchainInfo)
+end-block -->
+<!-- begin-block:internal -->
+[`ToolchainInfo` provider](http://g3doc/devtools/blaze/rules/g3doc/lib/ToolchainInfo.html)
+<!-- begin-block:shared -->
+of whatever target Bazel resolved the toolchain dependency to. The fields of the
+`ToolchainInfo` object are set by the underlying tool's rule; in the next
+section we'll define this rule such that there is a `barcinfo` field that wraps
+a `BarcInfo` object.
+
+Bazel's procedure for resolving toolchains to targets is described
+[below](#toolchain-resolution). Only the resolved toolchain target is actually
+made a dependency of the `bar_binary` target, not the whole space of candidate
+toolchains.
+
+## Defining toolchains
+
+To define some toolchains for a given toolchain type, we need three things:
+
+1. A language-specific rule representing the kind of tool or tool suite. By
+ convention this rule's name is suffixed with "\_toolchain".
+
+2. Several targets of this rule type, representing versions of the tool or tool
+ suite for different platforms.
+
+3. For each such target, an associated target of the generic
+<!-- begin-block:external
+[`toolchain`](be/platform.html#toolchain)
+end-block -->
+<!-- begin-block:internal -->
+[`toolchain`](https://g3doc.corp.google.com/devtools/blaze/g3doc/be/platform.html#toolchain)
+<!-- begin-block:shared -->
+rule, to provide metadata used by the toolchain framework.
+
+For our running example, here's a definition for a `bar_toolchain` rule. Our
+example has only a compiler, but other tools such as a linker could also be
+grouped underneath it.
+
+```python
+def _bar_toolchain_impl(ctx):
+ toolchain_info = platform_common.ToolchainInfo(
+ barcinfo = BarcInfo(
+ compiler_path = ctx.attr.compiler_path,
+ system_lib = ctx.attr.system_lib,
+ arch_flags = ctx.attr.arch_flags,
+ ),
+ )
+ return [toolchain_info]
+
+bar_toolchain = rule(
+ implementation = _bar_toolchain_impl,
+ attrs = {
+ "compiler_path": attr.string(),
+ "system_lib": attr.string(),
+ "arch_flags": attr.string(),
+ },
+)
+```
+
+The rule must return a `ToolchainInfo` provider, which becomes the object that
+the consuming rule retrieves using `ctx.toolchains` and the label of the
+toolchain type. `ToolchainInfo`, like `struct`, can hold arbitrary field-value
+pairs. The specification of exactly what fields are added to the `ToolchainInfo`
+should be clearly documented at the toolchain type. Here we have returned the
+values wrapped in a `BarcInfo` object in order to reuse the schema defined
+above; this style may be useful for validation and code reuse.
+
+Now we can define targets for specific `barc` compilers.
+
+```python
+bar_toolchain(
+ name = "barc_linux",
+ arch_flags = [
+ "--arch=Linux",
+ "--debug_everything",
+ ],
+ compiler_path = "/path/to/barc/on/linux",
+ system_lib = "/usr/lib/libbarc.so",
+)
+
+bar_toolchain(
+ name = "barc_windows",
+ arch_flags = [
+ "--arch=Windows",
+ # Different flags, no debug support on windows.
+ ],
+ compiler_path = "C:\\path\\on\\windows\\barc.exe",
+ system_lib = "C:\\path\\on\\windows\\barclib.dll",
+)
+```
+
+Finally, we create `toolchain` definitions for the two `bar_toolchain` targets.
+These definitions link the language-specific targets to the toolchain type and
+provide the constraint information that tells Bazel when the toolchain is
+appropriate for a given platform.
+
+```python
+toolchain(
+ name = "barc_linux_toolchain",
+ exec_compatible_with = [
+ "@bazel_tools//platforms:linux",
+ "@bazel_tools//platforms:x86_64",
+ ],
+ target_compatible_with = [
+ "@bazel_tools//platforms:linux",
+ "@bazel_tools//platforms:x86_64",
+ ],
+ toolchain = ":barc_linux",
+ toolchain_type = ":toolchain_type",
+)
+
+toolchain(
+ name = "barc_windows_toolchain",
+ exec_compatible_with = [
+ "@bazel_tools//platforms:windows",
+ "@bazel_tools//platforms:x86_64",
+ ],
+ target_compatible_with = [
+ "@bazel_tools//platforms:windows",
+ "@bazel_tools//platforms:x86_64",
+ ],
+ toolchain = ":barc_windows",
+ toolchain_type = ":toolchain_type",
+)
+```
+
+The use of relative path syntax above suggests these definitions are all in the
+same package, but there's no reason the toolchain type, language-specific
+toolchain targets, and `toolchain` definition targets can't all be in separate
+packages.
+
+See the [`go_toolchain`](https://github.com/bazelbuild/rules_go/blob/master/go/private/go_toolchain.bzl)
+for a real-world example.
+
+## Registering and building with toolchains
+
+At this point all the building blocks are assembled, and we just need to make
+the toolchains available to Bazel's resolution procedure. This is done by
+registering the toolchain, either in a `WORKSPACE` file using
+`register_toolchains()`, or by passing the toolchains' labels on the command
+line using the `--extra_toolchains` flag.
+
+```python
+register_toolchains(
+ "//bar_tools:barc_linux_toolchain",
+ "//bar_tools:barc_windows_toolchain",
+ # Target patterns are also permitted, so we could have also written:
+ # "//bar_tools:all",
+)
+```
+
+Now when you build a target that depends on a toolchain type, an appropriate
+toolchain will be selected based on the target and execution platforms.
+
+```python
+# my_pkg/BUILD
+
+platform(
+ name = "my_target_platform",
+ constraint_values = [
+ "@bazel_tools//platforms:linux",
+ ],
+)
+
+bar_binary(
+ name = "my_bar_binary",
+ ...
+)
+```
+
+```sh
+bazel build //my_pkg:my_bar_binary --platforms=//my_pkg:my_target_platform
+```
+
+Bazel will see that `//my_pkg:my_bar_binary` is being built with a platform that
+has `@bazel_tools//platforms:linux` and therefore resolve the
+`//bar_tools:toolchain_type` reference to `//bar_tools:barc_linux_toolchain`.
+This will end up building `//bar_tools:barc_linux` but not
+`//barc_tools:barc_windows`.
+
+## Toolchain Resolution
+
+**Note:** Some Bazel rules do not yet support toolchain resolution.
+
+For each target that uses toolchains, Bazel's toolchain resolution procedure
+determines the target's concrete toolchain dependencies. The procedure takes as input a
+set of required toolchain types, the target platform, the list of available
+execution platforms, and the list of available toolchains. Its outputs are a
+selected toolchain for each toolchain type as well as a selected execution
+platform for the current target.
+
+The available execution platforms and toolchains are gathered from the
+`WORKSPACE` file via
+<!-- begin-block:external
+[`register_execution_platforms`](skylark/lib/globals.html#register_execution_platforms)
+end-block -->
+<!-- begin-block:internal -->
+[`register_execution_platforms`](http://g3doc/devtools/blaze/rules/g3doc/lib/globals.html#register_execution_platforms)
+<!-- begin-block:shared -->
+and
+<!-- begin-block:external
+[`register_toolchains`](skylark/lib/globals.html#register_toolchains).
+end-block -->
+<!-- begin-block:internal -->
+[`register_toolchains`](http://g3doc/devtools/blaze/rules/g3doc/lib/globals.html#register_toolchains).
+<!-- begin-block:shared -->
+Additional execution platforms and toolchains may also be specified on the
+command line via
+<!-- begin-block:external
+[`--extra_execution_platforms`](command-line-reference.html#flag--extra_execution_platforms)
+end-block -->
+<!-- begin-block:internal -->
+[`--extra_execution_platforms`](http://g3doc/devtools/blaze/g3doc/user-manual.html#flag--extra_execution_platforms)
+<!-- begin-block:shared -->
+and
+<!-- begin-block:external
+[`--extra_toolchains`](command-line-reference.html#flag--extra_toolchains).
+end-block -->
+<!-- begin-block:internal -->
+[`--extra_toolchains`](http://g3doc/devtools/blaze/g3doc/user-manual.html#flag--extra_toolchains).
+<!-- begin-block:shared -->
+The host platform is automatically included as an available execution platform.
+Available platforms and toolchains are tracked as ordered lists for determinism,
+
+The resolution steps are as follows.
+
+1. If the target specifies the
+<!-- begin-block:external
+ [`exec_compatible_with` attribute](be/common-definitions.html#common.exec_compatible_with)
+end-block -->
+<!-- begin-block:internal -->
+ [`exec_compatible_with` attribute](https://g3doc.corp.google.com/devtools/blaze/g3doc/be/common-definitions.html#common.exec_compatible_with)
+<!-- begin-block:shared -->
+ (or the rule specifies the
+<!-- begin-block:external
+ [`exec_compatible_with` argument](skylark/lib/globals.html#rule.exec_compatible_with),
+end-block -->
+<!-- begin-block:internal -->
+ [`exec_compatible_with` argument](https://g3doc.corp.google.com/devtools/blaze/rules/g3doc/lib/globals.html#rule.exec_compatible_with),
+<!-- begin-block:shared -->
+ the list of available execution platforms is filtered to remove
+ any that do not match the execution constraints.
+
+2. For each available execution platform, we associate each toolchain type with
+ the first available toolchain, if any, that is compatible with this execution
+ platform and the target platform.
+
+3. Any execution platform that failed to find a compatible toolchain for one of
+ its toolchain types is ruled out. Of the remaining platforms, the first one
+ becomes the current target's execution platform, and its associated
+ toolchains become dependencies of the target.
+
+The chosen execution platform is used to run all actions that the target
+generates.
+
+In cases where the same target can be built in multiple configurations (such as
+for different CPUs) within the same build, the resolution procedure is applied
+independently to each version of the target.
+
+## Debugging toolchains
+
+When adding toolchain support to an existing rule, use the
+`--toolchain_resolution_debug` flag to make toolchain resolution verbose. Bazel
+will output names of toolchains it is checking and skipping during the
+resolution process.