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