1*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker========================= 4*61c4878aSAndroid Build Coastguard WorkerPigweed's GN Python Build 5*61c4878aSAndroid Build Coastguard Worker========================= 6*61c4878aSAndroid Build Coastguard Worker 7*61c4878aSAndroid Build Coastguard Worker.. seealso:: 8*61c4878aSAndroid Build Coastguard Worker - :bdg-ref-primary-line:`module-pw_build-python` for detailed template usage. 9*61c4878aSAndroid Build Coastguard Worker - :bdg-ref-primary-line:`module-pw_build` for other GN templates available 10*61c4878aSAndroid Build Coastguard Worker within Pigweed. 11*61c4878aSAndroid Build Coastguard Worker - :bdg-ref-primary-line:`docs-build-system` for a high level guide and 12*61c4878aSAndroid Build Coastguard Worker background information on Pigweed's build system as a whole. 13*61c4878aSAndroid Build Coastguard Worker 14*61c4878aSAndroid Build Coastguard WorkerPigweed uses a custom GN-based build system to manage its Python code. The 15*61c4878aSAndroid Build Coastguard WorkerPigweed Python build supports packaging, installation and distribution of 16*61c4878aSAndroid Build Coastguard Workerinterdependent local Python packages. It also provides for fast, incremental 17*61c4878aSAndroid Build Coastguard Workerstatic analysis and test running suitable for live use during development (e.g. 18*61c4878aSAndroid Build Coastguard Workerwith :ref:`module-pw_watch`) or in continuous integration. 19*61c4878aSAndroid Build Coastguard Worker 20*61c4878aSAndroid Build Coastguard WorkerPigweed's Python code is exclusively managed by GN, but the GN-based build may 21*61c4878aSAndroid Build Coastguard Workerbe used alongside CMake, Bazel, or any other build system. Pigweed's environment 22*61c4878aSAndroid Build Coastguard Workersetup uses GN to set up the initial Python environment, regardless of the final 23*61c4878aSAndroid Build Coastguard Workerbuild system. As needed, non-GN projects can declare just their Python packages 24*61c4878aSAndroid Build Coastguard Workerin GN. 25*61c4878aSAndroid Build Coastguard Worker 26*61c4878aSAndroid Build Coastguard WorkerHow it Works 27*61c4878aSAndroid Build Coastguard Worker============ 28*61c4878aSAndroid Build Coastguard WorkerIn addition to compiler commands a Pigweed GN build will execute Python scripts 29*61c4878aSAndroid Build Coastguard Workerfor various reasons including running tests, linting code, generating protos and 30*61c4878aSAndroid Build Coastguard Workermore. All these scripts are run as part of a 31*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_action` GN template which will ultimately run 32*61c4878aSAndroid Build Coastguard Worker``python``. Running Python on it's own by default will make any Python packages 33*61c4878aSAndroid Build Coastguard Workerinstalled on the users system available for importing. This is not good and can 34*61c4878aSAndroid Build Coastguard Workerlead to flaky builds when different packages are installed on each developer 35*61c4878aSAndroid Build Coastguard Workerworkstation. To get around this the Python community uses `virtual environments 36*61c4878aSAndroid Build Coastguard Worker<https://docs.python.org/3/library/venv.html>`_ (venvs) that expose a specific 37*61c4878aSAndroid Build Coastguard Workerset of Python packages separate from the host system. 38*61c4878aSAndroid Build Coastguard Worker 39*61c4878aSAndroid Build Coastguard WorkerWhen a Pigweed GN build starts a single venv is created for use by all 40*61c4878aSAndroid Build Coastguard Worker:ref:`pw_python_actions <module-pw_build-pw_python_action>` throughout the build 41*61c4878aSAndroid Build Coastguard Workergraph. Once created, all required third-party Python packages needed for the 42*61c4878aSAndroid Build Coastguard Workerproject are installed. At that point no further modifications are made to 43*61c4878aSAndroid Build Coastguard Workerthe venv. Of course if a new third-party package dependency is added it will be 44*61c4878aSAndroid Build Coastguard Workerinstalled too. Beyond that all venvs remain static. More venvs can be created 45*61c4878aSAndroid Build Coastguard Workerwith the :ref:`module-pw_build-pw_python_venv` template if desired, but only one 46*61c4878aSAndroid Build Coastguard Workeris used by default. 47*61c4878aSAndroid Build Coastguard Worker 48*61c4878aSAndroid Build Coastguard Worker.. card:: 49*61c4878aSAndroid Build Coastguard Worker 50*61c4878aSAndroid Build Coastguard Worker **Every pw_python_action is run inside a venv** 51*61c4878aSAndroid Build Coastguard Worker ^^^ 52*61c4878aSAndroid Build Coastguard Worker .. mermaid:: 53*61c4878aSAndroid Build Coastguard Worker :caption: 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard Worker flowchart LR 56*61c4878aSAndroid Build Coastguard Worker out[GN Build Dir<br/>fa:fa-folder out] 57*61c4878aSAndroid Build Coastguard Worker 58*61c4878aSAndroid Build Coastguard Worker out -->|ninja -C out| createvenvs 59*61c4878aSAndroid Build Coastguard Worker 60*61c4878aSAndroid Build Coastguard Worker createvenvs(Create venvs) 61*61c4878aSAndroid Build Coastguard Worker createvenvs --> pyactions1 62*61c4878aSAndroid Build Coastguard Worker createvenvs --> pyactions2 63*61c4878aSAndroid Build Coastguard Worker 64*61c4878aSAndroid Build Coastguard Worker subgraph pyactions1[Python venv 1] 65*61c4878aSAndroid Build Coastguard Worker direction TB 66*61c4878aSAndroid Build Coastguard Worker venv1(fa:fa-folder out/python-venv  ) 67*61c4878aSAndroid Build Coastguard Worker a1["pw_python_action('one')"] 68*61c4878aSAndroid Build Coastguard Worker a2["pw_python_action('two')"] 69*61c4878aSAndroid Build Coastguard Worker venv1 --> a1 70*61c4878aSAndroid Build Coastguard Worker venv1 --> a2 71*61c4878aSAndroid Build Coastguard Worker end 72*61c4878aSAndroid Build Coastguard Worker 73*61c4878aSAndroid Build Coastguard Worker subgraph pyactions2[Python venv 2] 74*61c4878aSAndroid Build Coastguard Worker direction TB 75*61c4878aSAndroid Build Coastguard Worker venv2(fa:fa-folder out/another-venv  ) 76*61c4878aSAndroid Build Coastguard Worker a3["pw_python_action('three')"] 77*61c4878aSAndroid Build Coastguard Worker a4["pw_python_action('four')"] 78*61c4878aSAndroid Build Coastguard Worker venv2 --> a3 79*61c4878aSAndroid Build Coastguard Worker venv2 --> a4 80*61c4878aSAndroid Build Coastguard Worker end 81*61c4878aSAndroid Build Coastguard Worker 82*61c4878aSAndroid Build Coastguard Worker.. note:: 83*61c4878aSAndroid Build Coastguard Worker 84*61c4878aSAndroid Build Coastguard Worker Pigweed uses `this venv target 85*61c4878aSAndroid Build Coastguard Worker <https://cs.opensource.google/pigweed/pigweed/+/main:pw_env_setup/BUILD.gn?q=pigweed_build_venv>`_ 86*61c4878aSAndroid Build Coastguard Worker if a project does not specify it's own build venv. See 87*61c4878aSAndroid Build Coastguard Worker :bdg-ref-primary-line:`docs-python-build-python-gn-venv` on how to define 88*61c4878aSAndroid Build Coastguard Worker your own default venv. 89*61c4878aSAndroid Build Coastguard Worker 90*61c4878aSAndroid Build Coastguard WorkerHaving a static venv containing only third-party dependencies opens the flood 91*61c4878aSAndroid Build Coastguard Workergates for python scripts to run. If the venv only contains third-party 92*61c4878aSAndroid Build Coastguard Workerdependencies you may be wondering how you can import your own in-tree Python 93*61c4878aSAndroid Build Coastguard Workerpackages. Python code run in the build may still import any in-tree Python 94*61c4878aSAndroid Build Coastguard Workerpackages created with :ref:`module-pw_build-pw_python_package` 95*61c4878aSAndroid Build Coastguard Workertemplates. However this only works if a correct ``python_deps`` arg is 96*61c4878aSAndroid Build Coastguard Workerprovided. Having that Python dependency defined in GN allows the 97*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_action` 98*61c4878aSAndroid Build Coastguard Workerto set `PYTHONPATH 99*61c4878aSAndroid Build Coastguard Worker<https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH>`_ so that given 100*61c4878aSAndroid Build Coastguard Workerpackage can be imported. This has the benefit of the build failing if a 101*61c4878aSAndroid Build Coastguard Workerdependency for any Python action or package is missing. 102*61c4878aSAndroid Build Coastguard Worker 103*61c4878aSAndroid Build Coastguard Worker.. admonition:: Benefits of Python ``venvs`` in GN 104*61c4878aSAndroid Build Coastguard Worker :class: important 105*61c4878aSAndroid Build Coastguard Worker 106*61c4878aSAndroid Build Coastguard Worker - Using venvs to execute Python in GN provides reproducible builds with fixed 107*61c4878aSAndroid Build Coastguard Worker third-party dependencies. 108*61c4878aSAndroid Build Coastguard Worker - Using ``PYTHONPATH`` coupled with ``python_deps`` to import in-tree Python 109*61c4878aSAndroid Build Coastguard Worker packages enforces dependency correctness. 110*61c4878aSAndroid Build Coastguard Worker 111*61c4878aSAndroid Build Coastguard Worker 112*61c4878aSAndroid Build Coastguard WorkerManaging Python Requirements 113*61c4878aSAndroid Build Coastguard Worker============================ 114*61c4878aSAndroid Build Coastguard Worker 115*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-python-gn-venv: 116*61c4878aSAndroid Build Coastguard Worker 117*61c4878aSAndroid Build Coastguard WorkerBuild Time Python Virtualenv 118*61c4878aSAndroid Build Coastguard Worker---------------------------- 119*61c4878aSAndroid Build Coastguard WorkerPigweed's GN Python build infrastructure relies on `Python virtual environments 120*61c4878aSAndroid Build Coastguard Worker<https://docs.python.org/3/library/venv.html>`_ for executing Python code. This 121*61c4878aSAndroid Build Coastguard Workerprovides a controlled isolated environment with a defined set of third party 122*61c4878aSAndroid Build Coastguard WorkerPython constraints where all Python tests, linting and 123*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_action` targets are executed. 124*61c4878aSAndroid Build Coastguard Worker 125*61c4878aSAndroid Build Coastguard WorkerThere must be at least one venv for Python defined in GN. There can be multiple 126*61c4878aSAndroid Build Coastguard Workervenvs but one must be the designated default. 127*61c4878aSAndroid Build Coastguard Worker 128*61c4878aSAndroid Build Coastguard WorkerThe default build venv is specified via a GN arg and is best set in the root 129*61c4878aSAndroid Build Coastguard Worker``.gn`` or ``BUILD.gn`` file. For example: 130*61c4878aSAndroid Build Coastguard Worker 131*61c4878aSAndroid Build Coastguard Worker.. code-block:: 132*61c4878aSAndroid Build Coastguard Worker 133*61c4878aSAndroid Build Coastguard Worker pw_build_PYTHON_BUILD_VENV = "//:project_build_venv" 134*61c4878aSAndroid Build Coastguard Worker 135*61c4878aSAndroid Build Coastguard Worker.. tip:: 136*61c4878aSAndroid Build Coastguard Worker Additional :ref:`module-pw_build-pw_python_venv` targets can be created as 137*61c4878aSAndroid Build Coastguard Worker needed. The :ref:`module-pw_build-pw_python_action` template can take an 138*61c4878aSAndroid Build Coastguard Worker optional ``venv`` argument to specify which Python venv it should run 139*61c4878aSAndroid Build Coastguard Worker within. If not specified the target referred in the 140*61c4878aSAndroid Build Coastguard Worker ``pw_build_PYTHON_BUILD_VENV`` is used. 141*61c4878aSAndroid Build Coastguard Worker 142*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-python-gn-requirements-files: 143*61c4878aSAndroid Build Coastguard Worker 144*61c4878aSAndroid Build Coastguard WorkerThird-party Python Requirements and Constraints 145*61c4878aSAndroid Build Coastguard Worker----------------------------------------------- 146*61c4878aSAndroid Build Coastguard WorkerYour project may have third party Python dependencies you wish to install into 147*61c4878aSAndroid Build Coastguard Workerthe bootstrapped environment and in the GN build venv. There are two main ways 148*61c4878aSAndroid Build Coastguard Workerto add Python package dependencies: 149*61c4878aSAndroid Build Coastguard Worker 150*61c4878aSAndroid Build Coastguard Worker**Adding Requirements Files** 151*61c4878aSAndroid Build Coastguard Worker 152*61c4878aSAndroid Build Coastguard Worker1. Add a ``install_requires`` entry to a ``setup.cfg`` file defined in a 153*61c4878aSAndroid Build Coastguard Worker :ref:`module-pw_build-pw_python_package` template. This is the best option 154*61c4878aSAndroid Build Coastguard Worker if your in-tree Python package requires an external Python package. 155*61c4878aSAndroid Build Coastguard Worker 156*61c4878aSAndroid Build Coastguard Worker2. Create a standard Python ``requirements.txt`` file in your project and add it 157*61c4878aSAndroid Build Coastguard Worker to the ``pw_build_PIP_REQUIREMENTS`` GN arg list. 158*61c4878aSAndroid Build Coastguard Worker 159*61c4878aSAndroid Build Coastguard Worker Requirements files support a wide range of install locations including 160*61c4878aSAndroid Build Coastguard Worker packages from pypi.org, the local file system and git repos. See `pip's 161*61c4878aSAndroid Build Coastguard Worker Requirements File documentation 162*61c4878aSAndroid Build Coastguard Worker <https://pip.pypa.io/en/stable/user_guide/#requirements-files>`_ for more 163*61c4878aSAndroid Build Coastguard Worker info. 164*61c4878aSAndroid Build Coastguard Worker 165*61c4878aSAndroid Build Coastguard Worker The GN arg can be set in your project's root ``.gn`` or ``BUILD.gn`` file. 166*61c4878aSAndroid Build Coastguard Worker 167*61c4878aSAndroid Build Coastguard Worker .. code-block:: 168*61c4878aSAndroid Build Coastguard Worker 169*61c4878aSAndroid Build Coastguard Worker pw_build_PIP_REQUIREMENTS = [ 170*61c4878aSAndroid Build Coastguard Worker # Project specific requirements 171*61c4878aSAndroid Build Coastguard Worker "//tools/requirements.txt", 172*61c4878aSAndroid Build Coastguard Worker ] 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker See the :ref:`docs-python-build-python-gn-structure` section below for a full 175*61c4878aSAndroid Build Coastguard Worker code listing. 176*61c4878aSAndroid Build Coastguard Worker 177*61c4878aSAndroid Build Coastguard Worker**Adding Constraints Files** 178*61c4878aSAndroid Build Coastguard Worker 179*61c4878aSAndroid Build Coastguard WorkerEvery project should ideally inherit Pigweed's third party Python package 180*61c4878aSAndroid Build Coastguard Workerversion. This is accomplished via `Python constraints files 181*61c4878aSAndroid Build Coastguard Worker<https://pip.pypa.io/en/stable/user_guide/#constraints-files>`_. Constraints 182*61c4878aSAndroid Build Coastguard Workercontrol which versions of packages get installed by ``pip`` if that package is 183*61c4878aSAndroid Build Coastguard Workerinstalled. To inherit Pigweed's Python constraints include ``constraint.list`` 184*61c4878aSAndroid Build Coastguard Workerfrom the ``pw_env_setup`` module from in your top level ``.gn`` file. Additonal 185*61c4878aSAndroid Build Coastguard Workerproject specific constraints can be appended to this list. 186*61c4878aSAndroid Build Coastguard Worker 187*61c4878aSAndroid Build Coastguard Worker.. code-block:: 188*61c4878aSAndroid Build Coastguard Worker 189*61c4878aSAndroid Build Coastguard Worker pw_build_PIP_CONSTRAINTS = [ 190*61c4878aSAndroid Build Coastguard Worker "$dir_pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list", 191*61c4878aSAndroid Build Coastguard Worker "//tools/constraints.txt", 192*61c4878aSAndroid Build Coastguard Worker ] 193*61c4878aSAndroid Build Coastguard Worker 194*61c4878aSAndroid Build Coastguard WorkerIn-tree ``pw_python_package`` Requirements 195*61c4878aSAndroid Build Coastguard Worker------------------------------------------ 196*61c4878aSAndroid Build Coastguard WorkerA given venv inherits a project's requirements and constraint files by default 197*61c4878aSAndroid Build Coastguard Workervia the ``pw_build_PIP_CONSTRAINTS`` and ``pw_build_PIP_REQUIREMENTS`` GN args 198*61c4878aSAndroid Build Coastguard Workeras described above. This can be overridden if needed. 199*61c4878aSAndroid Build Coastguard Worker 200*61c4878aSAndroid Build Coastguard Worker``generated_requirements.txt`` 201*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 202*61c4878aSAndroid Build Coastguard WorkerTo ensure the requirements of in-tree :ref:`module-pw_build-pw_python_package` 203*61c4878aSAndroid Build Coastguard Workertargets are installed :ref:`module-pw_build-pw_python_venv` introduces the 204*61c4878aSAndroid Build Coastguard Worker``source_packages`` argument. This is a list of in-tree ``pw_python_package`` 205*61c4878aSAndroid Build Coastguard WorkerGN targets expected to be used within the venv. When the venv is created each 206*61c4878aSAndroid Build Coastguard Worker``pw_python_package``'s ``setup.cfg`` file is read to pull the 207*61c4878aSAndroid Build Coastguard Worker``install_requires`` section for all third party dependencies. The full list of 208*61c4878aSAndroid Build Coastguard Workerall in-tree packages and any in-tree transitive dependencies is then written to 209*61c4878aSAndroid Build Coastguard Workerthe out directory in a single ``generated_requirements.txt``. 210*61c4878aSAndroid Build Coastguard Worker 211*61c4878aSAndroid Build Coastguard WorkerTake the ``//pw_build/py/gn_tests:downstream_tools_build_venv`` example below, 212*61c4878aSAndroid Build Coastguard Workerits ``source package`` is a single ``pw_python_distribution`` package which 213*61c4878aSAndroid Build Coastguard Workerbundles the ``pw_env_setup`` and ``pw_console`` ``pw_python_package``s. Those 214*61c4878aSAndroid Build Coastguard Workertwo packages each depend on a few other ``pw_python_package`` targets. The 215*61c4878aSAndroid Build Coastguard Workeroutput ``generated_requirements.txt`` below merges all these package deps and 216*61c4878aSAndroid Build Coastguard Workeradds ``-c`` lines for constraint files. 217*61c4878aSAndroid Build Coastguard Worker 218*61c4878aSAndroid Build Coastguard Worker.. seealso:: 219*61c4878aSAndroid Build Coastguard Worker The pip documentation on the `Requirements File Format 220*61c4878aSAndroid Build Coastguard Worker <https://pip.pypa.io/en/stable/reference/requirements-file-format/#requirements-file-format>`_ 221*61c4878aSAndroid Build Coastguard Worker 222*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/py/gn_tests/BUILD.gn 223*61c4878aSAndroid Build Coastguard Worker :start-after: [downstream-project-venv] 224*61c4878aSAndroid Build Coastguard Worker :end-before: [downstream-project-venv] 225*61c4878aSAndroid Build Coastguard Worker 226*61c4878aSAndroid Build Coastguard Worker.. code-block:: 227*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file;1em` out/python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/generated_requirements.txt 228*61c4878aSAndroid Build Coastguard Worker :name: generated_requirements 229*61c4878aSAndroid Build Coastguard Worker 230*61c4878aSAndroid Build Coastguard Worker # Auto-generated requirements.txt from the following packages: 231*61c4878aSAndroid Build Coastguard Worker # 232*61c4878aSAndroid Build Coastguard Worker # //pw_arduino_build/py:py 233*61c4878aSAndroid Build Coastguard Worker # //pw_build/py/gn_tests:downstream_project_tools 234*61c4878aSAndroid Build Coastguard Worker # //pw_build/py:py 235*61c4878aSAndroid Build Coastguard Worker # //pw_cli/py:py 236*61c4878aSAndroid Build Coastguard Worker # //pw_console/py:py 237*61c4878aSAndroid Build Coastguard Worker # //pw_env_setup/py:py 238*61c4878aSAndroid Build Coastguard Worker # //pw_log_tokenized/py:py 239*61c4878aSAndroid Build Coastguard Worker # //pw_package/py:py 240*61c4878aSAndroid Build Coastguard Worker # //pw_presubmit/py:py 241*61c4878aSAndroid Build Coastguard Worker # //pw_stm32cube_build/py:py 242*61c4878aSAndroid Build Coastguard Worker 243*61c4878aSAndroid Build Coastguard Worker # Constraint files: 244*61c4878aSAndroid Build Coastguard Worker -c ../../../../../../../pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list 245*61c4878aSAndroid Build Coastguard Worker 246*61c4878aSAndroid Build Coastguard Worker black>=23.1.0 247*61c4878aSAndroid Build Coastguard Worker build>=0.8.0 248*61c4878aSAndroid Build Coastguard Worker coloredlogs 249*61c4878aSAndroid Build Coastguard Worker coverage 250*61c4878aSAndroid Build Coastguard Worker ipython 251*61c4878aSAndroid Build Coastguard Worker jinja2 252*61c4878aSAndroid Build Coastguard Worker mypy>=0.971 253*61c4878aSAndroid Build Coastguard Worker parameterized 254*61c4878aSAndroid Build Coastguard Worker pip-tools>=6.12.3 255*61c4878aSAndroid Build Coastguard Worker prompt-toolkit>=3.0.26 256*61c4878aSAndroid Build Coastguard Worker psutil 257*61c4878aSAndroid Build Coastguard Worker ptpython>=3.0.20 258*61c4878aSAndroid Build Coastguard Worker pygments 259*61c4878aSAndroid Build Coastguard Worker pylint>=2.9.3 260*61c4878aSAndroid Build Coastguard Worker pyperclip 261*61c4878aSAndroid Build Coastguard Worker pyserial>=3.5,<4.0 262*61c4878aSAndroid Build Coastguard Worker pyyaml 263*61c4878aSAndroid Build Coastguard Worker setuptools 264*61c4878aSAndroid Build Coastguard Worker six 265*61c4878aSAndroid Build Coastguard Worker toml 266*61c4878aSAndroid Build Coastguard Worker types-pygments 267*61c4878aSAndroid Build Coastguard Worker types-pyserial>=3.5,<4.0 268*61c4878aSAndroid Build Coastguard Worker types-pyyaml 269*61c4878aSAndroid Build Coastguard Worker types-setuptools 270*61c4878aSAndroid Build Coastguard Worker types-six 271*61c4878aSAndroid Build Coastguard Worker websockets 272*61c4878aSAndroid Build Coastguard Worker wheel 273*61c4878aSAndroid Build Coastguard Worker yapf>=0.31.0 274*61c4878aSAndroid Build Coastguard Worker 275*61c4878aSAndroid Build Coastguard Worker``compiled_requirements.txt`` 276*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 277*61c4878aSAndroid Build Coastguard WorkerThe above ``generated_requirements.txt`` file is then fed into the 278*61c4878aSAndroid Build Coastguard Worker``pip-compile`` command from `the pip-tools package 279*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/pip-tools>`_ to fully expand and pin each package with 280*61c4878aSAndroid Build Coastguard Workerhashes. The resulting ``compiled_requirements.txt`` can then be used as the 281*61c4878aSAndroid Build Coastguard Workersingle Python requirements file for replicating this ``pw_python_venv`` 282*61c4878aSAndroid Build Coastguard Workerelsewhere. Each ``pw_python_venv`` will get this single file containing the 283*61c4878aSAndroid Build Coastguard Workerexact versions of each required Python package. 284*61c4878aSAndroid Build Coastguard Worker 285*61c4878aSAndroid Build Coastguard Worker.. tip:: 286*61c4878aSAndroid Build Coastguard Worker The ``compiled_requirements.txt`` generated by a ``pw_python_venv`` is used 287*61c4878aSAndroid Build Coastguard Worker by the :ref:`module-pw_build-pw_python_zip_with_setup` template when 288*61c4878aSAndroid Build Coastguard Worker producing a self contained zip of in-tree and third party Python packages. 289*61c4878aSAndroid Build Coastguard Worker 290*61c4878aSAndroid Build Coastguard WorkerBelow is a snippet of the ``compiled_requirements.txt`` for this 291*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_venv` target: 292*61c4878aSAndroid Build Coastguard Worker``//pw_build/py/gn_tests:downstream_tools_build_venv`` 293*61c4878aSAndroid Build Coastguard Worker 294*61c4878aSAndroid Build Coastguard Worker.. code-block:: 295*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file;1em` out/python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/compiled_requirements.txt 296*61c4878aSAndroid Build Coastguard Worker :name: compiled_requirements 297*61c4878aSAndroid Build Coastguard Worker 298*61c4878aSAndroid Build Coastguard Worker # 299*61c4878aSAndroid Build Coastguard Worker # This file is autogenerated by pip-compile with Python 3.11 300*61c4878aSAndroid Build Coastguard Worker # by the following command: 301*61c4878aSAndroid Build Coastguard Worker # 302*61c4878aSAndroid Build Coastguard Worker # pip-compile --allow-unsafe --generate-hashes 303*61c4878aSAndroid Build Coastguard Worker # --output-file=python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/compiled_requirements.txt 304*61c4878aSAndroid Build Coastguard Worker # --resolver=backtracking 305*61c4878aSAndroid Build Coastguard Worker # python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/generated_requirements.txt 306*61c4878aSAndroid Build Coastguard Worker # 307*61c4878aSAndroid Build Coastguard Worker appdirs==1.4.4 \ 308*61c4878aSAndroid Build Coastguard Worker --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \ 309*61c4878aSAndroid Build Coastguard Worker --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 310*61c4878aSAndroid Build Coastguard Worker # via 311*61c4878aSAndroid Build Coastguard Worker # -c python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/../../../../../../../pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list 312*61c4878aSAndroid Build Coastguard Worker # ptpython 313*61c4878aSAndroid Build Coastguard Worker astroid==2.14.2 \ 314*61c4878aSAndroid Build Coastguard Worker --hash=sha256:0e0e3709d64fbffd3037e4ff403580550f14471fd3eaae9fa11cc9a5c7901153 \ 315*61c4878aSAndroid Build Coastguard Worker --hash=sha256:a3cf9f02c53dd259144a7e8f3ccd75d67c9a8c716ef183e0c1f291bc5d7bb3cf 316*61c4878aSAndroid Build Coastguard Worker # via 317*61c4878aSAndroid Build Coastguard Worker # -c python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/../../../../../../../pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list 318*61c4878aSAndroid Build Coastguard Worker # pylint 319*61c4878aSAndroid Build Coastguard Worker ... 320*61c4878aSAndroid Build Coastguard Worker 321*61c4878aSAndroid Build Coastguard WorkerThe presence of hashes in the above example can be controlled via the 322*61c4878aSAndroid Build Coastguard Worker``pip_generate_hashes`` arg to the :ref:`module-pw_build-pw_python_venv` 323*61c4878aSAndroid Build Coastguard Workertemplate. 324*61c4878aSAndroid Build Coastguard Worker 325*61c4878aSAndroid Build Coastguard WorkerCaching Python Packages for Offline Installation 326*61c4878aSAndroid Build Coastguard Worker------------------------------------------------ 327*61c4878aSAndroid Build Coastguard Worker 328*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-downloading-packages: 329*61c4878aSAndroid Build Coastguard Worker 330*61c4878aSAndroid Build Coastguard WorkerDownloading Packages 331*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^ 332*61c4878aSAndroid Build Coastguard WorkerThe :ref:`module-pw_build-pw_python_venv` target adds an optional sub target 333*61c4878aSAndroid Build Coastguard Workerthat will download all Python packages from remote servers into a local 334*61c4878aSAndroid Build Coastguard Workerdirectory. The remote server is typically `pypi.org <https://pypi.org/>`_. 335*61c4878aSAndroid Build Coastguard Worker 336*61c4878aSAndroid Build Coastguard WorkerTaking the ``//pw_build/py/gn_tests:downstream_tools_build_venv`` target as an 337*61c4878aSAndroid Build Coastguard Workerexample again let's build a local cache. To run the download target append 338*61c4878aSAndroid Build Coastguard Worker``.vendor_wheels`` to the end of the ``pw_python_venv`` target name. In this 339*61c4878aSAndroid Build Coastguard Workerexample it would be 340*61c4878aSAndroid Build Coastguard Worker``//pw_build/py/gn_tests:downstream_tools_build_venv.vendor_wheels`` 341*61c4878aSAndroid Build Coastguard Worker 342*61c4878aSAndroid Build Coastguard WorkerTo build that one gn target with ninja, pass the output name from gn as a target 343*61c4878aSAndroid Build Coastguard Workername for ninja: 344*61c4878aSAndroid Build Coastguard Worker 345*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash 346*61c4878aSAndroid Build Coastguard Worker 347*61c4878aSAndroid Build Coastguard Worker gn gen out 348*61c4878aSAndroid Build Coastguard Worker ninja -C out \ 349*61c4878aSAndroid Build Coastguard Worker $(gn ls out --as=output \ 350*61c4878aSAndroid Build Coastguard Worker '//pw_build/py/gn_tests:downstream_tools_build_venv.vendor_wheels') 351*61c4878aSAndroid Build Coastguard Worker 352*61c4878aSAndroid Build Coastguard WorkerThis creates a ``wheels`` folder with all downloaded packages and a 353*61c4878aSAndroid Build Coastguard Worker``pip_download_log.txt`` with verbose logs from running ``pip download``. 354*61c4878aSAndroid Build Coastguard Worker 355*61c4878aSAndroid Build Coastguard Worker.. code-block:: 356*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file-directory;1em` Vendor wheels output directory 357*61c4878aSAndroid Build Coastguard Worker :name: vendor-wheel-output 358*61c4878aSAndroid Build Coastguard Worker 359*61c4878aSAndroid Build Coastguard Worker out/python/gen/pw_build/py/gn_tests/downstream_tools_build_venv.vendor_wheels/ 360*61c4878aSAndroid Build Coastguard Worker ├── pip_download_log.txt 361*61c4878aSAndroid Build Coastguard Worker └── wheels 362*61c4878aSAndroid Build Coastguard Worker ├── appdirs-1.4.4-py2.py3-none-any.whl 363*61c4878aSAndroid Build Coastguard Worker ├── astroid-2.14.2-py3-none-any.whl 364*61c4878aSAndroid Build Coastguard Worker ├── backcall-0.2.0-py2.py3-none-any.whl 365*61c4878aSAndroid Build Coastguard Worker ├── black-23.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl 366*61c4878aSAndroid Build Coastguard Worker ├ ... 367*61c4878aSAndroid Build Coastguard Worker ├── websockets-10.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl 368*61c4878aSAndroid Build Coastguard Worker ├── wheel-0.40.0-py3-none-any.whl 369*61c4878aSAndroid Build Coastguard Worker ├── wrapt-1.14.1.tar.gz 370*61c4878aSAndroid Build Coastguard Worker └── yapf-0.31.0-py2.py3-none-any.whl 371*61c4878aSAndroid Build Coastguard Worker 372*61c4878aSAndroid Build Coastguard WorkerNote the above output has both Python wheel ``.whl`` and source distribution 373*61c4878aSAndroid Build Coastguard Worker``.tar.gz`` files. The ``.whl`` may contain Python packages with precompiled C 374*61c4878aSAndroid Build Coastguard Workerextensions. This is denoted by this part of the filename: 375*61c4878aSAndroid Build Coastguard Worker``cp311-cp311-manylinux_2_17_x86_64.whl``. These binary packages are selected by 376*61c4878aSAndroid Build Coastguard Workerthe ``pip download`` command based on the host machine python version, OS, and 377*61c4878aSAndroid Build Coastguard WorkerCPU architecture. 378*61c4878aSAndroid Build Coastguard Worker 379*61c4878aSAndroid Build Coastguard Worker.. warning:: 380*61c4878aSAndroid Build Coastguard Worker If you need to cache Python packages for multiple platforms the 381*61c4878aSAndroid Build Coastguard Worker ``.vendor_wheels`` target will need to be run for each combination of Python 382*61c4878aSAndroid Build Coastguard Worker version, host operating system and architecture. For example, look at `the 383*61c4878aSAndroid Build Coastguard Worker files available for numpy <https://pypi.org/project/cffi/#files>`_. Some 384*61c4878aSAndroid Build Coastguard Worker combinations are: 385*61c4878aSAndroid Build Coastguard Worker 386*61c4878aSAndroid Build Coastguard Worker - cp311, manylinux_2_17_x86_64 387*61c4878aSAndroid Build Coastguard Worker - cp311, manylinux2014_x86_64 388*61c4878aSAndroid Build Coastguard Worker - cp311, macosx_11_0_arm64 389*61c4878aSAndroid Build Coastguard Worker - cp311, macosx_10_9_x86_64 390*61c4878aSAndroid Build Coastguard Worker - cp311, win_amd64 391*61c4878aSAndroid Build Coastguard Worker - cp311, win32 392*61c4878aSAndroid Build Coastguard Worker 393*61c4878aSAndroid Build Coastguard Worker Plus all of the above duplicated for Python 3.10 and 3.9 (``cp310`` and 394*61c4878aSAndroid Build Coastguard Worker ``cp39``). 395*61c4878aSAndroid Build Coastguard Worker 396*61c4878aSAndroid Build Coastguard Worker The output of multiple ``.vendor_wheels`` runs on different host systems can 397*61c4878aSAndroid Build Coastguard Worker all be merged into the same output directory. 398*61c4878aSAndroid Build Coastguard Worker 399*61c4878aSAndroid Build Coastguard Worker``.vendor_wheels`` can attempt to download binary packages for multiple 400*61c4878aSAndroid Build Coastguard Workerplatforms all at once by setting a GN arg: 401*61c4878aSAndroid Build Coastguard Worker 402*61c4878aSAndroid Build Coastguard Worker.. code-block:: 403*61c4878aSAndroid Build Coastguard Worker 404*61c4878aSAndroid Build Coastguard Worker pw_build_PYTHON_PIP_DOWNLOAD_ALL_PLATFORMS = true 405*61c4878aSAndroid Build Coastguard Worker 406*61c4878aSAndroid Build Coastguard WorkerThis will invoke `pip download 407*61c4878aSAndroid Build Coastguard Worker<https://pip.pypa.io/en/stable/cli/pip_download/>`_ for each combination of 408*61c4878aSAndroid Build Coastguard Workerplatform, architecture and Python version. This can take a significant amount of 409*61c4878aSAndroid Build Coastguard Workertime to complete. The current set of combinations is shown below: 410*61c4878aSAndroid Build Coastguard Worker 411*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/py/pw_build/generate_python_wheel_cache.py 412*61c4878aSAndroid Build Coastguard Worker :start-after: [wheel-platform-args] 413*61c4878aSAndroid Build Coastguard Worker :end-before: [wheel-platform-args] 414*61c4878aSAndroid Build Coastguard Worker 415*61c4878aSAndroid Build Coastguard Worker.. warning:: 416*61c4878aSAndroid Build Coastguard Worker The set of Python packages that will be downloaded is determined by the 417*61c4878aSAndroid Build Coastguard Worker ``compiled_requirements.txt`` file. This file can only be generated for the 418*61c4878aSAndroid Build Coastguard Worker current host OS and Python version. `pip-tools 419*61c4878aSAndroid Build Coastguard Worker <https://pypi.org/project/pip-tools>`_ does not expand requirements for 420*61c4878aSAndroid Build Coastguard Worker `platform specific dependencies 421*61c4878aSAndroid Build Coastguard Worker <https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#platform-specific-dependencies>`_. For 422*61c4878aSAndroid Build Coastguard Worker example ipython defines these two requirements: 423*61c4878aSAndroid Build Coastguard Worker 424*61c4878aSAndroid Build Coastguard Worker .. code-block:: 425*61c4878aSAndroid Build Coastguard Worker 426*61c4878aSAndroid Build Coastguard Worker appnope; sys_platform == "darwin" 427*61c4878aSAndroid Build Coastguard Worker colorama; sys_platform == "win32" 428*61c4878aSAndroid Build Coastguard Worker 429*61c4878aSAndroid Build Coastguard Worker If pip-tools is run on Linux then the above packages will not appear in 430*61c4878aSAndroid Build Coastguard Worker ``compiled_requirements.txt`` and not downloaded by the ``.vendor_wheels`` 431*61c4878aSAndroid Build Coastguard Worker target. 432*61c4878aSAndroid Build Coastguard Worker 433*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-installing-offline: 434*61c4878aSAndroid Build Coastguard Worker 435*61c4878aSAndroid Build Coastguard WorkerInstalling Offline 436*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^ 437*61c4878aSAndroid Build Coastguard WorkerOnce the vendor wheel output is saved to a directory in your project you can use 438*61c4878aSAndroid Build Coastguard Workerthis as the default pip install location in two different ways. 439*61c4878aSAndroid Build Coastguard Worker 440*61c4878aSAndroid Build Coastguard WorkerGN Args 441*61c4878aSAndroid Build Coastguard Worker....... 442*61c4878aSAndroid Build Coastguard WorkerSetting these args in the ``//.gn`` file will add the relevant pip command line 443*61c4878aSAndroid Build Coastguard Workerargs to perform offline installations. 444*61c4878aSAndroid Build Coastguard Worker 445*61c4878aSAndroid Build Coastguard Worker.. code-block:: 446*61c4878aSAndroid Build Coastguard Worker 447*61c4878aSAndroid Build Coastguard Worker # Adds --no-index forcing pip to not reach out to the internet (pypi.org) to 448*61c4878aSAndroid Build Coastguard Worker # download packages. Using this option requires setting 449*61c4878aSAndroid Build Coastguard Worker # pw_build_PYTHON_PIP_INSTALL_FIND_LINKS as well. 450*61c4878aSAndroid Build Coastguard Worker pw_build_PYTHON_PIP_INSTALL_OFFLINE = true 451*61c4878aSAndroid Build Coastguard Worker 452*61c4878aSAndroid Build Coastguard Worker # List of paths to folders containing Python wheels (*.whl) or source tar 453*61c4878aSAndroid Build Coastguard Worker # files (*.tar.gz). Pip will check each of these directories when looking for 454*61c4878aSAndroid Build Coastguard Worker # potential install candidates. 455*61c4878aSAndroid Build Coastguard Worker pw_build_PYTHON_PIP_INSTALL_FIND_LINKS = [ 456*61c4878aSAndroid Build Coastguard Worker "//environment/cipd/packages/python_packages/universal", 457*61c4878aSAndroid Build Coastguard Worker "//environment/cipd/packages/python_packages/linux/cp311", 458*61c4878aSAndroid Build Coastguard Worker ] 459*61c4878aSAndroid Build Coastguard Worker 460*61c4878aSAndroid Build Coastguard Worker # Optional: Adds '--no-cache-dir' forcing pip to ignore any previously cached 461*61c4878aSAndroid Build Coastguard Worker # Python packages. On most systems this is located in ~/.cache/pip/ 462*61c4878aSAndroid Build Coastguard Worker pw_build_PYTHON_PIP_INSTALL_DISABLE_CACHE = false 463*61c4878aSAndroid Build Coastguard Worker 464*61c4878aSAndroid Build Coastguard WorkerUsing a ``.pip.conf`` File 465*61c4878aSAndroid Build Coastguard Worker.......................... 466*61c4878aSAndroid Build Coastguard Worker1. Create a ``//pip.conf`` file containing: 467*61c4878aSAndroid Build Coastguard Worker 468*61c4878aSAndroid Build Coastguard Worker .. code-block:: 469*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file;1em` //pip.conf 470*61c4878aSAndroid Build Coastguard Worker :name: pip-conf-file 471*61c4878aSAndroid Build Coastguard Worker 472*61c4878aSAndroid Build Coastguard Worker [global] 473*61c4878aSAndroid Build Coastguard Worker # Disable searching pypi.org for packages 474*61c4878aSAndroid Build Coastguard Worker no-index = True 475*61c4878aSAndroid Build Coastguard Worker # Find packages in these directories: 476*61c4878aSAndroid Build Coastguard Worker find-links = 477*61c4878aSAndroid Build Coastguard Worker file://third_party/python_packages/universal 478*61c4878aSAndroid Build Coastguard Worker file://third_party/python_packages/linux/cp311 479*61c4878aSAndroid Build Coastguard Worker 480*61c4878aSAndroid Build Coastguard Worker This tells pip to not search pypi.org for packages and only look in 481*61c4878aSAndroid Build Coastguard Worker ``third_party/python_packages/universal`` and 482*61c4878aSAndroid Build Coastguard Worker ``third_party/python_packages/linux/cp311``. These paths can be absolute or 483*61c4878aSAndroid Build Coastguard Worker are relative to the ``pip.conf`` file. 484*61c4878aSAndroid Build Coastguard Worker 485*61c4878aSAndroid Build Coastguard Worker2. In the project ``bootstrap.sh`` set ``PIP_CONFIG_FILE`` to the location of 486*61c4878aSAndroid Build Coastguard Worker this file. 487*61c4878aSAndroid Build Coastguard Worker 488*61c4878aSAndroid Build Coastguard Worker .. code-block:: bash 489*61c4878aSAndroid Build Coastguard Worker 490*61c4878aSAndroid Build Coastguard Worker export PIP_CONFIG_FILE="${PW_PROJECT_ROOT}/pip.conf" 491*61c4878aSAndroid Build Coastguard Worker 492*61c4878aSAndroid Build Coastguard Worker With that environment var set all invocations of pip will apply the config file 493*61c4878aSAndroid Build Coastguard Worker settings above. 494*61c4878aSAndroid Build Coastguard Worker 495*61c4878aSAndroid Build Coastguard Worker.. seealso:: 496*61c4878aSAndroid Build Coastguard Worker The ``pip`` `documentation on Configuration 497*61c4878aSAndroid Build Coastguard Worker <https://pip.pypa.io/en/stable/topics/configuration/>`_. 498*61c4878aSAndroid Build Coastguard Worker 499*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-python-gn-structure: 500*61c4878aSAndroid Build Coastguard Worker 501*61c4878aSAndroid Build Coastguard WorkerGN File Structure for Python Code 502*61c4878aSAndroid Build Coastguard Worker================================= 503*61c4878aSAndroid Build Coastguard WorkerHere is a full example of what is required to build Python packages using 504*61c4878aSAndroid Build Coastguard WorkerPigweed's GN build system. A brief file hierarchy is shown here with file 505*61c4878aSAndroid Build Coastguard Workercontent following. See also :ref:`docs-python-build-structure` below for details 506*61c4878aSAndroid Build Coastguard Workeron the structure of Python packages. 507*61c4878aSAndroid Build Coastguard Worker 508*61c4878aSAndroid Build Coastguard Worker.. code-block:: 509*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file-directory;1em` Top level GN file hierarchy 510*61c4878aSAndroid Build Coastguard Worker :name: gn-python-file-tree 511*61c4878aSAndroid Build Coastguard Worker 512*61c4878aSAndroid Build Coastguard Worker project_root/ 513*61c4878aSAndroid Build Coastguard Worker ├── .gn 514*61c4878aSAndroid Build Coastguard Worker ├── BUILDCONFIG.gn 515*61c4878aSAndroid Build Coastguard Worker ├── build_overrides/ 516*61c4878aSAndroid Build Coastguard Worker │ └── pigweed.gni 517*61c4878aSAndroid Build Coastguard Worker ├── BUILD.gn 518*61c4878aSAndroid Build Coastguard Worker │ 519*61c4878aSAndroid Build Coastguard Worker ├── python_package1/ 520*61c4878aSAndroid Build Coastguard Worker │ ├── BUILD.gn 521*61c4878aSAndroid Build Coastguard Worker │ ├── setup.cfg 522*61c4878aSAndroid Build Coastguard Worker │ ├── pyproject.toml 523*61c4878aSAndroid Build Coastguard Worker │ │ 524*61c4878aSAndroid Build Coastguard Worker │ ├── package_name/ 525*61c4878aSAndroid Build Coastguard Worker │ │ ├── module_a.py 526*61c4878aSAndroid Build Coastguard Worker │ │ ├── module_b.py 527*61c4878aSAndroid Build Coastguard Worker │ │ ├── py.typed 528*61c4878aSAndroid Build Coastguard Worker │ │ └── nested_package/ 529*61c4878aSAndroid Build Coastguard Worker │ │ ├── py.typed 530*61c4878aSAndroid Build Coastguard Worker │ │ └── module_c.py 531*61c4878aSAndroid Build Coastguard Worker │ │ 532*61c4878aSAndroid Build Coastguard Worker │ ├── module_a_test.py 533*61c4878aSAndroid Build Coastguard Worker │ └── module_c_test.py 534*61c4878aSAndroid Build Coastguard Worker │ 535*61c4878aSAndroid Build Coastguard Worker ├── third_party/ 536*61c4878aSAndroid Build Coastguard Worker │ └── pigweed/ 537*61c4878aSAndroid Build Coastguard Worker │ 538*61c4878aSAndroid Build Coastguard Worker └── ... 539*61c4878aSAndroid Build Coastguard Worker 540*61c4878aSAndroid Build Coastguard Worker- :octicon:`file-directory;1em` project_root/ 541*61c4878aSAndroid Build Coastguard Worker 542*61c4878aSAndroid Build Coastguard Worker - :octicon:`file;1em` .gn 543*61c4878aSAndroid Build Coastguard Worker 544*61c4878aSAndroid Build Coastguard Worker .. code-block:: 545*61c4878aSAndroid Build Coastguard Worker 546*61c4878aSAndroid Build Coastguard Worker buildconfig = "//BUILDCONFIG.gn" 547*61c4878aSAndroid Build Coastguard Worker import("//build_overrides/pigweed.gni") 548*61c4878aSAndroid Build Coastguard Worker 549*61c4878aSAndroid Build Coastguard Worker default_args = { 550*61c4878aSAndroid Build Coastguard Worker pw_build_PIP_CONSTRAINTS = [ 551*61c4878aSAndroid Build Coastguard Worker # Inherit Pigweed Python constraints 552*61c4878aSAndroid Build Coastguard Worker "$dir_pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list", 553*61c4878aSAndroid Build Coastguard Worker 554*61c4878aSAndroid Build Coastguard Worker # Project specific constraints file 555*61c4878aSAndroid Build Coastguard Worker "//tools/constraint.txt", 556*61c4878aSAndroid Build Coastguard Worker ] 557*61c4878aSAndroid Build Coastguard Worker 558*61c4878aSAndroid Build Coastguard Worker pw_build_PIP_REQUIREMENTS = [ 559*61c4878aSAndroid Build Coastguard Worker # Project specific requirements 560*61c4878aSAndroid Build Coastguard Worker "//tools/requirements.txt", 561*61c4878aSAndroid Build Coastguard Worker ] 562*61c4878aSAndroid Build Coastguard Worker 563*61c4878aSAndroid Build Coastguard Worker # Default gn build virtualenv target. 564*61c4878aSAndroid Build Coastguard Worker pw_build_PYTHON_BUILD_VENV = "//:project_build_venv" 565*61c4878aSAndroid Build Coastguard Worker } 566*61c4878aSAndroid Build Coastguard Worker 567*61c4878aSAndroid Build Coastguard Worker .. tip:: 568*61c4878aSAndroid Build Coastguard Worker 569*61c4878aSAndroid Build Coastguard Worker There are some additional gn args to control how pip installations are 570*61c4878aSAndroid Build Coastguard Worker performed during the build. 571*61c4878aSAndroid Build Coastguard Worker 572*61c4878aSAndroid Build Coastguard Worker .. literalinclude:: pw_build/python_gn_args.gni 573*61c4878aSAndroid Build Coastguard Worker :start-after: [default-pip-gn-args] 574*61c4878aSAndroid Build Coastguard Worker :end-before: [default-pip-gn-args] 575*61c4878aSAndroid Build Coastguard Worker 576*61c4878aSAndroid Build Coastguard Worker - :octicon:`file;1em` BUILDCONFIG.gn 577*61c4878aSAndroid Build Coastguard Worker 578*61c4878aSAndroid Build Coastguard Worker .. code-block:: 579*61c4878aSAndroid Build Coastguard Worker 580*61c4878aSAndroid Build Coastguard Worker _pigweed_directory = { 581*61c4878aSAndroid Build Coastguard Worker import("//build_overrides/pigweed.gni") 582*61c4878aSAndroid Build Coastguard Worker } 583*61c4878aSAndroid Build Coastguard Worker 584*61c4878aSAndroid Build Coastguard Worker set_default_toolchain("${_pigweed_directory.dir_pw_toolchain}/default") 585*61c4878aSAndroid Build Coastguard Worker 586*61c4878aSAndroid Build Coastguard Worker - :octicon:`file-directory;1em` build_overrides / :octicon:`file;1em` pigweed.gni 587*61c4878aSAndroid Build Coastguard Worker 588*61c4878aSAndroid Build Coastguard Worker .. code-block:: 589*61c4878aSAndroid Build Coastguard Worker 590*61c4878aSAndroid Build Coastguard Worker declare_args() { 591*61c4878aSAndroid Build Coastguard Worker # Location of the Pigweed repository. 592*61c4878aSAndroid Build Coastguard Worker dir_pigweed = "//third_party/pigweed/" 593*61c4878aSAndroid Build Coastguard Worker } 594*61c4878aSAndroid Build Coastguard Worker 595*61c4878aSAndroid Build Coastguard Worker # Upstream Pigweed modules. 596*61c4878aSAndroid Build Coastguard Worker import("$dir_pigweed/modules.gni") 597*61c4878aSAndroid Build Coastguard Worker 598*61c4878aSAndroid Build Coastguard Worker - :octicon:`file;1em` BUILD.gn 599*61c4878aSAndroid Build Coastguard Worker 600*61c4878aSAndroid Build Coastguard Worker .. code-block:: 601*61c4878aSAndroid Build Coastguard Worker 602*61c4878aSAndroid Build Coastguard Worker import("//build_overrides/pigweed.gni") 603*61c4878aSAndroid Build Coastguard Worker 604*61c4878aSAndroid Build Coastguard Worker import("$dir_pw_build/python.gni") 605*61c4878aSAndroid Build Coastguard Worker import("$dir_pw_build/python_dist.gni") 606*61c4878aSAndroid Build Coastguard Worker import("$dir_pw_build/python_venv.gni") 607*61c4878aSAndroid Build Coastguard Worker import("$dir_pw_unit_test/test.gni") 608*61c4878aSAndroid Build Coastguard Worker 609*61c4878aSAndroid Build Coastguard Worker # Lists all the targets build by default with e.g. `ninja -C out`. 610*61c4878aSAndroid Build Coastguard Worker group("default") { 611*61c4878aSAndroid Build Coastguard Worker deps = [ 612*61c4878aSAndroid Build Coastguard Worker ":python.lint", 613*61c4878aSAndroid Build Coastguard Worker ":python.tests", 614*61c4878aSAndroid Build Coastguard Worker ] 615*61c4878aSAndroid Build Coastguard Worker } 616*61c4878aSAndroid Build Coastguard Worker 617*61c4878aSAndroid Build Coastguard Worker # This group is built during bootstrap to setup the interactive Python 618*61c4878aSAndroid Build Coastguard Worker # environment. 619*61c4878aSAndroid Build Coastguard Worker pw_python_group("python") { 620*61c4878aSAndroid Build Coastguard Worker python_deps = [ 621*61c4878aSAndroid Build Coastguard Worker # Generate and pip install _all_python_packages 622*61c4878aSAndroid Build Coastguard Worker ":pip_install_project_tools", 623*61c4878aSAndroid Build Coastguard Worker ] 624*61c4878aSAndroid Build Coastguard Worker } 625*61c4878aSAndroid Build Coastguard Worker 626*61c4878aSAndroid Build Coastguard Worker # In-tree Python packages 627*61c4878aSAndroid Build Coastguard Worker _project_python_packages = [ 628*61c4878aSAndroid Build Coastguard Worker "//python_package1", 629*61c4878aSAndroid Build Coastguard Worker ] 630*61c4878aSAndroid Build Coastguard Worker 631*61c4878aSAndroid Build Coastguard Worker # Pigweed Python packages to include 632*61c4878aSAndroid Build Coastguard Worker _pigweed_python_packages = [ 633*61c4878aSAndroid Build Coastguard Worker "$dir_pw_env_setup:core_pigweed_python_packages", 634*61c4878aSAndroid Build Coastguard Worker "$dir_pigweed/targets/lm3s6965evb_qemu/py", 635*61c4878aSAndroid Build Coastguard Worker "$dir_pigweed/targets/stm32f429i_disc1/py", 636*61c4878aSAndroid Build Coastguard Worker ] 637*61c4878aSAndroid Build Coastguard Worker 638*61c4878aSAndroid Build Coastguard Worker _all_python_packages = 639*61c4878aSAndroid Build Coastguard Worker _project_python_packages + _pigweed_python_packages 640*61c4878aSAndroid Build Coastguard Worker 641*61c4878aSAndroid Build Coastguard Worker # The default venv for Python actions in GN 642*61c4878aSAndroid Build Coastguard Worker # Set this gn arg in a declare_args block in this file 'BUILD.gn' or in '.gn' to 643*61c4878aSAndroid Build Coastguard Worker # use this venv. 644*61c4878aSAndroid Build Coastguard Worker # 645*61c4878aSAndroid Build Coastguard Worker # pw_build_PYTHON_BUILD_VENV = "//:project_build_venv" 646*61c4878aSAndroid Build Coastguard Worker # 647*61c4878aSAndroid Build Coastguard Worker pw_python_venv("project_build_venv") { 648*61c4878aSAndroid Build Coastguard Worker path = "$root_build_dir/python-venv" 649*61c4878aSAndroid Build Coastguard Worker constraints = pw_build_PIP_CONSTRAINTS 650*61c4878aSAndroid Build Coastguard Worker requirements = pw_build_PIP_REQUIREMENTS 651*61c4878aSAndroid Build Coastguard Worker 652*61c4878aSAndroid Build Coastguard Worker # Ensure all third party Python dependencies are installed into this venv. 653*61c4878aSAndroid Build Coastguard Worker # This works by checking the setup.cfg files for all packages listed here and 654*61c4878aSAndroid Build Coastguard Worker # installing the packages listed in the [options].install_requires field. 655*61c4878aSAndroid Build Coastguard Worker source_packages = _all_python_packages 656*61c4878aSAndroid Build Coastguard Worker } 657*61c4878aSAndroid Build Coastguard Worker 658*61c4878aSAndroid Build Coastguard Worker # This template collects all python packages and their dependencies into a 659*61c4878aSAndroid Build Coastguard Worker # single super Python package for installation into the bootstrapped virtual 660*61c4878aSAndroid Build Coastguard Worker # environment. 661*61c4878aSAndroid Build Coastguard Worker pw_python_distribution("generate_project_python_distribution") { 662*61c4878aSAndroid Build Coastguard Worker packages = _all_python_packages 663*61c4878aSAndroid Build Coastguard Worker generate_setup_cfg = { 664*61c4878aSAndroid Build Coastguard Worker name = "project-tools" 665*61c4878aSAndroid Build Coastguard Worker version = "0.0.1" 666*61c4878aSAndroid Build Coastguard Worker append_date_to_version = true 667*61c4878aSAndroid Build Coastguard Worker include_default_pyproject_file = true 668*61c4878aSAndroid Build Coastguard Worker } 669*61c4878aSAndroid Build Coastguard Worker } 670*61c4878aSAndroid Build Coastguard Worker 671*61c4878aSAndroid Build Coastguard Worker # Install the project-tools super Python package into the bootstrapped 672*61c4878aSAndroid Build Coastguard Worker # Python venv. 673*61c4878aSAndroid Build Coastguard Worker pw_python_pip_install("pip_install_project_tools") { 674*61c4878aSAndroid Build Coastguard Worker packages = [ ":generate_project_python_distribution" ] 675*61c4878aSAndroid Build Coastguard Worker } 676*61c4878aSAndroid Build Coastguard Worker 677*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-structure: 678*61c4878aSAndroid Build Coastguard Worker 679*61c4878aSAndroid Build Coastguard WorkerPigweed Module Structure for Python Code 680*61c4878aSAndroid Build Coastguard Worker======================================== 681*61c4878aSAndroid Build Coastguard WorkerPigweed Python code is structured into standard Python packages. This makes it 682*61c4878aSAndroid Build Coastguard Workersimple to package and distribute Pigweed Python packages with common Python 683*61c4878aSAndroid Build Coastguard Workertools. 684*61c4878aSAndroid Build Coastguard Worker 685*61c4878aSAndroid Build Coastguard WorkerLike all Pigweed source code, Python packages are organized into Pigweed 686*61c4878aSAndroid Build Coastguard Workermodules. A module's Python package is nested under a ``py/`` directory (see 687*61c4878aSAndroid Build Coastguard Worker:ref:`Pigweed Module Stucture <docs-module-structure>`). 688*61c4878aSAndroid Build Coastguard Worker 689*61c4878aSAndroid Build Coastguard Worker.. code-block:: 690*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file-directory;1em` Example layout of a Pigweed Python package. 691*61c4878aSAndroid Build Coastguard Worker :name: python-file-tree 692*61c4878aSAndroid Build Coastguard Worker 693*61c4878aSAndroid Build Coastguard Worker module_name/ 694*61c4878aSAndroid Build Coastguard Worker ├── py/ 695*61c4878aSAndroid Build Coastguard Worker │ ├── BUILD.gn 696*61c4878aSAndroid Build Coastguard Worker │ ├── setup.cfg 697*61c4878aSAndroid Build Coastguard Worker │ ├── pyproject.toml 698*61c4878aSAndroid Build Coastguard Worker │ ├── package_name/ 699*61c4878aSAndroid Build Coastguard Worker │ │ ├── module_a.py 700*61c4878aSAndroid Build Coastguard Worker │ │ ├── module_b.py 701*61c4878aSAndroid Build Coastguard Worker │ │ ├── py.typed 702*61c4878aSAndroid Build Coastguard Worker │ │ └── nested_package/ 703*61c4878aSAndroid Build Coastguard Worker │ │ ├── py.typed 704*61c4878aSAndroid Build Coastguard Worker │ │ └── module_c.py 705*61c4878aSAndroid Build Coastguard Worker │ ├── module_a_test.py 706*61c4878aSAndroid Build Coastguard Worker │ └── module_c_test.py 707*61c4878aSAndroid Build Coastguard Worker └── ... 708*61c4878aSAndroid Build Coastguard Worker 709*61c4878aSAndroid Build Coastguard WorkerThe ``BUILD.gn`` declares this package in GN. For upstream Pigweed, a presubmit 710*61c4878aSAndroid Build Coastguard Workercheck in ensures that all Python files are listed in a ``BUILD.gn``. 711*61c4878aSAndroid Build Coastguard Worker 712*61c4878aSAndroid Build Coastguard WorkerPigweed prefers to define Python packages using ``setup.cfg`` files. In the 713*61c4878aSAndroid Build Coastguard Workerabove file tree the ``pyproject.toml`` file is only a stub with the following 714*61c4878aSAndroid Build Coastguard Workercontent: 715*61c4878aSAndroid Build Coastguard Worker 716*61c4878aSAndroid Build Coastguard Worker.. code-block:: 717*61c4878aSAndroid Build Coastguard Worker :caption: :octicon:`file;1em` pyproject.toml 718*61c4878aSAndroid Build Coastguard Worker :name: pyproject-toml-stub 719*61c4878aSAndroid Build Coastguard Worker 720*61c4878aSAndroid Build Coastguard Worker [build-system] 721*61c4878aSAndroid Build Coastguard Worker requires = ['setuptools', 'wheel'] 722*61c4878aSAndroid Build Coastguard Worker build-backend = 'setuptools.build_meta' 723*61c4878aSAndroid Build Coastguard Worker 724*61c4878aSAndroid Build Coastguard WorkerEach ``pyproject.toml`` file is required to specify which build system should be 725*61c4878aSAndroid Build Coastguard Workerused for the given Python package. In Pigweed's case it always specifies using 726*61c4878aSAndroid Build Coastguard Workersetuptools. 727*61c4878aSAndroid Build Coastguard Worker 728*61c4878aSAndroid Build Coastguard Worker.. seealso:: 729*61c4878aSAndroid Build Coastguard Worker 730*61c4878aSAndroid Build Coastguard Worker - ``setup.cfg`` examples at `Configuring setup() using setup.cfg files`_ 731*61c4878aSAndroid Build Coastguard Worker - ``pyproject.toml`` background at `Build System Support - How to use it?`_ 732*61c4878aSAndroid Build Coastguard Worker 733*61c4878aSAndroid Build Coastguard Worker.. _module-pw_build-python-target: 734*61c4878aSAndroid Build Coastguard Worker 735*61c4878aSAndroid Build Coastguard Workerpw_python_package targets 736*61c4878aSAndroid Build Coastguard Worker------------------------- 737*61c4878aSAndroid Build Coastguard WorkerThe key abstraction in the Python build is the ``pw_python_package``. 738*61c4878aSAndroid Build Coastguard WorkerA ``pw_python_package`` represents a Python package as a GN target. It is 739*61c4878aSAndroid Build Coastguard Workerimplemented with a GN template. The ``pw_python_package`` template is documented 740*61c4878aSAndroid Build Coastguard Workerin :ref:`module-pw_build-python`. 741*61c4878aSAndroid Build Coastguard Worker 742*61c4878aSAndroid Build Coastguard WorkerThe key attributes of a ``pw_python_package`` are 743*61c4878aSAndroid Build Coastguard Worker 744*61c4878aSAndroid Build Coastguard Worker- a ``setup.cfg`` and ``pyproject.toml`` file, 745*61c4878aSAndroid Build Coastguard Worker- source files, 746*61c4878aSAndroid Build Coastguard Worker- test files, 747*61c4878aSAndroid Build Coastguard Worker- dependencies on other ``pw_python_package`` targets. 748*61c4878aSAndroid Build Coastguard Worker 749*61c4878aSAndroid Build Coastguard WorkerA ``pw_python_package`` target is composed of several GN subtargets. Each 750*61c4878aSAndroid Build Coastguard Workersubtarget represents different functionality in the Python build. 751*61c4878aSAndroid Build Coastguard Worker 752*61c4878aSAndroid Build Coastguard Worker- ``<name>`` - Represents the Python files in the build, but does not take any 753*61c4878aSAndroid Build Coastguard Worker actions. All subtargets depend on this target. 754*61c4878aSAndroid Build Coastguard Worker- ``<name>.tests`` - Runs all tests for this package. 755*61c4878aSAndroid Build Coastguard Worker 756*61c4878aSAndroid Build Coastguard Worker - ``<name>.tests.<test_file>`` - Runs the specified test. 757*61c4878aSAndroid Build Coastguard Worker 758*61c4878aSAndroid Build Coastguard Worker- ``<name>.lint`` - Runs static analysis tools on the Python code. This is a 759*61c4878aSAndroid Build Coastguard Worker group of three subtargets: 760*61c4878aSAndroid Build Coastguard Worker 761*61c4878aSAndroid Build Coastguard Worker - ``<name>.lint.mypy`` - Runs Mypy on all Python files, if enabled. 762*61c4878aSAndroid Build Coastguard Worker - ``<name>.lint.pylint`` - Runs Pylint on all Python files, if enabled. 763*61c4878aSAndroid Build Coastguard Worker - ``<name>.lint.ruff`` - Runs ruff on all Python files, if enabled. 764*61c4878aSAndroid Build Coastguard Worker 765*61c4878aSAndroid Build Coastguard Worker- ``<name>.install`` - Installs the package in a Python virtual environment. 766*61c4878aSAndroid Build Coastguard Worker- ``<name>.wheel`` - Builds a Python wheel for this package. 767*61c4878aSAndroid Build Coastguard Worker 768*61c4878aSAndroid Build Coastguard WorkerTo avoid unnecessary duplication, all Python actions are executed in the default 769*61c4878aSAndroid Build Coastguard Workertoolchain, even if they are referred to from other toolchains. 770*61c4878aSAndroid Build Coastguard Worker 771*61c4878aSAndroid Build Coastguard WorkerTesting 772*61c4878aSAndroid Build Coastguard Worker^^^^^^^ 773*61c4878aSAndroid Build Coastguard WorkerTests for a Python package are listed in its ``pw_python_package`` target. 774*61c4878aSAndroid Build Coastguard WorkerAdding a new test is simple: write the test file and list it in its accompanying 775*61c4878aSAndroid Build Coastguard WorkerPython package. The build will run it when the test, the package, or one of its 776*61c4878aSAndroid Build Coastguard Workerdependencies is updated. 777*61c4878aSAndroid Build Coastguard Worker 778*61c4878aSAndroid Build Coastguard WorkerStatic analysis 779*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^ 780*61c4878aSAndroid Build Coastguard Worker``pw_python_package`` targets are preconfigured to run Pylint, Mypy and Ruff on 781*61c4878aSAndroid Build Coastguard Workertheir source and test files. Users may specify which ``pylintrc``, ``mypy_ini`` 782*61c4878aSAndroid Build Coastguard Workerand ``ruff_toml`` files to use on a per-package basis. The configuration files 783*61c4878aSAndroid Build Coastguard Workermay also be provided in the directory structure; the tools will locate them 784*61c4878aSAndroid Build Coastguard Workerusing their standard means. Like tests, static analysis is only run when files 785*61c4878aSAndroid Build Coastguard Workeror their dependencies change. 786*61c4878aSAndroid Build Coastguard Worker 787*61c4878aSAndroid Build Coastguard WorkerPackages may opt out of static analysis as necessary by setting 788*61c4878aSAndroid Build Coastguard Worker``static_analysis`` on the ``pw_python_package`` target. 789*61c4878aSAndroid Build Coastguard Worker 790*61c4878aSAndroid Build Coastguard WorkerThe default set of analysis tools to run can be set globally via a GN arg 791*61c4878aSAndroid Build Coastguard Worker``pw_build_PYTHON_STATIC_ANALYSIS_TOOLS``. By default this is set to include the 792*61c4878aSAndroid Build Coastguard Workerbelow tools: 793*61c4878aSAndroid Build Coastguard Worker 794*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/python.gni 795*61c4878aSAndroid Build Coastguard Worker :start-after: [python-static-analysis-tools] 796*61c4878aSAndroid Build Coastguard Worker :end-before: [python-static-analysis-tools] 797*61c4878aSAndroid Build Coastguard Worker 798*61c4878aSAndroid Build Coastguard WorkerIn addition to user specified ``mypy_ini`` files some arguments are always 799*61c4878aSAndroid Build Coastguard Workerpassed to ``mypy`` by default. They can be seen in this excerpt of 800*61c4878aSAndroid Build Coastguard Worker``//pw_build/python.gni`` below: 801*61c4878aSAndroid Build Coastguard Worker 802*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/python.gni 803*61c4878aSAndroid Build Coastguard Worker :start-after: [default-mypy-args] 804*61c4878aSAndroid Build Coastguard Worker :end-before: [default-mypy-args] 805*61c4878aSAndroid Build Coastguard Worker 806*61c4878aSAndroid Build Coastguard WorkerBuilding Python wheels 807*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^ 808*61c4878aSAndroid Build Coastguard Worker`Wheels <https://wheel.readthedocs.io/en/stable/>`_ are the standard format for 809*61c4878aSAndroid Build Coastguard Workerdistributing Python packages. The Pigweed Python build supports creating wheels 810*61c4878aSAndroid Build Coastguard Workerfor individual packages and groups of packages. Building the ``.wheel`` 811*61c4878aSAndroid Build Coastguard Workersubtarget creates a ``.whl`` file for the package using the PyPA's `build 812*61c4878aSAndroid Build Coastguard Worker<https://pypa-build.readthedocs.io/en/stable/>`_ tool. 813*61c4878aSAndroid Build Coastguard Worker 814*61c4878aSAndroid Build Coastguard WorkerThe ``.wheel`` subtarget of any ``pw_python_package`` or 815*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_distribution` records the location of the 816*61c4878aSAndroid Build Coastguard Workergenerated wheel with `GN metadata 817*61c4878aSAndroid Build Coastguard Worker<https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#var_metadata>`_. 818*61c4878aSAndroid Build Coastguard WorkerWheels for a Python package and its transitive dependencies can be collected 819*61c4878aSAndroid Build Coastguard Workerfrom the ``pw_python_package_wheels`` key. See 820*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-python-dist`. 821*61c4878aSAndroid Build Coastguard Worker 822*61c4878aSAndroid Build Coastguard WorkerProtocol buffers 823*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^ 824*61c4878aSAndroid Build Coastguard WorkerThe Pigweed GN build supports protocol buffers with the ``pw_proto_library`` 825*61c4878aSAndroid Build Coastguard Workertarget (see :ref:`module-pw_protobuf_compiler`). Python protobuf modules are 826*61c4878aSAndroid Build Coastguard Workergenerated as standalone Python packages by default. Protocol buffers may also be 827*61c4878aSAndroid Build Coastguard Workernested within existing Python packages. In this case, the Python package in the 828*61c4878aSAndroid Build Coastguard Workersource tree is incomplete; the final Python package, including protobufs, is 829*61c4878aSAndroid Build Coastguard Workergenerated in the output directory. 830*61c4878aSAndroid Build Coastguard Worker 831*61c4878aSAndroid Build Coastguard WorkerGenerating setup.cfg 832*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^ 833*61c4878aSAndroid Build Coastguard WorkerThe ``pw_python_package`` target in the ``BUILD.gn`` duplicates much of the 834*61c4878aSAndroid Build Coastguard Workerinformation in the ``setup.cfg`` file. In many cases, it would be possible to 835*61c4878aSAndroid Build Coastguard Workergenerate a ``setup.cfg`` file rather than including it in the source 836*61c4878aSAndroid Build Coastguard Workertree. However, removing the ``setup.cfg`` would preclude using a direct, 837*61c4878aSAndroid Build Coastguard Workereditable installation from the source tree. 838*61c4878aSAndroid Build Coastguard Worker 839*61c4878aSAndroid Build Coastguard WorkerPigweed packages containing protobufs are generated in full or in part. These 840*61c4878aSAndroid Build Coastguard Workerpackages may use generated setup files, since they are always packaged or 841*61c4878aSAndroid Build Coastguard Workerinstalled from the build output directory. 842*61c4878aSAndroid Build Coastguard Worker 843*61c4878aSAndroid Build Coastguard Worker 844*61c4878aSAndroid Build Coastguard WorkerRationale 845*61c4878aSAndroid Build Coastguard Worker========= 846*61c4878aSAndroid Build Coastguard Worker 847*61c4878aSAndroid Build Coastguard WorkerBackground 848*61c4878aSAndroid Build Coastguard Worker---------- 849*61c4878aSAndroid Build Coastguard WorkerDeveloping software involves much more than writing source code. Software needs 850*61c4878aSAndroid Build Coastguard Workerto be compiled, executed, tested, analyzed, packaged, and deployed. As projects 851*61c4878aSAndroid Build Coastguard Workergrow beyond a few files, these tasks become impractical to manage manually. 852*61c4878aSAndroid Build Coastguard WorkerBuild systems automate these auxiliary tasks of software development, making it 853*61c4878aSAndroid Build Coastguard Workerpossible to build larger, more complex systems quickly and robustly. 854*61c4878aSAndroid Build Coastguard Worker 855*61c4878aSAndroid Build Coastguard WorkerPython is an interpreted language, but it shares most build automation concerns 856*61c4878aSAndroid Build Coastguard Workerwith other languages. Pigweed uses Python extensively and must address these 857*61c4878aSAndroid Build Coastguard Workerneeds for itself and its users. 858*61c4878aSAndroid Build Coastguard Worker 859*61c4878aSAndroid Build Coastguard WorkerExisting solutions 860*61c4878aSAndroid Build Coastguard Worker------------------ 861*61c4878aSAndroid Build Coastguard WorkerThe Python programming langauge does not have an official build automation 862*61c4878aSAndroid Build Coastguard Workersystem. However, there are numerous Python-focused build automation tools with 863*61c4878aSAndroid Build Coastguard Workervarying degrees of adoption. See the `Python Wiki 864*61c4878aSAndroid Build Coastguard Worker<https://wiki.python.org/moin/ConfigurationAndBuildTools>`_ for examples. 865*61c4878aSAndroid Build Coastguard Worker 866*61c4878aSAndroid Build Coastguard WorkerA few Python tools have become defacto standards, including `setuptools 867*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/setuptools/>`_, `wheel 868*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/wheel/>`_, and `pip <https://pypi.org/project/pip/>`_. 869*61c4878aSAndroid Build Coastguard WorkerThese essential tools address key aspects of Python packaging and distribution, 870*61c4878aSAndroid Build Coastguard Workerbut are not intended for general build automation. Tools like `PyBuilder 871*61c4878aSAndroid Build Coastguard Worker<https://pybuilder.io/>`_ and `tox <https://tox.readthedocs.io/en/latest/>`_ 872*61c4878aSAndroid Build Coastguard Workerprovide more general build automation for Python. 873*61c4878aSAndroid Build Coastguard Worker 874*61c4878aSAndroid Build Coastguard WorkerThe `Bazel <http://bazel.build/>`_ build system has first class support for 875*61c4878aSAndroid Build Coastguard WorkerPython and other languages used by Pigweed, including protocol buffers. 876*61c4878aSAndroid Build Coastguard Worker 877*61c4878aSAndroid Build Coastguard WorkerChallenges 878*61c4878aSAndroid Build Coastguard Worker---------- 879*61c4878aSAndroid Build Coastguard WorkerPigweed's use of Python is different from many other projects. Pigweed is a 880*61c4878aSAndroid Build Coastguard Workermulti-language, modular project. It serves both as a library or middleware and 881*61c4878aSAndroid Build Coastguard Workeras a development environment. 882*61c4878aSAndroid Build Coastguard Worker 883*61c4878aSAndroid Build Coastguard WorkerThis section describes Python build automation challenges encountered by 884*61c4878aSAndroid Build Coastguard WorkerPigweed. 885*61c4878aSAndroid Build Coastguard Worker 886*61c4878aSAndroid Build Coastguard WorkerDependencies 887*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^ 888*61c4878aSAndroid Build Coastguard WorkerPigweed is organized into distinct modules. In Python, each module is a separate 889*61c4878aSAndroid Build Coastguard Workerpackage, potentially with dependencies on other local or `PyPI 890*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/>`_ packages. 891*61c4878aSAndroid Build Coastguard Worker 892*61c4878aSAndroid Build Coastguard WorkerThe basic Python packaging tools lack dependency tracking for local packages. 893*61c4878aSAndroid Build Coastguard WorkerFor example, a package's ``setup.cfg`` lists all of its dependencies, but 894*61c4878aSAndroid Build Coastguard Worker``pip`` is not aware of local packages until they are installed. Packages must 895*61c4878aSAndroid Build Coastguard Workerbe installed with their dependencies taken into account, in topological sorted 896*61c4878aSAndroid Build Coastguard Workerorder. 897*61c4878aSAndroid Build Coastguard Worker 898*61c4878aSAndroid Build Coastguard WorkerTo work around this, one could set up a private `PyPI server 899*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/pypiserver/>`_ instance, but this is too cumbersome 900*61c4878aSAndroid Build Coastguard Workerfor daily development and incompatible with editable package installation. 901*61c4878aSAndroid Build Coastguard Worker 902*61c4878aSAndroid Build Coastguard WorkerTesting 903*61c4878aSAndroid Build Coastguard Worker^^^^^^^ 904*61c4878aSAndroid Build Coastguard WorkerTests are crucial to having a healthy, maintainable codebase. While they take 905*61c4878aSAndroid Build Coastguard Workersome initial work to write, the time investment pays for itself many times over 906*61c4878aSAndroid Build Coastguard Workerby contributing to the long-term resilience of a codebase. Despite their 907*61c4878aSAndroid Build Coastguard Workerbenefit, developers don't always take the time to write tests. Any barriers to 908*61c4878aSAndroid Build Coastguard Workerwriting and running tests result in fewer tests and consequently more fragile, 909*61c4878aSAndroid Build Coastguard Workerbug-prone codebases. 910*61c4878aSAndroid Build Coastguard Worker 911*61c4878aSAndroid Build Coastguard WorkerThere are lots of great Python libraries for testing, such as 912*61c4878aSAndroid Build Coastguard Worker`unittest <https://docs.python.org/3/library/unittest.html>`_ and 913*61c4878aSAndroid Build Coastguard Worker`pytest <https://docs.pytest.org/en/stable/>`_. These tools make it easy to 914*61c4878aSAndroid Build Coastguard Workerwrite and execute individual Python tests, but are not well suited for managing 915*61c4878aSAndroid Build Coastguard Workersuites of interdependent tests in a large project. Writing a test with these 916*61c4878aSAndroid Build Coastguard Workerutilities does not automatically run them or keep running them as the codebase 917*61c4878aSAndroid Build Coastguard Workerchanges. 918*61c4878aSAndroid Build Coastguard Worker 919*61c4878aSAndroid Build Coastguard WorkerStatic analysis 920*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^ 921*61c4878aSAndroid Build Coastguard Worker 922*61c4878aSAndroid Build Coastguard Worker.. seealso:: 923*61c4878aSAndroid Build Coastguard Worker 924*61c4878aSAndroid Build Coastguard Worker :bdg-ref-primary-line:`docs-automated-analysis` for info on other static 925*61c4878aSAndroid Build Coastguard Worker analysis tools used in Pigweed. 926*61c4878aSAndroid Build Coastguard Worker 927*61c4878aSAndroid Build Coastguard WorkerVarious static analysis tools exist for Python. Two widely used, powerful tools 928*61c4878aSAndroid Build Coastguard Workerare `Pylint <https://www.pylint.org/>`_ and `Mypy <http://mypy-lang.org/>`_. 929*61c4878aSAndroid Build Coastguard WorkerUsing these tools improves code quality, as they catch bugs, encourage good 930*61c4878aSAndroid Build Coastguard Workerdesign practices, and enforce a consistent coding style. As with testing, 931*61c4878aSAndroid Build Coastguard Workerbarriers to running static analysis tools cause many developers to skip them. 932*61c4878aSAndroid Build Coastguard WorkerSome developers may not even be aware of these tools. 933*61c4878aSAndroid Build Coastguard Worker 934*61c4878aSAndroid Build Coastguard WorkerDeploying static analysis tools to a codebase like Pigweed has some challenges. 935*61c4878aSAndroid Build Coastguard WorkerMypy and Pylint are simple to run, but they are extremely slow. Ideally, these 936*61c4878aSAndroid Build Coastguard Workertools would be run constantly during development, but only on files that change. 937*61c4878aSAndroid Build Coastguard WorkerThese tools do not have built-in support for incremental runs or dependency 938*61c4878aSAndroid Build Coastguard Workertracking. 939*61c4878aSAndroid Build Coastguard Worker 940*61c4878aSAndroid Build Coastguard WorkerAnother challenge is configuration. Mypy and Pylint support using configuration 941*61c4878aSAndroid Build Coastguard Workerfiles to select which checks to run and how to apply them. Both tools only 942*61c4878aSAndroid Build Coastguard Workersupport using a single configuration file for an entire run, which poses a 943*61c4878aSAndroid Build Coastguard Workerchallenge to modular middleware systems where different parts of a project may 944*61c4878aSAndroid Build Coastguard Workerrequire different configurations. 945*61c4878aSAndroid Build Coastguard Worker 946*61c4878aSAndroid Build Coastguard WorkerProtocol buffers 947*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^ 948*61c4878aSAndroid Build Coastguard Worker`Protocol buffers <https://developers.google.com/protocol-buffers>`_ are an 949*61c4878aSAndroid Build Coastguard Workerefficient system for serializing structured data. They are widely used by Google 950*61c4878aSAndroid Build Coastguard Workerand other companies. 951*61c4878aSAndroid Build Coastguard Worker 952*61c4878aSAndroid Build Coastguard WorkerThe protobuf compiler ``protoc`` generates Python modules from ``.proto`` files. 953*61c4878aSAndroid Build Coastguard Worker``protoc`` strictly generates protobuf modules according to their directory 954*61c4878aSAndroid Build Coastguard Workerstructure. This works well in a monorepo, but poses a challenge to a middleware 955*61c4878aSAndroid Build Coastguard Workersystem like Pigweed. Generating protobufs by path also makes integrating 956*61c4878aSAndroid Build Coastguard Workerprotobufs with existing packages awkward. 957*61c4878aSAndroid Build Coastguard Worker 958*61c4878aSAndroid Build Coastguard WorkerRequirements 959*61c4878aSAndroid Build Coastguard Worker------------ 960*61c4878aSAndroid Build Coastguard WorkerPigweed aims to provide high quality software components and a fast, effective, 961*61c4878aSAndroid Build Coastguard Workerflexible development experience for its customers. Pigweed's high-level goals 962*61c4878aSAndroid Build Coastguard Workerand the `challenges`_ described above inform these requirements for the Pigweed 963*61c4878aSAndroid Build Coastguard WorkerPython build. 964*61c4878aSAndroid Build Coastguard Worker 965*61c4878aSAndroid Build Coastguard Worker- Integrate seamlessly with the other Pigweed build tools. 966*61c4878aSAndroid Build Coastguard Worker- Easy to use independently, even if primarily using a different build system. 967*61c4878aSAndroid Build Coastguard Worker- Support standard packaging and distribution with setuptools, wheel, and pip. 968*61c4878aSAndroid Build Coastguard Worker- Correctly manage interdependent local Python packages. 969*61c4878aSAndroid Build Coastguard Worker- Out-of-the-box support for writing and running tests. 970*61c4878aSAndroid Build Coastguard Worker- Preconfigured, trivial-to-run static analysis integration for Pylint and Mypy. 971*61c4878aSAndroid Build Coastguard Worker- Fast, dependency-aware incremental rebuilds and test execution, suitable for 972*61c4878aSAndroid Build Coastguard Worker use with :ref:`module-pw_watch`. 973*61c4878aSAndroid Build Coastguard Worker- Seamless protocol buffer support. 974*61c4878aSAndroid Build Coastguard Worker 975*61c4878aSAndroid Build Coastguard WorkerDesign Decision 976*61c4878aSAndroid Build Coastguard Worker--------------- 977*61c4878aSAndroid Build Coastguard WorkerExisting Python tools may be effective for Python codebases, but their utility 978*61c4878aSAndroid Build Coastguard Workeris more limited in a multi-language project like Pigweed. The cost of bringing 979*61c4878aSAndroid Build Coastguard Workerup and maintaining an additional build automation system for a single language 980*61c4878aSAndroid Build Coastguard Workeris high. 981*61c4878aSAndroid Build Coastguard Worker 982*61c4878aSAndroid Build Coastguard WorkerPigweed uses GN as its primary build system for all languages. While GN does not 983*61c4878aSAndroid Build Coastguard Workernatively support Python, adding support is straightforward with GN templates. 984*61c4878aSAndroid Build Coastguard Worker 985*61c4878aSAndroid Build Coastguard WorkerGN has strong multi-toolchain and multi-language capabilities. In GN, it is 986*61c4878aSAndroid Build Coastguard Workerstraightforward to share targets and artifacts between different languages. For 987*61c4878aSAndroid Build Coastguard Workerexample, C++, Go, and Python targets can depend on the same protobuf 988*61c4878aSAndroid Build Coastguard Workerdeclaration. When using GN for multiple languages, Ninja schedules build steps 989*61c4878aSAndroid Build Coastguard Workerfor all languages together, resulting in faster total build times. 990*61c4878aSAndroid Build Coastguard Worker 991*61c4878aSAndroid Build Coastguard WorkerNot all Pigweed users build with GN. Of Pigweed's three supported build systems, 992*61c4878aSAndroid Build Coastguard WorkerGN is the fastest, lightest weight, and easiest to run. It also has simple, 993*61c4878aSAndroid Build Coastguard Workerclean syntax. This makes it feasible to use GN only for Python while building 994*61c4878aSAndroid Build Coastguard Workerprimarily with a different system. 995*61c4878aSAndroid Build Coastguard Worker 996*61c4878aSAndroid Build Coastguard WorkerGiven these considerations, GN is an ideal choice for Pigweed's Python build. 997*61c4878aSAndroid Build Coastguard Worker 998*61c4878aSAndroid Build Coastguard Worker.. _Configuring setup() using setup.cfg files: https://ipython.readthedocs.io/en/stable/interactive/reference.html#embedding 999*61c4878aSAndroid Build Coastguard Worker.. _Build System Support - How to use it?: https://setuptools.readthedocs.io/en/latest/build_meta.html?highlight=pyproject.toml#how-to-use-it 1000