xref: /aosp_15_r20/external/bazelbuild-rules_python/docs/toolchains.md (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker:::{default-domain} bzl
2*60517a1eSAndroid Build Coastguard Worker:::
3*60517a1eSAndroid Build Coastguard Worker
4*60517a1eSAndroid Build Coastguard Worker# Configuring Python toolchains and runtimes
5*60517a1eSAndroid Build Coastguard Worker
6*60517a1eSAndroid Build Coastguard WorkerThis documents how to configure the Python toolchain and runtimes for different
7*60517a1eSAndroid Build Coastguard Workeruse cases.
8*60517a1eSAndroid Build Coastguard Worker
9*60517a1eSAndroid Build Coastguard Worker## Bzlmod MODULE configuration
10*60517a1eSAndroid Build Coastguard Worker
11*60517a1eSAndroid Build Coastguard WorkerHow to configure `rules_python` in your MODULE.bazel file depends on how and why
12*60517a1eSAndroid Build Coastguard Workeryou're using Python. There are 4 basic use cases:
13*60517a1eSAndroid Build Coastguard Worker
14*60517a1eSAndroid Build Coastguard Worker1. A root module that always uses Python. For example, you're building a
15*60517a1eSAndroid Build Coastguard Worker   Python application.
16*60517a1eSAndroid Build Coastguard Worker2. A library module with dev-only uses of Python. For example, a Java project
17*60517a1eSAndroid Build Coastguard Worker   that only uses Python as part of testing itself.
18*60517a1eSAndroid Build Coastguard Worker3. A library module without version constraints. For example, a rule set with
19*60517a1eSAndroid Build Coastguard Worker   Python build tools, but defers to the user as to what Python version is used
20*60517a1eSAndroid Build Coastguard Worker   for the tools.
21*60517a1eSAndroid Build Coastguard Worker4. A library module with version constraints. For example, a rule set with
22*60517a1eSAndroid Build Coastguard Worker   Python build tools, and the module requires a specific version of Python
23*60517a1eSAndroid Build Coastguard Worker   be used with its tools.
24*60517a1eSAndroid Build Coastguard Worker
25*60517a1eSAndroid Build Coastguard Worker### Root modules
26*60517a1eSAndroid Build Coastguard Worker
27*60517a1eSAndroid Build Coastguard WorkerRoot modules are always the top-most module. These are special in two ways:
28*60517a1eSAndroid Build Coastguard Worker
29*60517a1eSAndroid Build Coastguard Worker1. Some `rules_python` bzlmod APIs are only respected by the root module.
30*60517a1eSAndroid Build Coastguard Worker2. The root module can force module overrides and specific module dependency
31*60517a1eSAndroid Build Coastguard Worker   ordering.
32*60517a1eSAndroid Build Coastguard Worker
33*60517a1eSAndroid Build Coastguard WorkerWhen configuring `rules_python` for a root module, you typically want to
34*60517a1eSAndroid Build Coastguard Workerexplicitly specify the Python version you want to use. This ensures that
35*60517a1eSAndroid Build Coastguard Workerdependencies don't change the Python version out from under you. Remember that
36*60517a1eSAndroid Build Coastguard Worker`rules_python` will set a version by default, but it will change regularly as
37*60517a1eSAndroid Build Coastguard Workerit tracks a recent Python version.
38*60517a1eSAndroid Build Coastguard Worker
39*60517a1eSAndroid Build Coastguard WorkerNOTE: If your root module only uses Python for development of the module itself,
40*60517a1eSAndroid Build Coastguard Workeryou should read the dev-only library module section.
41*60517a1eSAndroid Build Coastguard Worker
42*60517a1eSAndroid Build Coastguard Worker```
43*60517a1eSAndroid Build Coastguard Workerbazel_dep(name="rules_python", version=...)
44*60517a1eSAndroid Build Coastguard Workerpython = use_extension("@rules_python//python/extensions:python.bzl", "python")
45*60517a1eSAndroid Build Coastguard Worker
46*60517a1eSAndroid Build Coastguard Workerpython.toolchain(python_version = "3.12", is_default = True)
47*60517a1eSAndroid Build Coastguard Worker```
48*60517a1eSAndroid Build Coastguard Worker
49*60517a1eSAndroid Build Coastguard Worker### Library modules
50*60517a1eSAndroid Build Coastguard Worker
51*60517a1eSAndroid Build Coastguard WorkerA library module is a module that can show up in arbitrary locations in the
52*60517a1eSAndroid Build Coastguard Workerbzlmod module graph -- it's unknown where in the breadth-first search order the
53*60517a1eSAndroid Build Coastguard Workermodule will be relative to other modules. For example, `rules_python` is a
54*60517a1eSAndroid Build Coastguard Workerlibrary module.
55*60517a1eSAndroid Build Coastguard Worker
56*60517a1eSAndroid Build Coastguard Worker#### Library modules with dev-only Python usage
57*60517a1eSAndroid Build Coastguard Worker
58*60517a1eSAndroid Build Coastguard WorkerA library module with dev-only Python usage is usually one where Python is only
59*60517a1eSAndroid Build Coastguard Workerused as part of its tests. For example, a module for Java rules might run some
60*60517a1eSAndroid Build Coastguard WorkerPython program to generate test data, but real usage of the rules don't need
61*60517a1eSAndroid Build Coastguard WorkerPython to work. To configure this, follow the root-module setup, but remember to
62*60517a1eSAndroid Build Coastguard Workerspecify `dev_dependency = True` to the bzlmod APIs:
63*60517a1eSAndroid Build Coastguard Worker
64*60517a1eSAndroid Build Coastguard Worker```
65*60517a1eSAndroid Build Coastguard Worker# MODULE.bazel
66*60517a1eSAndroid Build Coastguard Workerbazel_dep(name = "rules_python", version=..., dev_dependency = True)
67*60517a1eSAndroid Build Coastguard Worker
68*60517a1eSAndroid Build Coastguard Workerpython = use_extension(
69*60517a1eSAndroid Build Coastguard Worker    "@rules_python//python/extensions:python.bzl",
70*60517a1eSAndroid Build Coastguard Worker    "python",
71*60517a1eSAndroid Build Coastguard Worker    dev_dependency = True
72*60517a1eSAndroid Build Coastguard Worker)
73*60517a1eSAndroid Build Coastguard Worker
74*60517a1eSAndroid Build Coastguard Workerpython.toolchain(python_version = "3.12", is_default=True)
75*60517a1eSAndroid Build Coastguard Worker```
76*60517a1eSAndroid Build Coastguard Worker
77*60517a1eSAndroid Build Coastguard Worker#### Library modules without version constraints
78*60517a1eSAndroid Build Coastguard Worker
79*60517a1eSAndroid Build Coastguard WorkerA library module without version constraints is one where the version of Python
80*60517a1eSAndroid Build Coastguard Workerused for the Python programs it runs isn't chosen by the module itself. Instead,
81*60517a1eSAndroid Build Coastguard Workerit's up to the root module to pick an appropriate version of Python.
82*60517a1eSAndroid Build Coastguard Worker
83*60517a1eSAndroid Build Coastguard WorkerFor this case, configuration is simple: just depend on `rules_python` and use
84*60517a1eSAndroid Build Coastguard Workerthe normal `//python:py_binary.bzl` et al rules. There is no need to call
85*60517a1eSAndroid Build Coastguard Worker`python.toolchain` -- rules_python ensures _some_ Python version is available,
86*60517a1eSAndroid Build Coastguard Workerbut more often the root module will specify some version.
87*60517a1eSAndroid Build Coastguard Worker
88*60517a1eSAndroid Build Coastguard Worker```
89*60517a1eSAndroid Build Coastguard Worker# MODULE.bazel
90*60517a1eSAndroid Build Coastguard Workerbazel_dep(name = "rules_python", version=...)
91*60517a1eSAndroid Build Coastguard Worker```
92*60517a1eSAndroid Build Coastguard Worker
93*60517a1eSAndroid Build Coastguard Worker#### Library modules with version constraints
94*60517a1eSAndroid Build Coastguard Worker
95*60517a1eSAndroid Build Coastguard WorkerA library module with version constraints is one where the module requires a
96*60517a1eSAndroid Build Coastguard Workerspecific Python version be used with its tools. This has some pros/cons:
97*60517a1eSAndroid Build Coastguard Worker
98*60517a1eSAndroid Build Coastguard Worker* It allows the library's tools to use a different version of Python than
99*60517a1eSAndroid Build Coastguard Worker  the rest of the build. For example, a user's program could use Python 3.12,
100*60517a1eSAndroid Build Coastguard Worker  while the library module's tools use Python 3.10.
101*60517a1eSAndroid Build Coastguard Worker* It reduces the support burden for the library module because the library only needs
102*60517a1eSAndroid Build Coastguard Worker  to test for the particular Python version they intend to run as.
103*60517a1eSAndroid Build Coastguard Worker* It raises the support burden for the library module because the version of
104*60517a1eSAndroid Build Coastguard Worker  Python being used needs to be regularly incremented.
105*60517a1eSAndroid Build Coastguard Worker* It has higher build overhead because additional runtimes and libraries need
106*60517a1eSAndroid Build Coastguard Worker  to be downloaded, and Bazel has to keep additional configuration state.
107*60517a1eSAndroid Build Coastguard Worker
108*60517a1eSAndroid Build Coastguard WorkerTo configure this, request the Python versions needed in MODULE.bazel and use
109*60517a1eSAndroid Build Coastguard Workerthe version-aware rules for `py_binary`.
110*60517a1eSAndroid Build Coastguard Worker
111*60517a1eSAndroid Build Coastguard Worker```
112*60517a1eSAndroid Build Coastguard Worker# MODULE.bazel
113*60517a1eSAndroid Build Coastguard Workerbazel_dep(name = "rules_python", version=...)
114*60517a1eSAndroid Build Coastguard Worker
115*60517a1eSAndroid Build Coastguard Workerpython = use_extension("@rules_python//python/extensions:python.bzl", "python")
116*60517a1eSAndroid Build Coastguard Workerpython.toolchain(python_version = "3.12")
117*60517a1eSAndroid Build Coastguard Worker
118*60517a1eSAndroid Build Coastguard Worker# BUILD.bazel
119*60517a1eSAndroid Build Coastguard Workerload("@python_versions//3.12:defs.bzl", "py_binary")
120*60517a1eSAndroid Build Coastguard Worker
121*60517a1eSAndroid Build Coastguard Workerpy_binary(...)
122*60517a1eSAndroid Build Coastguard Worker```
123*60517a1eSAndroid Build Coastguard Worker
124*60517a1eSAndroid Build Coastguard Worker### Pinning to a Python version
125*60517a1eSAndroid Build Coastguard Worker
126*60517a1eSAndroid Build Coastguard WorkerPinning to a version allows targets to force that a specific Python version is
127*60517a1eSAndroid Build Coastguard Workerused, even if the root module configures a different version as a default. This
128*60517a1eSAndroid Build Coastguard Workeris most useful for two cases:
129*60517a1eSAndroid Build Coastguard Worker
130*60517a1eSAndroid Build Coastguard Worker1. For submodules to ensure they run with the appropriate Python version
131*60517a1eSAndroid Build Coastguard Worker2. To allow incremental, per-target, upgrading to newer Python versions,
132*60517a1eSAndroid Build Coastguard Worker   typically in a mono-repo situation.
133*60517a1eSAndroid Build Coastguard Worker
134*60517a1eSAndroid Build Coastguard WorkerTo configure a submodule with the version-aware rules, request the particular
135*60517a1eSAndroid Build Coastguard Workerversion you need, then use the `@python_versions` repo to use the rules that
136*60517a1eSAndroid Build Coastguard Workerforce specific versions:
137*60517a1eSAndroid Build Coastguard Worker
138*60517a1eSAndroid Build Coastguard Worker```starlark
139*60517a1eSAndroid Build Coastguard Workerpython = use_extension("@rules_python//python/extensions:python.bzl", "python")
140*60517a1eSAndroid Build Coastguard Worker
141*60517a1eSAndroid Build Coastguard Workerpython.toolchain(
142*60517a1eSAndroid Build Coastguard Worker    python_version = "3.11",
143*60517a1eSAndroid Build Coastguard Worker)
144*60517a1eSAndroid Build Coastguard Workeruse_repo(python, "python_versions")
145*60517a1eSAndroid Build Coastguard Worker```
146*60517a1eSAndroid Build Coastguard Worker
147*60517a1eSAndroid Build Coastguard WorkerThen use e.g. `load("@python_versions//3.11:defs.bzl", "py_binary")` to use
148*60517a1eSAndroid Build Coastguard Workerthe rules that force that particular version. Multiple versions can be specified
149*60517a1eSAndroid Build Coastguard Workerand use within a single build.
150*60517a1eSAndroid Build Coastguard Worker
151*60517a1eSAndroid Build Coastguard WorkerFor more documentation, see the bzlmod examples under the {gh-path}`examples`
152*60517a1eSAndroid Build Coastguard Workerfolder.  Look for the examples that contain a `MODULE.bazel` file.
153*60517a1eSAndroid Build Coastguard Worker
154*60517a1eSAndroid Build Coastguard Worker### Other toolchain details
155*60517a1eSAndroid Build Coastguard Worker
156*60517a1eSAndroid Build Coastguard WorkerThe `python.toolchain()` call makes its contents available under a repo named
157*60517a1eSAndroid Build Coastguard Worker`python_X_Y`, where X and Y are the major and minor versions. For example,
158*60517a1eSAndroid Build Coastguard Worker`python.toolchain(python_version="3.11")` creates the repo `@python_3_11`.
159*60517a1eSAndroid Build Coastguard WorkerRemember to call `use_repo()` to make repos visible to your module:
160*60517a1eSAndroid Build Coastguard Worker`use_repo(python, "python_3_11")`
161*60517a1eSAndroid Build Coastguard Worker
162*60517a1eSAndroid Build Coastguard Worker#### Toolchain usage in other rules
163*60517a1eSAndroid Build Coastguard Worker
164*60517a1eSAndroid Build Coastguard WorkerPython toolchains can be utilized in other bazel rules, such as `genrule()`, by
165*60517a1eSAndroid Build Coastguard Workeradding the `toolchains=["@rules_python//python:current_py_toolchain"]`
166*60517a1eSAndroid Build Coastguard Workerattribute. You can obtain the path to the Python interpreter using the
167*60517a1eSAndroid Build Coastguard Worker`$(PYTHON2)` and `$(PYTHON3)` ["Make"
168*60517a1eSAndroid Build Coastguard WorkerVariables](https://bazel.build/reference/be/make-variables). See the
169*60517a1eSAndroid Build Coastguard Worker{gh-path}`test_current_py_toolchain <tests/load_from_macro/BUILD.bazel>` target
170*60517a1eSAndroid Build Coastguard Workerfor an example.
171*60517a1eSAndroid Build Coastguard Worker
172*60517a1eSAndroid Build Coastguard Worker### Overriding toolchain defaults and adding more versions
173*60517a1eSAndroid Build Coastguard Worker
174*60517a1eSAndroid Build Coastguard WorkerOne can perform various overrides for the registered toolchains from the root
175*60517a1eSAndroid Build Coastguard Workermodule. For example, the following use cases would be supported using the
176*60517a1eSAndroid Build Coastguard Workerexisting attributes:
177*60517a1eSAndroid Build Coastguard Worker
178*60517a1eSAndroid Build Coastguard Worker* Limiting the available toolchains for the entire `bzlmod` transitive graph
179*60517a1eSAndroid Build Coastguard Worker  via {attr}`python.override.available_python_versions`.
180*60517a1eSAndroid Build Coastguard Worker* Setting particular `X.Y.Z` Python versions when modules request `X.Y` version
181*60517a1eSAndroid Build Coastguard Worker  via {attr}`python.override.minor_mapping`.
182*60517a1eSAndroid Build Coastguard Worker* Per-version control of the coverage tool used using
183*60517a1eSAndroid Build Coastguard Worker  {attr}`python.single_version_platform_override.coverage_tool`.
184*60517a1eSAndroid Build Coastguard Worker* Adding additional Python versions via {bzl:obj}`python.single_version_override` or
185*60517a1eSAndroid Build Coastguard Worker  {bzl:obj}`python.single_version_platform_override`.
186*60517a1eSAndroid Build Coastguard Worker
187*60517a1eSAndroid Build Coastguard Worker## Workspace configuration
188*60517a1eSAndroid Build Coastguard Worker
189*60517a1eSAndroid Build Coastguard WorkerTo import rules_python in your project, you first need to add it to your
190*60517a1eSAndroid Build Coastguard Worker`WORKSPACE` file, using the snippet provided in the
191*60517a1eSAndroid Build Coastguard Worker[release you choose](https://github.com/bazelbuild/rules_python/releases)
192*60517a1eSAndroid Build Coastguard Worker
193*60517a1eSAndroid Build Coastguard WorkerTo depend on a particular unreleased version, you can do the following:
194*60517a1eSAndroid Build Coastguard Worker
195*60517a1eSAndroid Build Coastguard Worker```starlark
196*60517a1eSAndroid Build Coastguard Workerload("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
197*60517a1eSAndroid Build Coastguard Worker
198*60517a1eSAndroid Build Coastguard Worker
199*60517a1eSAndroid Build Coastguard Worker# Update the SHA and VERSION to the lastest version available here:
200*60517a1eSAndroid Build Coastguard Worker# https://github.com/bazelbuild/rules_python/releases.
201*60517a1eSAndroid Build Coastguard Worker
202*60517a1eSAndroid Build Coastguard WorkerSHA="84aec9e21cc56fbc7f1335035a71c850d1b9b5cc6ff497306f84cced9a769841"
203*60517a1eSAndroid Build Coastguard Worker
204*60517a1eSAndroid Build Coastguard WorkerVERSION="0.23.1"
205*60517a1eSAndroid Build Coastguard Worker
206*60517a1eSAndroid Build Coastguard Workerhttp_archive(
207*60517a1eSAndroid Build Coastguard Worker    name = "rules_python",
208*60517a1eSAndroid Build Coastguard Worker    sha256 = SHA,
209*60517a1eSAndroid Build Coastguard Worker    strip_prefix = "rules_python-{}".format(VERSION),
210*60517a1eSAndroid Build Coastguard Worker    url = "https://github.com/bazelbuild/rules_python/releases/download/{}/rules_python-{}.tar.gz".format(VERSION,VERSION),
211*60517a1eSAndroid Build Coastguard Worker)
212*60517a1eSAndroid Build Coastguard Worker
213*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:repositories.bzl", "py_repositories")
214*60517a1eSAndroid Build Coastguard Worker
215*60517a1eSAndroid Build Coastguard Workerpy_repositories()
216*60517a1eSAndroid Build Coastguard Worker```
217*60517a1eSAndroid Build Coastguard Worker
218*60517a1eSAndroid Build Coastguard Worker### Workspace toolchain registration
219*60517a1eSAndroid Build Coastguard Worker
220*60517a1eSAndroid Build Coastguard WorkerTo register a hermetic Python toolchain rather than rely on a system-installed interpreter for runtime execution, you can add to the `WORKSPACE` file:
221*60517a1eSAndroid Build Coastguard Worker
222*60517a1eSAndroid Build Coastguard Worker```starlark
223*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:repositories.bzl", "python_register_toolchains")
224*60517a1eSAndroid Build Coastguard Worker
225*60517a1eSAndroid Build Coastguard Workerpython_register_toolchains(
226*60517a1eSAndroid Build Coastguard Worker    name = "python_3_11",
227*60517a1eSAndroid Build Coastguard Worker    # Available versions are listed in @rules_python//python:versions.bzl.
228*60517a1eSAndroid Build Coastguard Worker    # We recommend using the same version your team is already standardized on.
229*60517a1eSAndroid Build Coastguard Worker    python_version = "3.11",
230*60517a1eSAndroid Build Coastguard Worker)
231*60517a1eSAndroid Build Coastguard Worker
232*60517a1eSAndroid Build Coastguard Workerload("@python_3_11//:defs.bzl", "interpreter")
233*60517a1eSAndroid Build Coastguard Worker
234*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:pip.bzl", "pip_parse")
235*60517a1eSAndroid Build Coastguard Worker
236*60517a1eSAndroid Build Coastguard Workerpip_parse(
237*60517a1eSAndroid Build Coastguard Worker    ...
238*60517a1eSAndroid Build Coastguard Worker    python_interpreter_target = interpreter,
239*60517a1eSAndroid Build Coastguard Worker    ...
240*60517a1eSAndroid Build Coastguard Worker)
241*60517a1eSAndroid Build Coastguard Worker```
242*60517a1eSAndroid Build Coastguard Worker
243*60517a1eSAndroid Build Coastguard WorkerAfter registration, your Python targets will use the toolchain's interpreter during execution, but a system-installed interpreter
244*60517a1eSAndroid Build Coastguard Workeris still used to 'bootstrap' Python targets (see https://github.com/bazelbuild/rules_python/issues/691).
245*60517a1eSAndroid Build Coastguard WorkerYou may also find some quirks while using this toolchain. Please refer to [python-build-standalone documentation's _Quirks_ section](https://gregoryszorc.com/docs/python-build-standalone/main/quirks.html).
246*60517a1eSAndroid Build Coastguard Worker
247*60517a1eSAndroid Build Coastguard Worker## Autodetecting toolchain
248*60517a1eSAndroid Build Coastguard Worker
249*60517a1eSAndroid Build Coastguard WorkerThe autodetecting toolchain is a deprecated toolchain that is built into Bazel.
250*60517a1eSAndroid Build Coastguard WorkerIt's name is a bit misleading: it doesn't autodetect anything. All it does is
251*60517a1eSAndroid Build Coastguard Workeruse `python3` from the environment a binary runs within. This provides extremely
252*60517a1eSAndroid Build Coastguard Workerlimited functionality to the rules (at build time, nothing is knowable about
253*60517a1eSAndroid Build Coastguard Workerthe Python runtime).
254*60517a1eSAndroid Build Coastguard Worker
255*60517a1eSAndroid Build Coastguard WorkerBazel itself automatically registers `@bazel_tools//tools/python:autodetecting_toolchain`
256*60517a1eSAndroid Build Coastguard Workeras the lowest priority toolchain. For WORKSPACE builds, if no other toolchain
257*60517a1eSAndroid Build Coastguard Workeris registered, that toolchain will be used. For bzlmod builds, rules_python
258*60517a1eSAndroid Build Coastguard Workerautomatically registers a higher-priority toolchain; it won't be used unless
259*60517a1eSAndroid Build Coastguard Workerthere is a toolchain misconfiguration somewhere.
260*60517a1eSAndroid Build Coastguard Worker
261*60517a1eSAndroid Build Coastguard WorkerTo aid migration off the Bazel-builtin toolchain, rules_python provides
262*60517a1eSAndroid Build Coastguard Worker{bzl:obj}`@rules_python//python/runtime_env_toolchains:all`. This is an equivalent
263*60517a1eSAndroid Build Coastguard Workertoolchain, but is implemented using rules_python's objects.
264*60517a1eSAndroid Build Coastguard Worker
265*60517a1eSAndroid Build Coastguard Worker
266*60517a1eSAndroid Build Coastguard Worker## Custom toolchains
267*60517a1eSAndroid Build Coastguard Worker
268*60517a1eSAndroid Build Coastguard WorkerWhile rules_python provides toolchains by default, it is not required to use
269*60517a1eSAndroid Build Coastguard Workerthem, and you can define your own toolchains to use instead. This section
270*60517a1eSAndroid Build Coastguard Workergives an introduction for how to define them yourself.
271*60517a1eSAndroid Build Coastguard Worker
272*60517a1eSAndroid Build Coastguard Worker:::{note}
273*60517a1eSAndroid Build Coastguard Worker* Defining your own toolchains is an advanced feature.
274*60517a1eSAndroid Build Coastguard Worker* APIs used for defining them are less stable and may change more often.
275*60517a1eSAndroid Build Coastguard Worker:::
276*60517a1eSAndroid Build Coastguard Worker
277*60517a1eSAndroid Build Coastguard WorkerUnder the hood, there are multiple toolchains that comprise the different
278*60517a1eSAndroid Build Coastguard Workerinformation necessary to build Python targets. Each one has an
279*60517a1eSAndroid Build Coastguard Workerassociated _toolchain type_ that identifies it. We call the collection of these
280*60517a1eSAndroid Build Coastguard Workertoolchains a "toolchain suite".
281*60517a1eSAndroid Build Coastguard Worker
282*60517a1eSAndroid Build Coastguard WorkerOne of the underlying design goals of the toolchains is to support complex and
283*60517a1eSAndroid Build Coastguard Workerbespoke environments. Such environments may use an arbitrary combination of
284*60517a1eSAndroid Build Coastguard Worker{obj}`RBE`, cross-platform building, multiple Python versions,
285*60517a1eSAndroid Build Coastguard Workerbuilding Python from source, embeding Python (as opposed to building separate
286*60517a1eSAndroid Build Coastguard Workerinterpreters), using prebuilt binaries, or using binaries built from source. To
287*60517a1eSAndroid Build Coastguard Workerthat end, many of the attributes they accept, and fields they provide, are
288*60517a1eSAndroid Build Coastguard Workeroptional.
289*60517a1eSAndroid Build Coastguard Worker
290*60517a1eSAndroid Build Coastguard Worker### Target toolchain type
291*60517a1eSAndroid Build Coastguard Worker
292*60517a1eSAndroid Build Coastguard WorkerThe target toolchain type is {obj}`//python:toolchain_type`, and it
293*60517a1eSAndroid Build Coastguard Workeris for _target configuration_ runtime information, e.g., the Python version
294*60517a1eSAndroid Build Coastguard Workerand interpreter binary that a program will use.
295*60517a1eSAndroid Build Coastguard Worker
296*60517a1eSAndroid Build Coastguard WorkerThe is typically implemented using {obj}`py_runtime()`, which
297*60517a1eSAndroid Build Coastguard Workerprovides the {obj}`PyRuntimeInfo` provider. For historical reasons from the
298*60517a1eSAndroid Build Coastguard WorkerPython 2 transition, `py_runtime` is wrapped in {obj}`py_runtime_pair`,
299*60517a1eSAndroid Build Coastguard Workerwhich provides {obj}`ToolchainInfo` with the field `py3_runtime`, which is an
300*60517a1eSAndroid Build Coastguard Workerinstance of `PyRuntimeInfo`.
301*60517a1eSAndroid Build Coastguard Worker
302*60517a1eSAndroid Build Coastguard WorkerThis toolchain type is intended to hold only _target configuration_ values. As
303*60517a1eSAndroid Build Coastguard Workersuch, when defining its associated {external:bzl:obj}`toolchain` target, only
304*60517a1eSAndroid Build Coastguard Workerset {external:bzl:obj}`toolchain.target_compatible_with` and/or
305*60517a1eSAndroid Build Coastguard Worker{external:bzl:obj}`toolchain.target_settings` constraints; there is no need to
306*60517a1eSAndroid Build Coastguard Workerset {external:bzl:obj}`toolchain.exec_compatible_with`.
307*60517a1eSAndroid Build Coastguard Worker
308*60517a1eSAndroid Build Coastguard Worker### Python C toolchain type
309*60517a1eSAndroid Build Coastguard Worker
310*60517a1eSAndroid Build Coastguard WorkerThe Python C toolchain type ("py cc") is {obj}`//python/cc:toolchain_type`, and
311*60517a1eSAndroid Build Coastguard Workerit has C/C++ information for the _target configuration_, e.g. the C headers that
312*60517a1eSAndroid Build Coastguard Workerprovide `Python.h`.
313*60517a1eSAndroid Build Coastguard Worker
314*60517a1eSAndroid Build Coastguard WorkerThis is typically implemented using {obj}`py_cc_toolchain()`, which provides
315*60517a1eSAndroid Build Coastguard Worker{obj}`ToolchainInfo` with the field `py_cc_toolchain` set, which is a
316*60517a1eSAndroid Build Coastguard Worker{obj}`PyCcToolchainInfo` provider instance.
317*60517a1eSAndroid Build Coastguard Worker
318*60517a1eSAndroid Build Coastguard WorkerThis toolchain type is intended to hold only _target configuration_ values
319*60517a1eSAndroid Build Coastguard Workerrelating to the C/C++ information for the Python runtime. As such, when defining
320*60517a1eSAndroid Build Coastguard Workerits associated {external:obj}`toolchain` target, only set
321*60517a1eSAndroid Build Coastguard Worker{external:bzl:obj}`toolchain.target_compatible_with` and/or
322*60517a1eSAndroid Build Coastguard Worker{external:bzl:obj}`toolchain.target_settings` constraints; there is no need to
323*60517a1eSAndroid Build Coastguard Workerset {external:bzl:obj}`toolchain.exec_compatible_with`.
324*60517a1eSAndroid Build Coastguard Worker
325*60517a1eSAndroid Build Coastguard Worker### Exec tools toolchain type
326*60517a1eSAndroid Build Coastguard Worker
327*60517a1eSAndroid Build Coastguard WorkerThe exec tools toolchain type is {obj}`//python:exec_tools_toolchain_type`,
328*60517a1eSAndroid Build Coastguard Workerand it is for supporting tools for _building_ programs, e.g. the binary to
329*60517a1eSAndroid Build Coastguard Workerprecompile code at build time.
330*60517a1eSAndroid Build Coastguard Worker
331*60517a1eSAndroid Build Coastguard WorkerThis toolchain type is intended to hold only _exec configuration_ values --
332*60517a1eSAndroid Build Coastguard Workerusually tools (prebuilt or from-source) used to build Python targets.
333*60517a1eSAndroid Build Coastguard Worker
334*60517a1eSAndroid Build Coastguard WorkerThis is typically implemented using {obj}`py_exec_tools_toolchain`, which
335*60517a1eSAndroid Build Coastguard Workerprovides {obj}`ToolchainInfo` with the field `exec_tools` set, which is an
336*60517a1eSAndroid Build Coastguard Workerinstance of {obj}`PyExecToolsInfo`.
337*60517a1eSAndroid Build Coastguard Worker
338*60517a1eSAndroid Build Coastguard WorkerThe toolchain constraints of this toolchain type can be a bit more nuanced than
339*60517a1eSAndroid Build Coastguard Workerthe other toolchain types. Typically, you set
340*60517a1eSAndroid Build Coastguard Worker{external:bzl:obj}`toolchain.target_settings` to the Python version the tools
341*60517a1eSAndroid Build Coastguard Workerare for, and {external:bzl:obj}`toolchain.exec_compatible_with` to the platform
342*60517a1eSAndroid Build Coastguard Workerthey can run on. This allows the toolchain to first be considered based on the
343*60517a1eSAndroid Build Coastguard Workertarget configuration (e.g. Python version), then for one to be chosen based on
344*60517a1eSAndroid Build Coastguard Workerfinding one compatible with the available host platforms to run the tool on.
345*60517a1eSAndroid Build Coastguard Worker
346*60517a1eSAndroid Build Coastguard WorkerHowever, what `target_compatible_with`/`target_settings` and
347*60517a1eSAndroid Build Coastguard Worker`exec_compatible_with` values to use depend on details of the tools being used.
348*60517a1eSAndroid Build Coastguard WorkerFor example:
349*60517a1eSAndroid Build Coastguard Worker* If you had a precompiler that supported any version of Python, then
350*60517a1eSAndroid Build Coastguard Worker  putting the Python version in `target_settings` is unnecessary.
351*60517a1eSAndroid Build Coastguard Worker* If you had a prebuilt polyglot precompiler binary that could run on any
352*60517a1eSAndroid Build Coastguard Worker  platform, then setting `exec_compatible_with` is unnecessary.
353*60517a1eSAndroid Build Coastguard Worker
354*60517a1eSAndroid Build Coastguard WorkerThis can work because, when the rules invoke these build tools, they pass along
355*60517a1eSAndroid Build Coastguard Workerall necessary information so that the tool can be entirely independent of the
356*60517a1eSAndroid Build Coastguard Workertarget configuration being built for.
357*60517a1eSAndroid Build Coastguard Worker
358*60517a1eSAndroid Build Coastguard WorkerAlternatively, if you had a precompiler that only ran on linux, and only
359*60517a1eSAndroid Build Coastguard Workerproduced valid output for programs intended to run on linux, then _both_
360*60517a1eSAndroid Build Coastguard Worker`exec_compatible_with` and `target_compatible_with` must be set to linux.
361*60517a1eSAndroid Build Coastguard Worker
362*60517a1eSAndroid Build Coastguard Worker### Custom toolchain example
363*60517a1eSAndroid Build Coastguard Worker
364*60517a1eSAndroid Build Coastguard WorkerHere, we show an example for a semi-complicated toolchain suite, one that is:
365*60517a1eSAndroid Build Coastguard Worker
366*60517a1eSAndroid Build Coastguard Worker* A CPython-based interpreter
367*60517a1eSAndroid Build Coastguard Worker* For Python version 3.12.0
368*60517a1eSAndroid Build Coastguard Worker* Using an in-build interpreter built from source
369*60517a1eSAndroid Build Coastguard Worker* That only runs on Linux
370*60517a1eSAndroid Build Coastguard Worker* Using a prebuilt precompiler that only runs on Linux, and only produces byte
371*60517a1eSAndroid Build Coastguard Worker  code valid for 3.12
372*60517a1eSAndroid Build Coastguard Worker* With the exec tools interpreter disabled (unnecessary with a prebuild
373*60517a1eSAndroid Build Coastguard Worker  precompiler)
374*60517a1eSAndroid Build Coastguard Worker* Providing C headers and libraries
375*60517a1eSAndroid Build Coastguard Worker
376*60517a1eSAndroid Build Coastguard WorkerDefining toolchains for this might look something like this:
377*60517a1eSAndroid Build Coastguard Worker
378*60517a1eSAndroid Build Coastguard Worker```
379*60517a1eSAndroid Build Coastguard Worker# File: toolchain_impls/BUILD
380*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:py_cc_toolchain.bzl", "py_cc_toolchain")
381*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:py_exec_tools_toolchain.bzl", "py_exec_tools_toolchain")
382*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:py_runtime.bzl", "py_runtime")
383*60517a1eSAndroid Build Coastguard Workerload("@rules_python//python:py_runtime_pair.bzl", "py_runtime_pair")
384*60517a1eSAndroid Build Coastguard Worker
385*60517a1eSAndroid Build Coastguard WorkerMAJOR = 3
386*60517a1eSAndroid Build Coastguard WorkerMINOR = 12
387*60517a1eSAndroid Build Coastguard WorkerMICRO = 0
388*60517a1eSAndroid Build Coastguard Worker
389*60517a1eSAndroid Build Coastguard Workerpy_runtime(
390*60517a1eSAndroid Build Coastguard Worker    name = "runtime",
391*60517a1eSAndroid Build Coastguard Worker    interpreter = ":python",
392*60517a1eSAndroid Build Coastguard Worker    interpreter_version_info = {
393*60517a1eSAndroid Build Coastguard Worker        "major": str(MAJOR),
394*60517a1eSAndroid Build Coastguard Worker        "minor": str(MINOR),
395*60517a1eSAndroid Build Coastguard Worker        "micro": str(MICRO),
396*60517a1eSAndroid Build Coastguard Worker    }
397*60517a1eSAndroid Build Coastguard Worker    implementation = "cpython"
398*60517a1eSAndroid Build Coastguard Worker)
399*60517a1eSAndroid Build Coastguard Workerpy_runtime_pair(
400*60517a1eSAndroid Build Coastguard Worker    name = "runtime_pair",
401*60517a1eSAndroid Build Coastguard Worker    py3_runtime = ":runtime"
402*60517a1eSAndroid Build Coastguard Worker)
403*60517a1eSAndroid Build Coastguard Worker
404*60517a1eSAndroid Build Coastguard Workerpy_cc_toolchain(
405*60517a1eSAndroid Build Coastguard Worker    name = "py_cc_toolchain_impl",
406*60517a1eSAndroid Build Coastguard Worker    headers = ":headers",
407*60517a1eSAndroid Build Coastguard Worker    libs = ":libs",
408*60517a1eSAndroid Build Coastguard Worker    python_version = "{}.{}".format(MAJOR, MINOR)
409*60517a1eSAndroid Build Coastguard Worker)
410*60517a1eSAndroid Build Coastguard Worker
411*60517a1eSAndroid Build Coastguard Workerpy_exec_tools_toolchain(
412*60517a1eSAndroid Build Coastguard Worker    name = "exec_tools_toolchain_impl",
413*60517a1eSAndroid Build Coastguard Worker    exec_interpreter = "@rules_python/python:none",
414*60517a1eSAndroid Build Coastguard Worker    precompiler = "precompiler-cpython-3.12"
415*60517a1eSAndroid Build Coastguard Worker)
416*60517a1eSAndroid Build Coastguard Worker
417*60517a1eSAndroid Build Coastguard Workercc_binary(name = "python3.12", ...)
418*60517a1eSAndroid Build Coastguard Workercc_library(name = "headers", ...)
419*60517a1eSAndroid Build Coastguard Workercc_library(name = "libs", ...)
420*60517a1eSAndroid Build Coastguard Worker
421*60517a1eSAndroid Build Coastguard Worker# File: toolchains/BUILD
422*60517a1eSAndroid Build Coastguard Worker# Putting toolchain() calls in a separate package from the toolchain
423*60517a1eSAndroid Build Coastguard Worker# implementations minimizes Bazel loading overhead
424*60517a1eSAndroid Build Coastguard Worker
425*60517a1eSAndroid Build Coastguard Workertoolchain(
426*60517a1eSAndroid Build Coastguard Worker    name = "runtime_toolchain",
427*60517a1eSAndroid Build Coastguard Worker    toolchain = "//toolchain_impl:runtime_pair",
428*60517a1eSAndroid Build Coastguard Worker    toolchain_type = "@rules_python//python:toolchain_type",
429*60517a1eSAndroid Build Coastguard Worker    target_compatible_with = ["@platforms/os:linux"]
430*60517a1eSAndroid Build Coastguard Worker)
431*60517a1eSAndroid Build Coastguard Workertoolchain(
432*60517a1eSAndroid Build Coastguard Worker    name = "py_cc_toolchain",
433*60517a1eSAndroid Build Coastguard Worker    toolchain = "//toolchain_impl:py_cc_toolchain_impl",
434*60517a1eSAndroid Build Coastguard Worker    toolchain_type = "@rules_python//python/cc:toolchain_type",
435*60517a1eSAndroid Build Coastguard Worker    target_compatible_with = ["@platforms/os:linux"]
436*60517a1eSAndroid Build Coastguard Worker)
437*60517a1eSAndroid Build Coastguard Worker
438*60517a1eSAndroid Build Coastguard Workertoolchain(
439*60517a1eSAndroid Build Coastguard Worker    name = "exec_tools_toolchain",
440*60517a1eSAndroid Build Coastguard Worker    toolchain = "//toolchain_impl:exec_tools_toolchain_impl",
441*60517a1eSAndroid Build Coastguard Worker    toolchain_type = "@rules_python//python:exec_tools_toolchain_type",
442*60517a1eSAndroid Build Coastguard Worker    target_settings = [
443*60517a1eSAndroid Build Coastguard Worker        "@rules_python//python/config_settings:is_python_3.12",
444*60517a1eSAndroid Build Coastguard Worker    ],
445*60517a1eSAndroid Build Coastguard Worker    exec_comaptible_with = ["@platforms/os:linux"]
446*60517a1eSAndroid Build Coastguard Worker)
447*60517a1eSAndroid Build Coastguard Worker```
448*60517a1eSAndroid Build Coastguard Worker
449*60517a1eSAndroid Build Coastguard Worker:::{note}
450*60517a1eSAndroid Build Coastguard WorkerThe toolchain() calls should be in a separate BUILD file from everything else.
451*60517a1eSAndroid Build Coastguard WorkerThis avoids Bazel having to perform unnecessary work when it discovers the list
452*60517a1eSAndroid Build Coastguard Workerof available toolchains.
453*60517a1eSAndroid Build Coastguard Worker:::
454