xref: /aosp_15_r20/external/bazelbuild-rules_python/docs/precompiling.md (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker# Precompiling
2*60517a1eSAndroid Build Coastguard Worker
3*60517a1eSAndroid Build Coastguard WorkerPrecompiling is compiling Python source files (`.py` files) into byte code
4*60517a1eSAndroid Build Coastguard Worker(`.pyc` files) at build time instead of runtime. Doing it at build time can
5*60517a1eSAndroid Build Coastguard Workerimprove performance by skipping that work at runtime.
6*60517a1eSAndroid Build Coastguard Worker
7*60517a1eSAndroid Build Coastguard WorkerPrecompiling is disabled by default, so you must enable it using flags or
8*60517a1eSAndroid Build Coastguard Workerattributes to use it.
9*60517a1eSAndroid Build Coastguard Worker
10*60517a1eSAndroid Build Coastguard Worker## Overhead of precompiling
11*60517a1eSAndroid Build Coastguard Worker
12*60517a1eSAndroid Build Coastguard WorkerWhile precompiling helps runtime performance, it has two main costs:
13*60517a1eSAndroid Build Coastguard Worker1. Increasing the size (count and disk usage) of runfiles. It approximately
14*60517a1eSAndroid Build Coastguard Worker   double the count of the runfiles because for every `.py` file, there is also
15*60517a1eSAndroid Build Coastguard Worker   a `.pyc` file. Compiled files are generally around the same size as the
16*60517a1eSAndroid Build Coastguard Worker   source files, so it approximately doubles the disk usage.
17*60517a1eSAndroid Build Coastguard Worker2. Precompiling requires running an extra action at build time. While
18*60517a1eSAndroid Build Coastguard Worker   compiling itself isn't that expensive, the overhead can become noticable
19*60517a1eSAndroid Build Coastguard Worker   as more files need to be compiled.
20*60517a1eSAndroid Build Coastguard Worker
21*60517a1eSAndroid Build Coastguard Worker## Binary-level opt-in
22*60517a1eSAndroid Build Coastguard Worker
23*60517a1eSAndroid Build Coastguard WorkerBecause of the costs of precompiling, it may not be feasible to globally enable it
24*60517a1eSAndroid Build Coastguard Workerfor your repo for everything. For example, some binaries may be
25*60517a1eSAndroid Build Coastguard Workerparticularly large, and doubling the number of runfiles isn't doable.
26*60517a1eSAndroid Build Coastguard Worker
27*60517a1eSAndroid Build Coastguard WorkerIf this is the case, there's an alternative way to more selectively and
28*60517a1eSAndroid Build Coastguard Workerincrementally control precompiling on a per-binry basis.
29*60517a1eSAndroid Build Coastguard Worker
30*60517a1eSAndroid Build Coastguard WorkerTo use this approach, the two basic steps are:
31*60517a1eSAndroid Build Coastguard Worker1. Disable pyc files from being automatically added to runfiles:
32*60517a1eSAndroid Build Coastguard Worker   {bzl:obj}`--@rules_python//python/config_settings:precompile_add_to_runfiles=decided_elsewhere`,
33*60517a1eSAndroid Build Coastguard Worker2. Set the `pyc_collection` attribute on the binaries/tests that should or should
34*60517a1eSAndroid Build Coastguard Worker   not use precompiling.
35*60517a1eSAndroid Build Coastguard Worker
36*60517a1eSAndroid Build Coastguard WorkerThe default for the `pyc_collection` attribute is controlled by the flag
37*60517a1eSAndroid Build Coastguard Worker{bzl:obj}`--@rules_python//python/config_settings:pyc_collection`, so you
38*60517a1eSAndroid Build Coastguard Workercan use an opt-in or opt-out approach by setting its value:
39*60517a1eSAndroid Build Coastguard Worker* targets must opt-out: `--@rules_python//python/config_settings:pyc_collection=include_pyc`
40*60517a1eSAndroid Build Coastguard Worker* targets must opt-in: `--@rules_python//python/config_settings:pyc_collection=disabled`
41*60517a1eSAndroid Build Coastguard Worker
42*60517a1eSAndroid Build Coastguard Worker## Advanced precompiler customization
43*60517a1eSAndroid Build Coastguard Worker
44*60517a1eSAndroid Build Coastguard WorkerThe default implementation of the precompiler is a persistent, multiplexed,
45*60517a1eSAndroid Build Coastguard Workersandbox-aware, cancellation-enabled, json-protocol worker that uses the same
46*60517a1eSAndroid Build Coastguard Workerinterpreter as the target toolchain. This works well for local builds, but may
47*60517a1eSAndroid Build Coastguard Workernot work as well for remote execution builds. To customize the precompiler, two
48*60517a1eSAndroid Build Coastguard Workermechanisms are available:
49*60517a1eSAndroid Build Coastguard Worker
50*60517a1eSAndroid Build Coastguard Worker* The exec tools toolchain allows customizing the precompiler binary used with
51*60517a1eSAndroid Build Coastguard Worker  the `precompiler` attribute. Arbitrary binaries are supported.
52*60517a1eSAndroid Build Coastguard Worker* The execution requirements can be customized using
53*60517a1eSAndroid Build Coastguard Worker  `--@rules_python//tools/precompiler:execution_requirements`. This is a list
54*60517a1eSAndroid Build Coastguard Worker  flag that can be repeated. Each entry is a key=value that is added to the
55*60517a1eSAndroid Build Coastguard Worker  execution requirements of the `PyCompile` action. Note that this flag
56*60517a1eSAndroid Build Coastguard Worker  is specific to the rules_python precompiler. If a custom binary is used,
57*60517a1eSAndroid Build Coastguard Worker  this flag will have to be propagated from the custom binary using the
58*60517a1eSAndroid Build Coastguard Worker  `testing.ExecutionInfo` provider; refer to the `py_interpreter_program` an
59*60517a1eSAndroid Build Coastguard Worker
60*60517a1eSAndroid Build Coastguard WorkerThe default precompiler implementation is an asynchronous/concurrent
61*60517a1eSAndroid Build Coastguard Workerimplementation. If you find it has bugs or hangs, please report them. In the
62*60517a1eSAndroid Build Coastguard Workermeantime, the flag `--worker_extra_flag=PyCompile=--worker_impl=serial` can
63*60517a1eSAndroid Build Coastguard Workerbe used to switch to a synchronous/serial implementation that may not perform
64*60517a1eSAndroid Build Coastguard Workeras well, but is less likely to have issues.
65*60517a1eSAndroid Build Coastguard Worker
66*60517a1eSAndroid Build Coastguard WorkerThe `execution_requirements` keys of most relevance are:
67*60517a1eSAndroid Build Coastguard Worker* `supports-workers`: 1 or 0, to indicate if a regular persistent worker is
68*60517a1eSAndroid Build Coastguard Worker  desired.
69*60517a1eSAndroid Build Coastguard Worker* `supports-multiplex-workers`: 1 o 0, to indicate if a multiplexed persistent
70*60517a1eSAndroid Build Coastguard Worker  worker is desired.
71*60517a1eSAndroid Build Coastguard Worker* `requires-worker-protocol`: json or proto; the rules_python precompiler
72*60517a1eSAndroid Build Coastguard Worker  currently only supports json.
73*60517a1eSAndroid Build Coastguard Worker* `supports-multiplex-sandboxing`: 1 or 0, to indicate if sanboxing is of the
74*60517a1eSAndroid Build Coastguard Worker  worker is supported.
75*60517a1eSAndroid Build Coastguard Worker* `supports-worker-cancellation`: 1 or 1, to indicate if requests to the worker
76*60517a1eSAndroid Build Coastguard Worker  can be cancelled.
77*60517a1eSAndroid Build Coastguard Worker
78*60517a1eSAndroid Build Coastguard WorkerNote that any execution requirements values can be specified in the flag.
79*60517a1eSAndroid Build Coastguard Worker
80*60517a1eSAndroid Build Coastguard Worker## Known issues, caveats, and idiosyncracies
81*60517a1eSAndroid Build Coastguard Worker
82*60517a1eSAndroid Build Coastguard Worker* Precompiling requires Bazel 7+ with the Pystar rule implementation enabled.
83*60517a1eSAndroid Build Coastguard Worker* Mixing rules_python PyInfo with Bazel builtin PyInfo will result in pyc files
84*60517a1eSAndroid Build Coastguard Worker  being dropped.
85*60517a1eSAndroid Build Coastguard Worker* Precompiled files may not be used in certain cases prior to Python 3.11. This
86*60517a1eSAndroid Build Coastguard Worker  occurs due Python adding the directory of the binary's main `.py` file, which
87*60517a1eSAndroid Build Coastguard Worker  causes the module to be found in the workspace source directory instead of
88*60517a1eSAndroid Build Coastguard Worker  within the binary's runfiles directory (where the pyc files are). This can
89*60517a1eSAndroid Build Coastguard Worker  usually be worked around by removing `sys.path[0]` (or otherwise ensuring the
90*60517a1eSAndroid Build Coastguard Worker  runfiles directory comes before the repos source directory in `sys.path`).
91*60517a1eSAndroid Build Coastguard Worker* The pyc filename does not include the optimization level (e.g.
92*60517a1eSAndroid Build Coastguard Worker  `foo.cpython-39.opt-2.pyc`). This works fine (it's all byte code), but also
93*60517a1eSAndroid Build Coastguard Worker  means the interpreter `-O` argument can't be used -- doing so will cause the
94*60517a1eSAndroid Build Coastguard Worker  interpreter to look for the non-existent `opt-N` named files.
95