GeezerVison is showing github.com — gh-158948: Generate `Modules/getbuildinfo.h` by vstinner · Pull Request #158951 · python/cpython
Conversation
vstinner
commented
Oct 7, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Add Tools/build/generate_getbuildinfo.py to generate a new Module/getbuildinfo.h header file which contains build information strings. It replaces C code which generates these strings at runtime.
Merge Python/getcompiler.c, Python/getcopyright.c, Python/getplatform.c and Python/getversion.c into Modules/getbuildinfo.c.
Truncate long Clang version string to just keep "Clang x.y.z" or "Apple Clang x.y.z".
COMPILER and _Py_COMPILER macros no longer contain surrounding square brackets.
Add _getcompiler project to the Visual Studio solution.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Merge Python/getcompiler.c, Python/getcopyright.c,
Python/getplatform.c and Python/getversion.c into
Modules/getbuildinfo.c.
Add Tools/build/generate_getbuildinfo.py to auto-generate a new
Module/getbuildinfo.h header file which contains build information
strings.
|
This PR is a draft. I didn't investigate Windows support yet. I didn't try cross-compilation, it may break.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Oct 7, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Ok, I fixed the out-of-tree build (used by the Ubuntu CI for example).
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
It's only needed in the Python script. Python.h defines PY_VERSION
(via patchlevel.h).
|
Example of auto-generated Modules/getbuildinfo.h header file:
// Header file auto-generated by Tools/build/generate_getbuildinfo.py
#define DATE "Oct 7 2026"
#define TIME "05:35:34"
#define COMPILER "[GCC 16.2.1 20260819 (Red Hat 16.2.1-2)]"
#define PLATFORM "linux"
#define GITBRANCH "getbuildinfo"
#define GITTAG "heads/getbuildinfo"
#define GITVERSION "22d1a6b7c1e"
#define GIT_IDENTIFIER "heads/getbuildinfo"
#define BUILDINFO "heads/getbuildinfo:22d1a6b7c1e, Oct 7 2026, 05:35:34"
#define GET_VERSION "3.16.0a0 (heads/getbuildinfo:22d1a6b7c1e, Oct 7 2026, 05:35:34) [GCC 16.2.1 20260819 (Red Hat 16.2.1-2)]"
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Oct 7, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
|
Ah, the "WASI / build and test" job does cross-compile! Running the Programs/_getcompiler program to get the compiler version fails with Exec format error.
/home/runner/work/cpython/cpython/cross-build/aarch64-unknown-linux-gnu/python ../../Tools/build/generate_getbuildinfo.py Modules/getbuildinfo.h \
"wasi" \
`LC_ALL=C git --git-dir ../../.git rev-parse --short HEAD` \
`LC_ALL=C git --git-dir ../../.git describe --all --always --dirty` \
`LC_ALL=C git --git-dir ../../.git name-rev --name-only HEAD` \
"`Programs/_getcompiler`"
(...)
/bin/sh: 1: Programs/_getcompiler: Exec format error
Later, running test.pythinfo fails on collect_platform() because sys.version lacks the compiler:
ERROR: collect_platform() failed
Traceback (most recent call last):
File "/Lib/test/pythoninfo.py", line 1418, in collect_info
collect_func(info_add)
~~~~~~~~~~~~^^^^^^^^^^
File "/Lib/test/pythoninfo.py", line 185, in collect_platform
platform.python_implementation())
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "/Lib/platform.py", line 1199, in python_implementation
return _sys_version()[0]
~~~~~~~~~~~~^^
File "/Lib/platform.py", line 1159, in _sys_version
raise ValueError(
'failed to parse CPython sys.version: %s' %
repr(sys_version))
ValueError: failed to parse CPython sys.version: '3.16.0a0 (remotes/pull/158951/merge-dirty:00e222b, Oct 7 2026, 03:37:58) '
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
With the help of @zware, I managed to update the PCbuild project, to build Programs_getcompiler.c and generate Modules\getbuildinfo.h on Windows.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Aha, test_freeze_simple_script() of test_tools fails on Ubuntu / build and test (ubuntu-26.04-arm) with:
LC_ALL=C sed -e 's,\$(\([A-Za-z0-9_]*\)),\$\{\1\},g' < Misc/python-config.sh >python-config
python3.14 /tmp/test_python_0l4z8_yx/tmpt900bnty/cpython/Tools/build/generate_getbuildinfo.py Modules/getbuildinfo.h \
"linux" \
`LC_ALL=C ` \
`LC_ALL=C ` \
`LC_ALL=C ` \
"`Programs/_getcompiler || echo COMPILER`" \
use_pyconfig
usage: generate_getbuildinfo.py OUTPUT PLATFORM GITVERSION GITTAG GITBRANCH COMPILER GIL_ENABLED
make[1]: Leaving directory '/tmp/test_python_0l4z8_yx/tmpt900bnty/python-build'
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Aha, test_freeze_simple_script() of test_tools fails on Ubuntu / build and test (ubuntu-26.04-arm)
It's just missing quotes: I fixed it.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
* Use argparse for command line parsing.
* Run _getcompiler if --compiler option is omitted.
* Rename getbuildinfo.h variables.
Adjust also getbuildinfo.h indentation
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Logs of truncated Clang versions on buildbots:
- aarch64 Android (build Python): Truncate compiler string
Clang 16.0.0 (clang-1600.0.26.6) to Clang 16.0.0
- AMD64 Android (host Python):Truncate compiler string
Android (13691557, +pgo, +bolt, +lto, +mlgo, based on r522817d) clang version 18.0.4 (https://android.googlesource.com/toolchain/llvm-project d8003a456d14a3deb8054cdaa529ffbf02d9b262) to Android Clang 18.0.4
- AMD64 FreeBSD Refleaks: Truncate compiler string
Clang 19.1.7 (https://github.com/llvm/llvm-project.git llvmorg-19.1.7-0-gcd708029e0b2) to Clang 19.1.7
- wasm32-wasi: Truncate compiler string
Clang 23.1.0-wasi-sdk (https://github.com/llvm/llvm-project 895aa2c896ada719451be2e3673c83da8ddf1141) to Clang 23.1.0
- iOS ARM64 Simulator (build Python): Truncate compiler string
Clang 16.0.0 (clang-1600.0.26.6) to Clang 16.0.0
- iOS ARM64 Simulator (host Python): Truncate compiler string
Apple clang version 16.0.0 (clang-1600.0.26.6) to Apple Clang 16.0.0
- WASM Emscripten: Truncate compiler string
Clang 24.0.0git (https:/github.com/llvm/llvm-project a06d9165905ce89b5ffef2bbb84c886d60a9b8bf) to Clang 24.0.0git
- aarch64 Fedora Stable Clang: Truncate compiler string
Clang 21.1.8 (Fedora 21.1.8-6.fc43) to Clang 21.1.8
- x86-64 macOS: Truncate compiler string
Clang 14.0.0 (clang-1400.0.29.202) to Clang 14.0.0
Note: Clang 23.1.0-wasi-sdk truncated to Clang 23.1.0 is a bug: the -wasi-sdk suffix should be kept. I will fix it in my next change.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Windows also does cross-compilation, and presumably you're running the generator using whichever host Python is available, which means there's 0% guarantee it'll be the same as the target.
I'd also be very disappointed if generating the build info invalidates the cleanness of version control - if everything is committed, it should show as clean, and overwriting Modules/getbuildinfo.h will break that (equally, having the file be absent/ignored until created is annoying for editors/IDEs, as is putting it outside of the source tree).
Is there a real reason to rework this into a script rather than just avoiding the fixed-length arrays? Between some external commands and the C preprocessor, this should be straightforward.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
@zooba:
Windows also does cross-compilation, and presumably you're running the generator using whichever host Python is available, which means there's 0% guarantee it'll be the same as the target.
Tools/build/generate_getbuildinfo.py doesn't get any information from the Python used to run the script. It only collects data from its command line arguments, Makefile, pyconfig.h, $(srcdir)/Include/patchlevel.h, the _getcompiler program, and SOURCE_DATE_EPOCH environment variable.
On Windows, the _getcompiler program is run by the Visual studio project in PCbuild/_freeze_module.vcxproj.
I didn't think about cross-compilation on Windows. On Unix, running _getprogram can fail on cross-compilation: in this case, the C compiler is retrieve from the CC variable of Makefile and $CC --version is run. I suppose that we can do the same on Windows, run <compiler> --version (or something like that). But I'm not sure of the retrieve the C compiler? Any advice is welcomed :-)
I'd also be very disappointed if generating the build info invalidates the cleanness of version control - if everything is committed, it should show as clean, and overwriting Modules/getbuildinfo.h will break that (equally, having the file be absent/ignored until created is annoying for editors/IDEs, as is putting it outside of the source tree).
Modules/getbuildinfo.h is generated at each build. I'm not sure when it should be updated. I have to check how it works currently. So far, I spent a lot of time to just make the build work in all platforms supported by Python (GitHub Actions and now buildbots) :-)
I didn't get your remark on version control: Modules/getbuildinfo.h is not tracked by Git on purpose.
Is there a real reason to rework this into a script rather than just avoiding the fixed-length arrays? Between some external commands and the C preprocessor, this should be straightforward.
- The Clang version string is normalized (truncated).
- Add support for
SOURCE_DATE_EPOCH environment variable for reproducible build.
Py_GetBuildInfo() and Py_GetVersion() no longer have to format the string at the first call: it's now computed statically during Python build.
- Later, it will be easiler to modify the code to allow overridding the compiler string for reproducible build: see PR gh-144121: Allow overriding COMPILER with UNVERSIONED_COMPILER #144124.
To me, it seems cleaner to have the Tools/build/generate_getbuildinfo.py script to process, cleanup, and validate all build information.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
I wasn't sure if PYTHON_FOR_BUILD is actually needed to build Python on Unix. I tried PYTHON_FOR_BUILD=false and the build fails on running false ./Tools/build/generate-build-details.py none/build-details.json. Ah yes, we do run a Python script PYTHON_FOR_BUILD to build Python! So my change doesn't introduce a new dependency on Python.
On Windows, the FindPythonForBuild target downloads Python if Python is not already installed. It is especially needed by "regen" targets.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
It is especially needed by "regen" targets
Which are optional, and if the generated files are present, it shouldn't run.
(From one of the buildbots):
py -3.14 Tools/build/generate_getbuildinfo.py --platform=win32 --git-version="00401067d0" --git-tag="heads/refs/pull/158951/merge" --git-branch="refs/pull/158951/merge" --compiler="MSC v.1951 32 bit (Intel)" --free-threading=1
This command line bothers me, there seems to be some very easy ways to inject extra commands here if you control the branch name or compiler name (and as we know, some compiler names can be a bit silly). I'd rather see the values passed as environment variables to avoid any risk
I haven't dug through the change yet to figure it out, but it's worth being aware that our release builds don't always run the two PGO builds on the same machine. We do the instrumented build first, maybe start a new machine to run the profile, and then start another new machine to merge the profile. This involves copying $(IntDir) from the first machine and download it on the third one, so if the generated file is in that directory it should be fine, but if it lives somewhere else then we may have to generate it again later. It shouldn't matter (output should be identical), but it'd be nice to know ahead of time whether it's going to reuse the file or not.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
See also #157368 where the Clang version was too long (Clang 22.1.3 (https://github.com/llvm/llvm-project e9846648fd6183ee6d8cbdb4502213fcf902a211)) on Windows, and has been replaced with "Clang x.y.z" (PR #157369).
The Windows clang build bot now shows (https://buildbot.python.org/?#/builders/2269/builds/34/steps/3/logs/stdio) 1
sys.version: 3.16.0a0 (heads/refs/pull/158951/merge:00401067d0, Oct 8 2026, 00:02:24) [Clang 22.1.3]
vs https://buildbot.python.org/#/builders/2269/builds/17/steps/3/logs/stdio
sys.version: 3.16.0a0 (heads/refs/pull/157934/merge:a83720779a, Oct 6 2026, 10:19:52) [Clang 22.1.3 64 bit (AMD64) with MSC v.1951 CRT]
Quote from #157368
A lot of code depends on being able to parse the now missing 64 bit (AMD64) part (#145410, #154200, #154199, ...)
which the associated PRs #154210 and #154553 "masked away" on main (and hence the buildbot stayed green). 3rd party code relying on being able to parse the 64 bit (AMD64) part will now be broken again?
Also, I'd miss the MSC CRT version ...
Footnotes
-
confirmed on a local build as well, and the build log shows generate_getbuildinfo.py: Truncate compiler string 'Clang 22.1.3 64 bit (AMD64) with MSC v.1951 CRT' to 'Clang 22.1.3' ↩
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Check also that the string doesn't contain embedded null character.
|
@chris-eibl: Leaving the compiler string unchanged on Windows is trivial. I updated the script and I added tests. Deciding how to truncate Clang version or not is open to debate, that's one of the reason why I created the discussion on Discourse.
@zooba: Oh right, I can see how a compiler string or a Git version/tag/branch can inject quotes which would change the generate_getbuildinfo.py command line. Not good. I changed the script so it now runs _getcompiler program and runs the 3 git commands. Later, I'm also planning to move git commands into the script on Unix (remove the GIT variables from Makefile and configure).
Next week I plan to investigate the cross-compilation on Windows to get the right compiler string.
Also, it seems like 32-bit is reported ([MSC v.1951 32 bit (Intel)]) even when Python is built in 64-bit mode. I need to investigate this issue.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Remove also pathcch.lib dependency and use the Python resource.
Also, it seems like 32-bit is reported ([MSC v.1951 32 bit (Intel)]) even when Python is built in 64-bit mode. I need to investigate this issue.
Ah. It was a surprising choice to use <Platform>$(PreferredToolArchitecture)</Platform> for <FreezeProjects>. _freeze_module_d.exe was also built in 32-bit even if Python is built in 64-bit. I changed that to <Platform>$(Platform)</Platform> and so the right architecture is now picked (the same than the one used to build Python).
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
|
|
|
|
|
|
|
def compact_compiler(compiler):
|
|
|
if '64 bit (AMD64)' in compiler:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are also
[MSC v.1951 32 bit (Intel)]
[MSC v.1951 64 bit (ARM64)]
for "regular" MSC builds, but they don't get compacted, because CLANG_VERSION_REGEX does not match.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Truncate long Clang version string to just keep "Clang x.y.z" or "Apple Clang x.y.z".
Please do not truncate the Apple Clang version string to "x.y.z". The "x.y.z" value is not unique among Xcode versions as can be seen here. It is often important to know which Apple Clang was used for builds and examining the version string that displays in the interpreter startup has been used for years as an easy check. I don't understand what is driving this change. Please reconsider.
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Ah. It was a surprising choice to use <Platform>$(PreferredToolArchitecture)</Platform> for <FreezeProjects>.
This was a deliberate choice in #28491, because the _freeze_module.exe has to run on the compiling host, not the target platform. IOW, this will break cross-compilation like done for the official release builds, where the compiling host is x64 and the target is Arm64.
|
zooba reacted with thumbs up emoji
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Also, it seems like 32-bit is reported ([MSC v.1951 32 bit (Intel)]) even when Python is built in 64-bit mode.
Yupp, due to PreferredToolArchitecture and because we use the 32bit version of msbuild by default. Thus, the _freeze_module is built using HostX86\x86\CL.exe, whereas the rest is "cross-compiled" using HostX86\x64\CL.exe, see #158244 (comment).
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
zooba
commented
Oct 9, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Ah. It was a surprising choice to use <Platform>$(PreferredToolArchitecture)</Platform> for <FreezeProjects>. _freeze_module_d.exe was also built in 32-bit even if Python is built in 64-bit. I changed that to <Platform>$(Platform)</Platform> and so the right architecture is now picked (the same than the one used to build Python).
(Edit: I see Chris got here first. Don't read this as a pile-on, I did "quote reply" and skipped over the rest of the comments :-) )
Changing this will break cross-compilation. We need tools to be built using the preferred tool architecture so they are guaranteed to be runnable on the build machine. (The default being 32-bit is up to Microsoft to change, but at least by using the standard variable it's easy for users to override.)
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
|
Another approach you might take here that could be easier would be to use a very short C project compiled with preprocessor output enabled, then grab that output and process it again using the Python script. You don't need to run the built executable. (This might even be possible to do as part of pythoncore.vcxproj, I'm not sure if there's a guarantee what order these run in. Might be getting into some tricky MSBuild logic though, so maybe don't bother.)
In vcxproj, adding <PreprocessToFile>true</PreprocessToFile> and <PreprocessOutputPath>$(path)</PreprocessOutputPath> (and optionally PreprocessSuppressLineNumbers) to the ClCompile element will write the preprocessor output (using /P and /Fi).
|
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
|