Skip to content

Commit cc522fc

Browse files
committed
gh-138489: Add build-details.json generation to PC/layout
1 parent 40dc61a commit cc522fc

5 files changed

Lines changed: 140 additions & 0 deletions

File tree

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

PC/layout/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
__path__ = [str(Path(__file__).resolve().parent)]
2323

2424
from .support.appxmanifest import *
25+
from .support.builddetails import *
2526
from .support.catalog import *
2627
from .support.constants import *
2728
from .support.filesets import *
@@ -310,6 +311,9 @@ def _c(d):
310311
for dest, src in get_appx_layout(ns):
311312
yield dest, src
312313

314+
for dest, src in get_builddetails(ns):
315+
yield dest, src
316+
313317
if ns.include_cat:
314318
if ns.flat_dlls:
315319
yield ns.include_cat.name, ns.include_cat

PC/layout/support/builddetails.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import io
2+
import json
3+
from . import constants
4+
5+
_LEVELS = {
6+
0xA0: "alpha",
7+
0xB0: "beta",
8+
0xC0: "candidate",
9+
0xF0: "final",
10+
}
11+
12+
13+
_TEMPLATE = {
14+
"schema_version": "1.0",
15+
"base_prefix": ".",
16+
"base_interpreter": "python.exe",
17+
"platform": None, # Set later
18+
"language": {
19+
"version": f"{constants.VER_MAJOR}.{constants.VER_MINOR}",
20+
"version_info": {
21+
"major": constants.VER_MAJOR,
22+
"minor": constants.VER_MINOR,
23+
"micro": constants.VER_MICRO,
24+
"releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"),
25+
"serial": constants.VER_FIELD4 & 0x0F,
26+
},
27+
},
28+
"implementation": {
29+
"name": "cpython",
30+
"cache_tag": f"cpython-{constants.VER_MAJOR}{constants.VER_MINOR}",
31+
"version": {
32+
"major": constants.VER_MAJOR,
33+
"minor": constants.VER_MINOR,
34+
"micro": constants.VER_MICRO,
35+
"releaselevel": _LEVELS.get(constants.VER_FIELD4 & 0xF0, "final"),
36+
"serial": constants.VER_FIELD4 & 0x0F,
37+
},
38+
},
39+
"abi": {
40+
"flags": [],
41+
"extension_suffix": ".pyd",
42+
"stable_abi_suffix": ".pyd",
43+
},
44+
"suffixes": {
45+
"source": [".py"],
46+
"bytecode": [".pyc"],
47+
"extensions": [".pyd"],
48+
},
49+
"libpython": {
50+
"dynamic": constants.PYTHON_DLL_NAME,
51+
"dynamic_stableabi": constants.PYTHON_STABLE_DLL_NAME,
52+
"link_extensions": True,
53+
},
54+
"c_api": {
55+
},
56+
}
57+
58+
59+
def _with_d(path):
60+
pre, sep, post = path.partition(".")
61+
return pre + "_d" + sep + post
62+
63+
64+
def _add_d(data, *args):
65+
for a in args[:-1]:
66+
data = data[a]
67+
a = args[-1]
68+
v = data[a]
69+
if isinstance(v, list):
70+
data[a] = [_with_d(i) for i in data[a]]
71+
else:
72+
data[a] = _with_d(data[a])
73+
74+
75+
def get_builddetails(ns):
76+
if not ns.include_builddetails_json:
77+
return
78+
79+
details = dict(_TEMPLATE)
80+
81+
plat = {
82+
"win32": "win32",
83+
"amd64": "win-amd64",
84+
"arm64": "win-arm64",
85+
}.get(ns.arch, ns.arch)
86+
87+
pyd_abi_flags = ""
88+
if ns.include_freethreaded:
89+
details["abi"]["flags"].append("t")
90+
pyd_abi_flags += "t"
91+
if ns.debug:
92+
details["abi"]["flags"].append("d")
93+
94+
norm_plat = plat.replace("-", "_")
95+
ext_suffix = f".cp{constants.VER_MAJOR}{constants.VER_MINOR}{pyd_abi_flags}-{norm_plat}.pyd"
96+
details["abi"]["extension_suffix"] = ext_suffix
97+
details["suffixes"]["extensions"].insert(0, ext_suffix)
98+
99+
details["platform"] = plat
100+
101+
if ns.include_dev:
102+
details["c_api"]["headers"] = "Include"
103+
104+
if ns.include_freethreaded:
105+
details["libpython"]["dynamic"] = constants.FREETHREADED_PYTHON_DLL_NAME
106+
details["libpython"]["dynamic_stableabi"] = constants.FREETHREADED_PYTHON_STABLE_DLL_NAME
107+
108+
if ns.debug:
109+
_add_d(details, "base_interpreter")
110+
_add_d(details, "abi", "stable_abi_suffix")
111+
_add_d(details, "abi", "extension_suffix")
112+
_add_d(details, "suffixes", "extensions")
113+
_add_d(details, "libpython", "dynamic")
114+
_add_d(details, "libpython", "dynamic_stableabi")
115+
116+
buffer = io.StringIO()
117+
json.dump(details, buffer, indent=2)
118+
yield "build-details.json", ("build-details.json", buffer.getvalue().encode())

PC/layout/support/constants.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ def _unpack_hexversion():
2323
return _read_patchlevel_version(pathlib.Path(os.getenv("PYTHONINCLUDE")))
2424
except OSError:
2525
pass
26+
# Manual search for a '-s <source dir>` arument
27+
try:
28+
src = sys.argv[sys.argv.index("-s") + 1]
29+
return _read_patchlevel_version(pathlib.Path(src) / "Include")
30+
except (IndexError, ValueError):
31+
pass
32+
except OSError:
33+
pass
2634
return struct.pack(">i", sys.hexversion)
2735

2836

PC/layout/support/options.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ def public(f):
3939
"install-json": {"help": "a PyManager __install__.json file"},
4040
"install-embed-json": {"help": "a PyManager __install__.json file for embeddable distro"},
4141
"install-test-json": {"help": "a PyManager __install__.json for the test distro"},
42+
"builddetails-json": {"help": "a PEP 739 build-details.json"},
4243
}
4344

4445

@@ -69,6 +70,7 @@ def public(f):
6970
"props",
7071
"nuspec",
7172
"alias",
73+
"builddetails-json",
7274
],
7375
},
7476
"iot": {"help": "Windows IoT Core", "options": ["alias", "stable", "pip"]},
@@ -85,6 +87,7 @@ def public(f):
8587
"symbols",
8688
"html-doc",
8789
"alias",
90+
"builddetails-json",
8891
],
8992
},
9093
"embed": {
@@ -96,6 +99,7 @@ def public(f):
9699
"flat-dlls",
97100
"underpth",
98101
"precompile",
102+
"builddetails-json",
99103
],
100104
},
101105
"pymanager": {
@@ -109,6 +113,7 @@ def public(f):
109113
"dev",
110114
"html-doc",
111115
"install-json",
116+
"builddetails-json",
112117
],
113118
},
114119
"pymanager-test": {
@@ -124,6 +129,7 @@ def public(f):
124129
"symbols",
125130
"tests",
126131
"install-test-json",
132+
"builddetails-json",
127133
],
128134
},
129135
}

0 commit comments

Comments
 (0)