Skip to content

Commit a0780d4

Browse files
committed
Enhance generate_getbuildinfo.py
* Use argparse for command line parsing. * Run _getcompiler if --compiler option is omitted. * Rename getbuildinfo.h variables.
1 parent eab1b0e commit a0780d4

4 files changed

Lines changed: 123 additions & 72 deletions

File tree

‎Makefile.pre.in‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,13 +1867,12 @@ regen-all: regen-cases regen-slots \
18671867
# Special rules for object files
18681868

18691869
Modules/getbuildinfo.h: $(srcdir)/Tools/build/generate_getbuildinfo.py Programs/_getcompiler
1870-
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_getbuildinfo.py $@ \
1871-
"$(MACHDEP)" \
1872-
"`LC_ALL=C $(GITVERSION)`" \
1873-
"`LC_ALL=C $(GITTAG)`" \
1874-
"`LC_ALL=C $(GITBRANCH)`" \
1875-
"`Programs/_getcompiler || echo COMPILER`" \
1876-
use_pyconfig
1870+
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/generate_getbuildinfo.py \
1871+
-o $@ \
1872+
--platform="$(MACHDEP)" \
1873+
--git-version="`LC_ALL=C $(GITVERSION)`" \
1874+
--git-tag="`LC_ALL=C $(GITTAG)`" \
1875+
--git-branch="`LC_ALL=C $(GITBRANCH)`"
18771876

18781877
Modules/getbuildinfo.o: $(srcdir)/Modules/getbuildinfo.c Modules/getbuildinfo.h
18791878
# Add local Modules/ include directory to get Modules/getbuildinfo.h

‎Modules/getbuildinfo.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Py_GetPlatform(void)
4040
const char *
4141
_Py_gitversion(void)
4242
{
43-
return GITVERSION;
43+
return GIT_VERSION;
4444
}
4545

4646
const char *
@@ -52,15 +52,15 @@ _Py_gitidentifier(void)
5252
const char *
5353
Py_GetBuildInfo(void)
5454
{
55-
return BUILDINFO;
55+
return BUILD_INFO;
5656
}
5757

5858
// Export the Python hex version as a constant.
5959
const unsigned long Py_Version = PY_VERSION_HEX;
6060

6161
// Keep the 'version' variable for backward compatibility.
6262
// Some debuggers inspect directly the variable.
63-
static const char *version = GET_VERSION;
63+
static const char *version = VERSION;
6464

6565
const char *
6666
Py_GetVersion(void)

‎PCbuild/_freeze_module.vcxproj‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@
491491
</PropertyGroup>
492492

493493
<Message Text="Run generate_getbuildinfo.py" Importance="high" />
494-
<Exec Command='$(PythonForBuild) Tools/build/generate_getbuildinfo.py Modules\getbuildinfo.h win32 $(GitVersion) $(GitTag) $(GitBranch) "$(Compiler)" $(GilEnabled)'
494+
<Exec Command='$(PythonForBuild) Tools/build/generate_getbuildinfo.py --platform=win32 --git-version="$(GitVersion)" --git-tag="$(GitTag)" --git-branch="$(GitBranch)" --compiler="$(Compiler)" --gil-enabled=$(GilEnabled)'
495495
WorkingDirectory="$(PySourcePath)" />
496496
</Target>
497497
<Target Name="_RebuildFrozen" AfterTargets="AfterBuild" Condition="$(Configuration) != 'PGUpdate'">

‎Tools/build/generate_getbuildinfo.py‎

Lines changed: 113 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Script to generate Modules/getbuildinfo.h
22

3+
import argparse
34
import locale
45
import os
56
import re
7+
import shlex
8+
import subprocess
69
import sys
710
import time
811

@@ -11,24 +14,38 @@
1114
SCRIPT_FULLNAME = f'Tools/build/{SCRIPT_NAME}'
1215

1316
# Get PY_VERSION from Include/patchlevel.h
14-
PY_VERSION_REGEX = re.compile(r'#define PY_VERSION +"(.*)"')
17+
PY_VERSION_REGEX = re.compile(r'^#define PY_VERSION +"(.*)"$', re.MULTILINE)
18+
19+
# Get HOSTRUNNER from Makefile
20+
HOSTRUNNER_REGEX = re.compile(r'^HOSTRUNNER *= *(.*)$', re.MULTILINE)
1521

1622
# Py_GIL_DISABLED from pyconfig.h
17-
Py_GIL_DISABLED_DEF_REGEX = re.compile(r'#define Py_GIL_DISABLED 1')
18-
Py_GIL_DISABLED_UNDEF_REGEX = re.compile(r'/\* #undef Py_GIL_DISABLED \*/')
23+
Py_GIL_DISABLED_DEF_REGEX = re.compile(r'^#define Py_GIL_DISABLED 1$', re.MULTILINE)
24+
Py_GIL_DISABLED_UNDEF_REGEX = re.compile(r'^/\* #undef Py_GIL_DISABLED \*/$', re.MULTILINE)
1925

2026

21-
def get_py_version():
22-
patchlevel_h = os.path.join(SRC_DIR, 'Include', 'patchlevel.h')
23-
with open(patchlevel_h, encoding='utf8') as fp:
27+
def parse_file(variable_name, filename, regex):
28+
with open(filename, encoding='utf8') as fp:
2429
code = fp.read()
25-
match = PY_VERSION_REGEX.search(code)
30+
match = regex.search(code)
2631
if not match:
27-
print(f"ERROR: Unable to locate PY_VERSION in {patchlevel_h}")
32+
print(f"ERROR: Unable to locate {variable_name} in {filename}")
2833
sys.exit(1)
2934
return match.group(1)
3035

3136

37+
def get_py_version():
38+
patchlevel_h = os.path.join(SRC_DIR, 'Include', 'patchlevel.h')
39+
return parse_file('PY_VERSION ', patchlevel_h, PY_VERSION_REGEX)
40+
41+
42+
def get_host_runner():
43+
# Look in the current working directory
44+
makefile = 'Makefile'
45+
HOSTRUNNER = parse_file('HOSTRUNNER', makefile, HOSTRUNNER_REGEX)
46+
return HOSTRUNNER.rstrip()
47+
48+
3249
def get_gil_disable():
3350
# Look in the current working directory
3451
pyconfig_h = 'pyconfig.h'
@@ -54,79 +71,114 @@ def get_date_time():
5471
day = time.strftime("%d", time_tuple)
5572
if day.startswith("0"):
5673
day = " " + day[1:]
57-
DATE = time.strftime(f"%b {day} %Y", time_tuple)
58-
TIME = time.strftime("%H:%M:%S", time_tuple)
59-
return (DATE, TIME)
74+
build_date = time.strftime(f"%b {day} %Y", time_tuple)
75+
build_time = time.strftime("%H:%M:%S", time_tuple)
76+
return (build_date, build_time)
6077

6178

62-
def main():
63-
if len(sys.argv) != 8:
64-
print(f"usage: {SCRIPT_NAME} "
65-
"OUTPUT PLATFORM GITVERSION GITTAG GITBRANCH COMPILER GIL_ENABLED")
66-
sys.exit(1)
79+
def get_build_info(git_tag, git_branch, git_version, build_date, build_time):
80+
if git_tag and git_tag != "undefined":
81+
git_id = git_tag
82+
else:
83+
git_id = git_branch
84+
if not git_id:
85+
git_id = "main"
6786

68-
OUTPUT = sys.argv[1]
69-
PLATFORM = sys.argv[2]
70-
GITVERSION = sys.argv[3]
71-
GITTAG = sys.argv[4]
72-
GITBRANCH = sys.argv[5]
73-
COMPILER = sys.argv[6]
74-
GIL_ENABLED = sys.argv[7]
87+
sep = ":" if git_version else ""
7588

76-
if not PLATFORM:
77-
PLATFORM = "unknown"
89+
build_info = f"{git_id}{sep}{git_version}, {build_date:.20s}, {build_time:.9s}"
90+
return (build_info, git_id)
7891

79-
# Force the C locale to format date as English
80-
locale.setlocale(locale.LC_ALL, 'C')
8192

82-
gittag = GITTAG
83-
if gittag and gittag != "undefined":
84-
gitid = gittag
93+
def parse_args():
94+
parser = argparse.ArgumentParser()
95+
parser.add_argument('-o', '--output', type=str)
96+
parser.add_argument('--platform', type=str, required=True)
97+
parser.add_argument('--git-version', type=str, required=True)
98+
parser.add_argument('--git-tag', type=str, required=True)
99+
parser.add_argument('--git-branch', type=str, required=True)
100+
parser.add_argument('--compiler', type=str)
101+
parser.add_argument('--gil-enabled', type=int)
102+
return parser.parse_args()
103+
104+
105+
def run_command(cmd):
106+
try:
107+
proc = subprocess.run(cmd, stdout=subprocess.PIPE, text=True)
108+
except OSError as exc:
109+
error = f'with: {exc!r}'
85110
else:
86-
gitid = GITBRANCH
111+
exitcode = proc.returncode
112+
if exitcode:
113+
error = f'with exit code {exitcode}'
114+
else:
115+
error = None
116+
117+
if error:
118+
print(f"Command {shlex.join(cmd)} failed {error}")
119+
sys.exit(1)
120+
return proc.stdout.rstrip()
87121

88-
revision = GITVERSION
89-
sep = ":" if revision else ""
90-
if not gitid:
91-
gitid = "main"
92122

93-
DATE, TIME = get_date_time()
123+
def main():
124+
# Force the C locale to format date as English
125+
locale.setlocale(locale.LC_ALL, 'C')
126+
127+
args = parse_args()
128+
output_filename = args.output
129+
platform = args.platform
130+
git_version = args.git_version
131+
git_tag = args.git_tag
132+
git_branch = args.git_branch
133+
compiler = args.compiler
134+
gil_enabled = args.gil_enabled
135+
136+
if not output_filename:
137+
# In the current directory
138+
output_filename = os.path.join('Modules', 'getbuildinfo.h')
139+
if not platform:
140+
platform = "unknown"
141+
142+
if not compiler:
143+
getcompiler = os.path.join('Programs', '_getcompiler')
144+
HOSTRUNNER = get_host_runner()
145+
if HOSTRUNNER:
146+
runner = shlex.split(HOSTRUNNER)[0]
147+
compiler = run_command([runner, getcompiler])
148+
else:
149+
compiler = run_command([getcompiler])
150+
151+
build_date, build_time = get_date_time()
152+
build_info, git_id = get_build_info(git_tag, git_branch, git_version, build_date, build_time)
153+
154+
# Get PY_VERSION macro from Include/patchlevel.h
94155
PY_VERSION = get_py_version()
95-
if GIL_ENABLED == 'use_pyconfig':
156+
if gil_enabled is None:
157+
# Get Py_GIL_DISABLED macro from pyconfig.h (defined or undefined)
96158
Py_GIL_DISABLED = get_gil_disable()
97-
GIL_ENABLED = not Py_GIL_DISABLED
98-
else:
99-
GIL_ENABLED = int(GIL_ENABLED)
100-
BUILDINFO = f"{gitid}{sep}{revision}, {DATE:.20s}, {TIME:.9s}"
159+
gil_enabled = not Py_GIL_DISABLED
101160

102-
if not GIL_ENABLED:
103-
GET_VERSION = f"{PY_VERSION} free-threading build ({BUILDINFO}) {COMPILER}"
161+
if not gil_enabled:
162+
version = f"{PY_VERSION} free-threading build ({build_info}) {compiler}"
104163
else:
105-
GET_VERSION = f"{PY_VERSION} ({BUILDINFO}) {COMPILER}"
164+
version = f"{PY_VERSION} ({build_info}) {compiler}"
106165

107-
new_filename = OUTPUT + ".new"
166+
new_filename = output_filename + ".new"
108167
with open(new_filename, "w", encoding="utf8") as fp:
109168
def write_macro(name, value):
110169
print(f'#define {name} "{value}"', file=fp)
111170

112171
print(f'// Header file auto-generated by {SCRIPT_FULLNAME}', file=fp)
113172
print(file=fp)
114-
write_macro('DATE', DATE)
115-
write_macro('TIME', TIME)
116-
write_macro('COMPILER', COMPILER)
117-
print(file=fp)
118-
write_macro('PLATFORM', PLATFORM)
119-
print(file=fp)
120-
write_macro('GITBRANCH', GITBRANCH)
121-
write_macro('GITTAG', GITTAG)
122-
write_macro('GITVERSION', GITVERSION)
123-
write_macro('GIT_IDENTIFIER', gitid)
124-
print(file=fp)
125-
write_macro('BUILDINFO', BUILDINFO)
126-
write_macro('GET_VERSION', GET_VERSION)
127-
128-
os.replace(new_filename, OUTPUT)
129-
print(f"{OUTPUT} updated")
173+
write_macro('PLATFORM', platform)
174+
write_macro('COMPILER', compiler)
175+
write_macro('GIT_VERSION', git_version)
176+
write_macro('GIT_IDENTIFIER', git_id)
177+
write_macro('BUILD_INFO', build_info)
178+
write_macro('VERSION', version)
179+
180+
os.replace(new_filename, output_filename)
181+
print(f"{output_filename} updated")
130182

131183

132184
if __name__ == "__main__":

0 commit comments

Comments
 (0)