gh-138489: Add build-details.json generation to PC/layout (GH-149153)

This commit is contained in:
Steve Dower 2026-05-15 13:51:27 +01:00 committed by GitHub
parent a0551b1a12
commit 4aa296f9c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 142 additions and 0 deletions

View file

@ -0,0 +1,4 @@
Windows distributions now include a :file:`build-details.json` file (see
:pep:`739`). The legacy installer does not install it, but all other
distributions from python.org and all preset configurations in the
``PC\layout`` script will include one.

View file

@ -22,6 +22,7 @@
__path__ = [str(Path(__file__).resolve().parent)]
from .support.appxmanifest import *
from .support.builddetails import *
from .support.catalog import *
from .support.constants import *
from .support.filesets import *
@ -317,6 +318,9 @@ def _c(d):
for dest, src in get_appx_layout(ns):
yield dest, src
for dest, src in get_builddetails(ns):
yield dest, src
if ns.include_cat:
if ns.flat_dlls:
yield ns.include_cat.name, ns.include_cat

View file

@ -0,0 +1,119 @@
import io
import json
from . import constants
_LEVELS = {
0xA0: "alpha",
0xB0: "beta",
0xC0: "candidate",
0xF0: "final",
}
_TEMPLATE = {
"schema_version": "1.0",
"base_prefix": ".",
"base_interpreter": "python.exe",
"platform": None, # Set later
"language": {
"version": f"{constants.VER_MAJOR}.{constants.VER_MINOR}",
"version_info": {
"major": constants.VER_MAJOR,
"minor": constants.VER_MINOR,
"micro": constants.VER_MICRO,
"releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"),
"serial": constants.VER_FIELD4 & 0x0F,
},
},
"implementation": {
"name": "cpython",
"cache_tag": f"cpython-{constants.VER_MAJOR}{constants.VER_MINOR}",
"version": {
"major": constants.VER_MAJOR,
"minor": constants.VER_MINOR,
"micro": constants.VER_MICRO,
"releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"),
"serial": constants.VER_FIELD4 & 0x0F,
},
"hexversion": constants.VER_HEXVERSION,
},
"abi": {
"flags": [],
"extension_suffix": ".pyd",
"stable_abi_suffix": ".pyd",
},
"suffixes": {
"source": [".py", ".pyw"],
"bytecode": [".pyc"],
"extensions": [".pyd"],
},
"libpython": {
"dynamic": constants.PYTHON_DLL_NAME,
"dynamic_stableabi": constants.PYTHON_STABLE_DLL_NAME,
"link_extensions": True,
},
"c_api": {
},
}
def _with_d(path):
pre, sep, post = path.partition(".")
return pre + "_d" + sep + post
def _add_d(data, *args):
for a in args[:-1]:
data = data[a]
a = args[-1]
v = data[a]
if isinstance(v, list):
data[a] = [_with_d(i) for i in data[a]]
else:
data[a] = _with_d(data[a])
def get_builddetails(ns):
if not ns.include_builddetails_json:
return
details = dict(_TEMPLATE)
plat = {
"win32": "win32",
"amd64": "win-amd64",
"arm64": "win-arm64",
}.get(ns.arch, ns.arch)
pyd_abi_flags = ""
if ns.include_freethreaded:
details["abi"]["flags"].append("t")
pyd_abi_flags += "t"
if ns.debug:
details["abi"]["flags"].append("d")
norm_plat = plat.replace("-", "_")
ext_suffix = f".cp{constants.VER_MAJOR}{constants.VER_MINOR}{pyd_abi_flags}-{norm_plat}.pyd"
details["abi"]["extension_suffix"] = ext_suffix
details["suffixes"]["extensions"].insert(0, ext_suffix)
details["platform"] = plat
if ns.include_dev:
details["c_api"]["headers"] = "Include"
if ns.include_freethreaded:
details["libpython"]["dynamic"] = constants.FREETHREADED_PYTHON_DLL_NAME
details["libpython"]["dynamic_stableabi"] = constants.FREETHREADED_PYTHON_STABLE_DLL_NAME
if ns.debug:
_add_d(details, "base_interpreter")
_add_d(details, "abi", "stable_abi_suffix")
_add_d(details, "abi", "extension_suffix")
_add_d(details, "suffixes", "extensions")
_add_d(details, "libpython", "dynamic")
_add_d(details, "libpython", "dynamic_stableabi")
buffer = io.StringIO()
json.dump(details, buffer, indent=2)
yield "build-details.json", ("build-details.json", buffer.getvalue().encode())

View file

@ -23,6 +23,14 @@ def _unpack_hexversion():
return _read_patchlevel_version(pathlib.Path(os.getenv("PYTHONINCLUDE")))
except OSError:
pass
# Manual search for a '-s <source dir>` arument
try:
src = sys.argv[sys.argv.index("-s") + 1]
return _read_patchlevel_version(pathlib.Path(src) / "Include")
except (IndexError, ValueError):
pass
except OSError:
pass
return struct.pack(">i", sys.hexversion)
@ -68,6 +76,7 @@ def check_patchlevel_version(sources):
VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4 = _unpack_hexversion()
VER_HEXVERSION = (VER_MAJOR << 24) | (VER_MINOR << 16) | (VER_MICRO << 8) | (VER_FIELD4)
VER_SUFFIX = _get_suffix(VER_FIELD4)
VER_FIELD3 = VER_MICRO << 8 | VER_FIELD4
VER_DOT = "{}.{}".format(VER_MAJOR, VER_MINOR)

View file

@ -39,6 +39,7 @@ def public(f):
"install-json": {"help": "a PyManager __install__.json file"},
"install-embed-json": {"help": "a PyManager __install__.json file for embeddable distro"},
"install-test-json": {"help": "a PyManager __install__.json for the test distro"},
"builddetails-json": {"help": "a PEP 739 build-details.json"},
}
@ -69,6 +70,7 @@ def public(f):
"props",
"nuspec",
"alias",
"builddetails-json",
],
},
"iot": {"help": "Windows IoT Core", "options": ["alias", "stable", "pip"]},
@ -85,6 +87,7 @@ def public(f):
"symbols",
"html-doc",
"alias",
"builddetails-json",
],
},
"embed": {
@ -96,6 +99,7 @@ def public(f):
"flat-dlls",
"underpth",
"precompile",
"builddetails-json",
],
},
"pymanager": {
@ -109,6 +113,7 @@ def public(f):
"dev",
"html-doc",
"install-json",
"builddetails-json",
],
},
"pymanager-test": {
@ -124,6 +129,7 @@ def public(f):
"symbols",
"tests",
"install-test-json",
"builddetails-json",
],
},
}