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).
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
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.cdfcatalog 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--copytargets a Dev Drive, an adjacent temp directory on the same drive is used for speed.-vincreases verbosity. Repeat for more detail.
Optional components are selected with --include-<name> flags. Presets group
these into the configurations we ship (see 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-stablethe stable ABI DLL (python3.dll).--include-pippip, extracted from the bundled wheels inLib/ensurepip/_bundled.--include-pip-userapip.inidefaulting to--userinstalls.--include-tcltkTcl, Tk and tkinter.--include-idleIDLE. Implies--include-tcltk.--include-teststhe test suite.--include-toolsscripts fromTools.--include-venvvenv and ensurepip, plus the venv launcher executables.--include-devheaders and.libfiles.--include-symbols.pdbsymbol files.--include-underpthapython<XY>._pthfile. Not affected by--include-all.--include-launchersextra launcher executables (used with--include-appxmanifest).--include-appxmanifestan APPX/MSIX manifest.--include-propsapython.propsMSBuild file.--include-nuspecapython.nuspecNuGet spec.--include-chmthe CHM documentation.--include-html-docthe HTML documentation.--include-freethreadedfree-threaded binaries. Not affected by--include-all.--include-alias,--include-alias3,--include-alias3xaliased entry-point executables (python.exe,python3.exe,python3.x.exeand theirwvariants).--include-install-json,--include-install-embed-json,--include-install-test-jsona PyManager__install__.jsonfor the respective distribution.--include-builddetails-jsona PEP 739build-details.json.
Layout behavior flags:
-d,--debuglays out the debug build (files with the_dsuffix). The debug binaries must already have been built (for example withPCbuild/build.bat -d); the script never builds them.-p,--precompileincludes.pycfiles (at optimization levels 0, 1 and 2) instead of, or in addition to,.pyfiles. The bytecode is compiled during layout, in-process, using thepy_compilemodule 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.pycfiles the target cannot use.-z,--zip-libputs the standard library intopython<XY>.ziprather than aLibdirectory.--flat-dllsplaces extension modules and DLLs next to the executables rather than in aDLLsdirectory.--include-cat <file>includes an already-built.catcatalog 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.catfrom a.cdf(see--catalog) is a separate step.
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/PYTHONINCLUDEoverride version detection when the target version cannot be inferred by readingInclude/patchlevel.hfrom the source tree. Set one of these when laying out a version other than the one running the script (see below).TCL_LIBRARYlocates the Tcl library when--include-tcltkis set. If unset, the script falls back toTCL_LIBRARY.envin the build directory.PYTHON_NUSPEC_VERSION,PYTHON_PROPS_PLATFORMfill in the generatedpython.nuspecandpython.propsfiles. 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_SHA256fill in the generated APPX manifest. When unset, they fall back to defaults: a placeholder publisher certificate name, aMaxVersionTestedof10.0.22000.0, and no SCCD hash. These defaults are fine for local use but are not suitable for a signed, Store-ready package.
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.
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.
Layouts for the Python install manager.
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.
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.
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.
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.
A minimal layout for Windows IoT Core: aliases, the stable ABI and pip. This is not used for upstream CPython releases.
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/--buildpoints at the build tree with the compiled binaries. It does not need to match the interpreter running the script.-s/--sourcepoints at the source tree that suppliesLib,Include,Toolsand 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.
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.pydefines theOPTIONSandPRESETStables and generates the--include-*and--preset-*command-line arguments. Add new options and presets here.constants.pyderives version numbers, DLL names and related constants frompatchlevel.hor the version environment variables.filesets.pyprovides the file-matching helpers (FileStemSet,FileNameSet,FileSuffixSet) and therglobglobbing helper used throughoutmain.py.arch.pyinfers the target architecture from a binary's PE header.logging.pyconfigures logging and tracks whether errors occurred.pip.pyextracts pip from the bundled wheels and lists the pip files.catalog.pygenerates the.cdf/.catcatalog definitions for signing.props.pygeneratespython.props(NuGet/MSBuild).nuspec.pygeneratespython.nuspec(NuGet).appxmanifest.pygenerates APPX/MSIX manifests.pymanager.pygenerates the PyManager__install__.json.builddetails.pygenerates the PEP 739build-details.json.
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 andLibdirectories; gated on--include-tests. Extension module names starting with_testare already matched; add any other test-only build module here (see also the note inPCbuild/readme.txt).TCLTK_PYDS_ONLY,TCLTK_DLLS_ONLY,TCLTK_DIRS_ONLY,TCLTK_FILES_ONLY-- Tcl/Tk/tkinter extension modules (_tkinter), DLLs (tcl*,tk*,zlib1),Libdirectories (tkinter,turtledemo) and files (turtle.py); gated on--include-tcltk.IDLE_DIRS_ONLY-- IDLE'sLibdirectory (idlelib); gated on--include-idle.VENV_DIRS_ONLY--venvandensurepipLibdirectories; 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 intoLib(*.pyc,__pycache__,*.pickle).EXCLUDE_FROM_COMPILE--Libfiles 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_dsuffix 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_ddebug-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.
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.versionof the running interpreter. (Precompilation with--precompileis 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) rather than adding one-off special cases.