| # PC/layout script |
| |
| This document provides an overview of the `PC/layout` script, which is used to |
| convert from a build tree to a ready-to-run directory of files. It's the |
| equivalent of `make install` when using the Makefile. We use it for official |
| binary releases, but it also supports a lot of configuration and can be used for |
| whatever your custom scenario should look like. |
| |
| The script never builds anything. It reads files from an existing build tree |
| (`-b`) and the source tree (`-s`), then copies or zips them into a layout. It |
| does not require the Python being laid out to be runnable, and it can target a |
| different version from the one running the script (see [Build source |
| options](#build-source-options)). |
| |
| ## Quick start |
| |
| Run the script as a directory with any Python 3 interpreter. From the |
| repository root: |
| |
| ``` |
| python PC/layout --help |
| ``` |
| |
| A useful invocation names an output directory and a preset. The build |
| directory is inferred from the running interpreter (`-b` overrides it), but a |
| `--preset-<name>` (or explicit `--include-<name>` options) is required; |
| otherwise the result is a bare, minimal layout that is rarely useful. |
| |
| ``` |
| python PC/layout --copy dist --preset-default |
| ``` |
| |
| ### Output options |
| |
| The script produces one or both of the following outputs. At least one is |
| required for the run to do anything useful. |
| |
| * `--copy <dir>` copies the layout into a directory. |
| * `--zip <file>` writes the layout into a ZIP file. |
| |
| Additional output-related options: |
| |
| * `--catalog <file>` writes a `.cdf` catalog definition for the non-binary |
| files, used later to produce a signed catalog. Compilation and signing are |
| separate steps. |
| * `--log <file>` writes all operations to a log file. |
| * `-t`, `--temp <dir>` sets the temporary working directory used for generated |
| files (ZIP library, `._pth`, extracted pip, generated JSON). When omitted, a |
| temporary directory is created automatically. If `--copy` targets a Dev |
| Drive, an adjacent temp directory on the same drive is used for speed. |
| * `-v` increases verbosity. Repeat for more detail. |
| |
| ### Layout options |
| |
| Optional components are selected with `--include-<name>` flags. Presets group |
| these into the configurations we ship (see [Layouts](#layouts)). For a quick |
| throwaway layout, `-a`/`--include-all` turns on every option (except those |
| noted below as not affected by `--include-all`); it is intended for debugging |
| rather than for producing a real distribution, since it mixes components that |
| are never shipped together. The main component flags are: |
| |
| * `--include-stable` the stable ABI DLL (`python3.dll`). |
| * `--include-pip` pip, extracted from the bundled wheels in |
| `Lib/ensurepip/_bundled`. |
| * `--include-pip-user` a `pip.ini` defaulting to `--user` installs. |
| * `--include-tcltk` Tcl, Tk and tkinter. |
| * `--include-idle` IDLE. Implies `--include-tcltk`. |
| * `--include-tests` the test suite. |
| * `--include-tools` scripts from `Tools`. |
| * `--include-venv` venv and ensurepip, plus the venv launcher executables. |
| * `--include-dev` headers and `.lib` files. |
| * `--include-symbols` `.pdb` symbol files. |
| * `--include-underpth` a `python<XY>._pth` file. Not affected by |
| `--include-all`. |
| * `--include-launchers` extra launcher executables (used with |
| `--include-appxmanifest`). |
| * `--include-appxmanifest` an APPX/MSIX manifest. |
| * `--include-props` a `python.props` MSBuild file. |
| * `--include-nuspec` a `python.nuspec` NuGet spec. |
| * `--include-chm` the CHM documentation. |
| * `--include-html-doc` the HTML documentation. |
| * `--include-freethreaded` free-threaded binaries. Not affected by |
| `--include-all`. |
| * `--include-alias`, `--include-alias3`, `--include-alias3x` aliased |
| entry-point executables (`python.exe`, `python3.exe`, `python3.x.exe` and |
| their `w` variants). |
| * `--include-install-json`, `--include-install-embed-json`, |
| `--include-install-test-json` a PyManager `__install__.json` for the |
| respective distribution. |
| * `--include-builddetails-json` a [PEP 739](https://peps.python.org/pep-0739/) |
| `build-details.json`. |
| |
| Layout behavior flags: |
| |
| * `-d`, `--debug` lays out the debug build (files with the `_d` suffix). The |
| debug binaries must already have been built (for example with |
| `PCbuild/build.bat -d`); the script never builds them. |
| * `-p`, `--precompile` includes `.pyc` files (at optimization levels 0, 1 and |
| 2) instead of, or in addition to, `.py` files. The bytecode is compiled |
| during layout, in-process, using the `py_compile` module of the interpreter |
| running the script. It does not launch the laid-out runtime and does not check |
| its version, so it assumes the running interpreter matches the target version; |
| compiling with a mismatched version produces `.pyc` files the target cannot |
| use. |
| * `-z`, `--zip-lib` puts the standard library into `python<XY>.zip` rather than |
| a `Lib` directory. |
| * `--flat-dlls` places extension modules and DLLs next to the executables |
| rather than in a `DLLs` directory. |
| * `--include-cat <file>` includes an already-built `.cat` catalog file. This |
| only copies the named file into the layout; it does not build or sign the |
| catalog and requires no external tooling. Producing the `.cat` from a `.cdf` |
| (see `--catalog`) is a separate step. |
| |
| ### Source options |
| |
| These options tell the script where to read from and what it is laying out. |
| |
| * `-s`, `--source <dir>` the repository root. Defaults to the repository |
| containing the script. |
| * `-b`, `--build <dir>` the build directory containing the compiled binaries. |
| Defaults to the directory containing the running interpreter. |
| * `--arch <win32|amd64|arm32|arm64>` the target architecture. When omitted, it |
| is inferred by reading the PE header of a binary in the build directory. |
| * `--doc-build <dir>` the documentation build directory. Defaults to |
| `<source>/Doc/build`. |
| |
| The following environment variables are read when set: |
| |
| * `PYTHON_HEXVERSION` / `PYTHONINCLUDE` override version detection when the |
| target version cannot be inferred by reading `Include/patchlevel.h` from the |
| source tree. Set one of these when laying out a version other than the one |
| running the script (see below). |
| * `TCL_LIBRARY` locates the Tcl library when `--include-tcltk` is set. If |
| unset, the script falls back to `TCL_LIBRARY.env` in the build directory. |
| * `PYTHON_NUSPEC_VERSION`, `PYTHON_PROPS_PLATFORM` fill in the generated |
| `python.nuspec` and `python.props` files. When unset, the version falls back |
| to the detected version number and the platform falls back to a value derived |
| from the target architecture. |
| * `APPX_DATA_PUBLISHER`, `APPX_DATA_WINVER`, `APPX_DATA_SHA256` fill in the |
| generated APPX manifest. When unset, they fall back to defaults: a placeholder |
| publisher certificate name, a `MaxVersionTested` of `10.0.22000.0`, and no |
| SCCD hash. These defaults are fine for local use but are not suitable for a |
| signed, Store-ready package. |
| |
| ## Layouts |
| |
| This section lists the common presets, which reflect our supported |
| configurations. Each is selected with `--preset-<name>` and expands to a fixed |
| set of `--include-<name>` options. They should help you understand which to use |
| for your scenario, and they are useful for figuring out where to put a new file |
| that you've just added to CPython. |
| |
| A preset can be combined with additional `--include-<name>` options to add |
| components on top of it; the options are cumulative. |
| |
| ### Development Kit (`--preset-default`) |
| |
| ``` |
| python PC/layout --copy dist --preset-default |
| ``` |
| |
| The development kit layout. This is the closest equivalent to a full install |
| and contains the interpreter, the standard library in `Lib`, extension modules |
| in `DLLs`, headers and import libraries (`--include-dev`), symbols, pip, tcltk, |
| IDLE, venv, the test suite, HTML docs, the stable ABI DLL, aliases and a |
| `build-details.json`. |
| |
| ### Python install manager (`--preset-pymanager`, `--preset-pymanager-test`) |
| |
| Layouts for the [Python install manager](https://github.com/python/pymanager). |
| This is now the primary way upstream CPython is distributed on Windows. Both |
| resemble the development kit but add a PyManager `__install__.json`. |
| |
| `pymanager-test` additionally includes the test suite and symbols; |
| `--preset-pymanager-test` is what produces the `py install PythonTest\` |
| packages. |
| |
| ### Embeddable package (`--preset-embed`) |
| |
| ``` |
| python PC/layout --zip embed.zip --preset-embed |
| ``` |
| |
| The embeddable package: a minimal, self-contained runtime intended to be |
| bundled inside another application. The standard library is placed in a ZIP |
| (`--zip-lib`), DLLs are flattened next to the executables (`--flat-dlls`), the |
| library is precompiled, and a `._pth` file (`--underpth`) is included to fix the |
| search path and isolate the runtime from user site directories. It omits pip, |
| tcltk, IDLE, the tests and development files. |
| |
| `--preset-embed --include-install-embed-json` is what produces the |
| `py install PythonEmbed\` packages. |
| |
| ### NuGet package (`--preset-nuget`) |
| |
| The NuGet package layout. Includes development files, pip, the stable ABI, |
| venv, aliases, a `build-details.json`, and the `python.props` and |
| `python.nuspec` files that describe the package to MSBuild and NuGet. |
| |
| ### APPX package (`--preset-appx`) |
| |
| The APPX/MSIX package layout for the Windows Store distribution. Includes the |
| stable ABI, pip, tcltk, IDLE, venv, development files, launchers, aliases and an |
| APPX manifest. This is no longer used for upstream CPython releases. |
| |
| ### Windows IoT Core (`--preset-iot`) |
| |
| A minimal layout for Windows IoT Core: aliases, the stable ABI and pip. This is |
| not used for upstream CPython releases. |
| |
| ## Build source options |
| |
| The `-b` and `-s` options let you lay out a build that is separate from the |
| interpreter running the script, including a different Python version. |
| |
| * `-b`/`--build` points at the build tree with the compiled binaries. It does |
| not need to match the interpreter running the script. |
| * `-s`/`--source` points at the source tree that supplies `Lib`, `Include`, |
| `Tools` and version information. |
| |
| The target version is normally read from `Include/patchlevel.h` in the source |
| tree. When laying out a version that differs from the running interpreter and |
| the source tree is not the matching one, set `PYTHON_HEXVERSION` (a hex version |
| such as `0x030f00a0`) or `PYTHONINCLUDE` (a directory containing |
| `patchlevel.h`) so the correct DLL names, suffixes and version numbers are used. |
| The script validates the inferred version against `patchlevel.h` and stops with |
| an error if they disagree. |
| |
| ## Tool structure |
| |
| The script is a package under `PC/layout`. `main.py` drives argument parsing, |
| builds the file list (`get_layout`), generates derived files |
| (`generate_source_files`) and copies or zips the result (`copy_files`). Support |
| modules live in `PC/layout/support`: |
| |
| * `options.py` defines the `OPTIONS` and `PRESETS` tables and generates the |
| `--include-*` and `--preset-*` command-line arguments. Add new options and |
| presets here. |
| * `constants.py` derives version numbers, DLL names and related constants from |
| `patchlevel.h` or the version environment variables. |
| * `filesets.py` provides the file-matching helpers (`FileStemSet`, |
| `FileNameSet`, `FileSuffixSet`) and the `rglob` globbing helper used |
| throughout `main.py`. |
| * `arch.py` infers the target architecture from a binary's PE header. |
| * `logging.py` configures logging and tracks whether errors occurred. |
| * `pip.py` extracts pip from the bundled wheels and lists the pip files. |
| * `catalog.py` generates the `.cdf`/`.cat` catalog definitions for signing. |
| * `props.py` generates `python.props` (NuGet/MSBuild). |
| * `nuspec.py` generates `python.nuspec` (NuGet). |
| * `appxmanifest.py` generates APPX/MSIX manifests. |
| * `pymanager.py` generates the PyManager `__install__.json`. |
| * `builddetails.py` generates the PEP 739 `build-details.json`. |
| |
| ### Classifying new files |
| |
| `main.py` collects files by globbing shared directories -- the build output |
| directory (`-b`) for binaries and the source `Lib`, `Include` and `Tools` |
| directories -- and then filters them. A new file added to any of these is |
| usually picked up with no change here: build extension modules (`*.pyd`) land in |
| `DLLs` (or alongside the executables under `--flat-dlls`), other build DLLs land |
| next to them, and files under `Lib` are mirrored into the layout's `Lib`. |
| |
| Changes are only needed when a new file belongs to an optional component, so it |
| must be routed to the right `--include-<name>` option rather than always |
| copied. The routing is driven by a set of file-matching tables near the top of |
| `main.py` (built from the `FileStemSet`, `FileNameSet` and `FileSuffixSet` |
| helpers in `support/filesets.py`). To classify a new file, add its name or |
| pattern to the matching table. |
| |
| Tables that gate files on an optional component (the file is only included when |
| the corresponding option is set): |
| |
| * `TEST_PYDS_ONLY`, `TEST_DLLS_ONLY`, `TEST_DIRS_ONLY` -- test-only extension |
| modules, DLLs and `Lib` directories; gated on `--include-tests`. Extension |
| module names starting with `_test` are already matched; add any other |
| test-only build module here (see also the note in `PCbuild/readme.txt`). |
| * `TCLTK_PYDS_ONLY`, `TCLTK_DLLS_ONLY`, `TCLTK_DIRS_ONLY`, `TCLTK_FILES_ONLY` -- |
| Tcl/Tk/tkinter extension modules (`_tkinter`), DLLs (`tcl*`, `tk*`, `zlib1`), |
| `Lib` directories (`tkinter`, `turtledemo`) and files (`turtle.py`); gated on |
| `--include-tcltk`. |
| * `IDLE_DIRS_ONLY` -- IDLE's `Lib` directory (`idlelib`); gated on |
| `--include-idle`. |
| * `VENV_DIRS_ONLY` -- `venv` and `ensurepip` `Lib` directories; gated on |
| `--include-venv`. |
| |
| Tables that exclude files outright: |
| |
| * `EXCLUDE_FROM_DLLS` -- build DLLs that are handled elsewhere and must not be |
| copied by the generic DLL glob (`python*`, `pyshellext`, `vcruntime*`). |
| * `EXCLUDE_FROM_LIB` -- never copied into `Lib` (`*.pyc`, `__pycache__`, |
| `*.pickle`). |
| * `EXCLUDE_FROM_COMPILE` -- `Lib` files that must not be precompiled |
| (`badsyntax_*`, `bad_*`). |
| * `EXCLUDE_FROM_CATALOG` -- suffixes omitted from the signing catalog because |
| they are signed separately (`.exe`, `.pyd`, `.dll`). |
| |
| Special cases in the debug and binary handling: |
| |
| * `REQUIRED_DLLS` (`libcrypto*`, `libssl*`, `libffi*`) -- always copied from the |
| build directory even for a release layout. Most build DLLs are filtered by |
| their `_d` suffix to match the debug or release build being laid out; these |
| dependencies do not follow that naming and would otherwise be dropped, so they |
| are matched here to force inclusion. Add a new external dependency DLL here if |
| it does not use the `_d` debug-suffix convention. |
| |
| When deciding where a new file goes, match it to the component it belongs to and |
| add it to the corresponding table. If it belongs in every layout and follows the |
| normal conventions, no change is needed. |
| |
| |
| ## Contributing guidelines |
| |
| Contributions are welcome. The script supports a broad range of scenarios, and |
| extending it for a new one is encouraged. Because the same code produces the |
| official releases across every supported version and architecture, additions |
| have to respect a few constraints so that existing configurations keep working. |
| |
| The script runs in an unusual context, and new code must hold to the following |
| assumptions: |
| |
| * Do not assume the Python being laid out can be launched. The script must run |
| correctly using only the interpreter running it, which may differ from the |
| target. |
| * Do not assume the layout version matches the version running the script. |
| Derive version-dependent behavior from the detected version rather than from |
| `sys.version` of the running interpreter. (Precompilation with `--precompile` |
| is the one deliberate exception, and it assumes a matching interpreter.) |
| * The script may be used to lay out an older version, so behavior changes have |
| to be preserved, either behind an option or gated on a version check, rather |
| than replaced outright. |
| * The script never builds anything. Everything it emits must already exist in |
| the build or source tree. |
| |
| When adding features, keep the surface area aligned with upstream: |
| |
| * New `--include-<name>` options for further customization are fine. |
| * Do not add presets beyond those used by upstream. Presets describe the |
| configurations we ship, so a new one implies a new supported release |
| artifact. |
| * Route new files through the classification tables (see [Classifying new |
| files](#classifying-new-files)) rather than adding one-off special cases. |