`FindPython` option to skip debug binaries on Windows

Hi! There’s an issue when trying to build debug version of some Python extension on Windows - it require… debug Python libraries (e.g. python_d.exe , python311_d.dll, python311_d.lib)

They’re becoming less accessible - the only way to get them, outside of compiling them yourself, is official Python official installer which is not very good for portable installations and it’s now deprecated (it will be gone in 3.16+), in the future Windows installation will switch to Python Installation Manager which won’t have debug binaries.
And if you have them, the chances are that you don’t actually want to use them - because it creates more problems than solves, since then you also need to make sure all other Python modules you use are in debug mode too (e.g. numpy_d.pyd instead of numpy.pyd) and there’s really no simple way to get them.
So debug Python binaries really needed if you want to either debug Python itself or part of your extension that interacts with Python (e.g. debugging reference counts, etc). But more typical scenario is that you need debug verison of your extension to debug it’s main code, without getting deep into Python internals.

On Unix using Python Debug API requires Py_DEBUG option to be set, so using debug Python is deliberate. But on Windows it’s set automatically on _DEBUG, which is set automatically when /MDd flag is used during compilation and this flag is used in any default Windows Debug build to link VCRUNTIME140D.dll.

To go arround this users either don’t do full debug builds or do some # undef _DEBUG hacks before including Python.h, e.g. code from swig:

Since Python 3.9 its debug and release ABI became mostly compatible, but there are two issues left:

  • On Windows it’s automatically linking against python315_d if Py_DEBUG is set. Which is annoying practice and general and probably mostly historical. Good news that in Python 3.14 Py_NO_LINK_LIB flag was added to avoid this behaviour.
  • Py_DEBUG also automatically implies Py_REF_DEBUG which includes couple symbols for debugging ref count and they’re not available in release binaries leading to issues on linking. As of Pyhon 3.14 there’s no way to avoid it.

From discussion on Python forum and tests, Py_REF_DEBUG is the last thing preventing linking against release binaries on Windows, so I plan to submit a PR to CPython to add some kind of Py_WIN_NO_PY_DEBUG or Py_NO_REF_DEBUG flag to avoid this behaviour.

So in theory in Python 3.15 it will be finally possible to use release binaries for debug builds.

And I wanted to propose adding some kind flag to cmake’s FindPython to set those automatically - e.g. before find_package(Python) to set Python_WIN_NO_PY_DEBUG that would

  • define Py_NO_LINK_LIB and Py_WIN_NO_PY_DEBUG / Py_NO_REF_DEBUG for Python targets.
  • would avoid setting IMPORTED_IMPLIB_DEBUG / IMPORTED_LOCATION_DEBUG.
  • avoid setting debug postfix for targets.

Or maybe Py_NO_LINK_LIB should be separated to another option, not sure.

Anyways, issue should be first fixed upstream of course, but wanted to ask for your thoughts if this makes sense or maybe there some other caveats to consider.

FYI, starting with CMake 3.31.8, flag Py_NO_LINK_LIB is automatically set when python*_add_library() command is used.

Regarding debug library, the various debug artifacts are defined only if the debug library is found. Otherwise, these artifacts are not defined (debug artifacts are optional), so there is no need to introduce some specific configuration for that.

1 Like

Missed it, that’s very neat!

Understandable, but still - user might have release and debug Python binaries and both of them would be found by FindPython, but it still might be not desirable to use debug version of Python for the extensions build, because of all the downsides it has.

Though it’s more rare - most of the time users will indeed have just release binaries. Maybe it would make sense to set hypothetical Python_WIN_NO_PY_DEBUG (that would define Py_WIN_NO_PY_DEBUG) automatically if no debug libraries were found? So it would work for the most of the users seamlessly, without setting additional config variable.