Skip to content

feat!: drop support for Python 3.8, MSVC 2017#6110

Draft
henryiii wants to merge 9 commits into
masterfrom
drop-python-3.8
Draft

feat!: drop support for Python 3.8, MSVC 2017#6110
henryiii wants to merge 9 commits into
masterfrom
drop-python-3.8

Conversation

@henryiii

@henryiii henryiii commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Now require 3.9+ and matching MSVC 2019+.

🤖 AI text below 🤖

Description

Python 3.8 is at end of life. The deprecation note in the docs said that support
goes away in 3.1. This PR removes it. The minimum is now Python 3.9.

Configuration and tooling:

  • requires-python, the classifiers, and the mypy and pylint versions move to 3.9
  • CI matrix and packaging jobs move from 3.8 to 3.9. The AlmaLinux 8 job installs python39-devel
  • The AppVeyor job uses C:\Python39 in place of C:\Python38
  • The CMake tooling asks for Python 3.9
  • The #error in detail/common.h rejects Python earlier than 3.9
  • setup_helpers.py uses built-in generics in place of typing.List and typing.Tuple

Dead code paths that this removes:

  • the _PyObject_Vectorcall fallback in cast.h
  • the frame->f_code and frame->f_back fallbacks in pytypes.h
  • the PyFrame_FastToLocals path in get_type_override
  • the conditional Py_VISIT(Py_TYPE(self)) in tp_traverse
  • PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX, the pre-PyConfig interpreter init, and
    the widen_chars helpers in embed.h

The embed.h macro had a default of 0x03080000. Its legacy branch cannot run when
the minimum is 3.9, so the macro and the branch are gone. Four interpreter test cases
were behind that macro. They now always run.

I also renamed the Add program dir to path pre-PyConfig test case to
Add program dir to path without PyConfig, because no pre-PyConfig path is left.

Suggested changelog entry:

  • Support for Python 3.8 was removed. The minimum supported version is now Python 3.9.

📚 Documentation preview 📚: https://pybind11--6110.org.readthedocs.build/

henryiii added 3 commits July 24, 2026 23:46
The minimum supported version is now Python 3.9. pybind11 v3.0 was the last
release that supports Python 3.8. The deprecation note said that support goes
away in 3.1.

Remove the code paths that this makes dead:

- the `_PyObject_Vectorcall` fallback in `cast.h`
- the `frame->f_code` and `frame->f_back` fallbacks in `pytypes.h`
- the `PyFrame_FastToLocals` path in `get_type_override`
- the conditional `Py_VISIT(Py_TYPE(self))` in `tp_traverse`
- `PYBIND11_PYCONFIG_SUPPORT_PY_VERSION_HEX`, the pre-PyConfig interpreter
  init, and the `widen_chars` helpers in `embed.h`

Assisted-by: ClaudeCode:claude-opus-5
The AppVeyor job set `PYTHON: 38`, which makes the path `C:\Python38`.
The image gives Python 3.9.13 as `C:\Python39`.

Assisted-by: ClaudeCode:claude-opus-5
Python 3.9 is the new minimum, so MSVC 2017 is no longer needed. Raise the
compile-time floor to _MSC_VER 1920 and remove the workarounds that only
applied below it: std::launder, fold expressions, weak_from_this, aligned
new/delete, the C4100 warning helper, and the func_handle syntax error.

AppVeyor now builds with Visual Studio 2019.

Assisted-by: ClaudeCode:claude-opus-5
@henryiii henryiii changed the title feat!: drop support for Python 3.8 feat!: drop support for Python 3.8, MSVC 2017 Jul 25, 2026
henryiii added 6 commits July 25, 2026 00:44
CMake 4 has no FindPythonLibs, so pybind11 uses FindPython. FindPython reads
the registry before PATH and selected `C:\Python314-x64`, but the test packages
go into the Python on PATH. Pass `Python_ROOT_DIR` to name the correct one.

Also set `CMAKE_ARCH`. It was never set, so the architecture came from the
generator. Visual Studio 2017 defaults to Win32, but Visual Studio 2019
defaults to x64, which made this x86 job build 64-bit code.

Assisted-by: ClaudeCode:claude-opus-5
The build compiled but failed to link with LNK1104 on a bare `python39.lib`.
That name comes from the `#pragma comment(lib, ...)` in pyconfig.h, so the
linker needs the directory. CMake 4 has no FindPythonLibs, and FindPython does
not add it for this Debug x86 build. Put it on LIB instead.

The directory listing is temporary, to confirm the library is present.

Assisted-by: ClaudeCode:claude-opus-5
The image ships python39_d.lib next to python39.lib, so FindPython picks the
debug import library for a Debug build. pybind11 undefines _DEBUG around
Python.h, so pyconfig.h asks for python39.lib instead and the link failed with
LNK1104. Name the release library for the debug slot.

Setting LIB does not work, because MSBuild replaces it from the toolset, and it
would link both import libraries.

Assisted-by: ClaudeCode:claude-opus-5
Revert the two attempted fixes. Neither changed the failure: setting LIB does
not survive MSBuild, and naming the release library for Python_LIBRARY_DEBUG
had no effect.

Print the Python cache entries and the link settings of a generated project
file instead, to see what the linker really gets. Temporary.

Assisted-by: ClaudeCode:claude-opus-5
The generated project file linked C:\Python39\libs\python39_d.lib in the Debug
configuration, because the image ships debug binaries next to the release ones.
pybind11 undefines _DEBUG around Python.h, so pyconfig.h asks for python39.lib
in a #pragma comment(lib), which nothing on the link line satisfies and no
library directory holds. Map Debug to the release artifacts.

Assisted-by: ClaudeCode:claude-opus-5
Assisted-by: ClaudeCode:claude-opus-5
@henryiii

Copy link
Copy Markdown
Collaborator Author

🤖 AI text below 🤖

Why AppVeyor failed

The job compiled, then failed to link every module:

LINK : fatal error LNK1104: cannot open file 'python39.lib'

The AppVeyor image has python39_d.lib next to python39.lib. FindPython therefore used the debug import library for the Debug configuration:

Debug:   <AdditionalDependencies>C:\Python39\libs\python39_d.lib;kernel32.lib;...
Release: <AdditionalDependencies>C:\Python39\libs\python39.lib;kernel32.lib;...
         <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>

pybind11 undefines _DEBUG around Python.h, so pyconfig.h asks for the release library in a #pragma comment(lib, "python39.lib"). The linker satisfies such a request for free only if a library of that name is already on the link line. In Release it is. In Debug it is not, and there is no library directory to search.

This is new because the Visual Studio 2019 image has CMake 4.1, which has no FindPythonLibs. The build now uses FindPython. The Visual Studio 2017 job used the classic module, which took the release library. GitHub Actions does not show the problem, because setup-python installs no _d library.

The fix

One flag, so Debug uses the release artifacts of imported targets:

-DCMAKE_MAP_IMPORTED_CONFIG_DEBUG=Release

AppVeyor is green: Debug links python39.lib, 1256 tests pass, and the C++ tests give 25 cases with 11285 assertions.

Follow-up, not in this PR

The same mismatch can hit users. An MSVC Debug build against a Python installation that has the optional debug binaries links pythonXY_d.lib, but pybind11 builds for the release ABI. A fix in tools/pybind11NewTools.cmake needs care, because MAP_IMPORTED_CONFIG_DEBUG on the module target applies to all imported dependencies of that target, not only Python.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant