gh-127405: Add ABIFLAGS to sysconfig variables on Windows (GH-131799)

This commit is contained in:
Xuehai Pan 2025-04-11 23:19:03 +08:00 committed by GitHub
parent 9ded6f0830
commit 26ae05e95c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 99 additions and 7 deletions

View File

@ -1078,6 +1078,14 @@ sys.monitoring
* Two new events are added: :monitoring-event:`BRANCH_LEFT` and
:monitoring-event:`BRANCH_RIGHT`. The ``BRANCH`` event is deprecated.
sysconfig
---------
* Add ``ABIFLAGS`` key to :func:`sysconfig.get_config_vars` on Windows.
(Contributed by Xuehai Pan in :gh:`131799`.)
threading
---------
@ -1085,6 +1093,7 @@ threading
to :attr:`threading.Thread.name`.
(Contributed by Victor Stinner in :gh:`59705`.)
tkinter
-------

View File

@ -401,9 +401,20 @@ def _init_non_posix(vars):
vars['BINLIBDEST'] = get_path('platstdlib')
vars['INCLUDEPY'] = get_path('include')
# Add EXT_SUFFIX, SOABI, and Py_GIL_DISABLED
# Add EXT_SUFFIX, SOABI, Py_DEBUG, and Py_GIL_DISABLED
vars.update(_sysconfig.config_vars())
# NOTE: ABIFLAGS is only an emulated value. It is not present during build
# on Windows. sys.abiflags is absent on Windows and vars['abiflags']
# is already widely used to calculate paths, so it should remain an
# empty string.
vars['ABIFLAGS'] = ''.join(
(
't' if vars['Py_GIL_DISABLED'] else '',
'_d' if vars['Py_DEBUG'] else '',
),
)
vars['LIBDIR'] = _safe_realpath(os.path.join(get_config_var('installed_base'), 'libs'))
if hasattr(sys, 'dllhandle'):
dllhandle = _winapi.GetModuleFileName(sys.dllhandle)

View File

@ -724,6 +724,8 @@ class SysModuleTest(unittest.TestCase):
self.assertIn(sys.float_repr_style, ('short', 'legacy'))
if not sys.platform.startswith('win'):
self.assertIsInstance(sys.abiflags, str)
else:
self.assertFalse(hasattr(sys, 'abiflags'))
def test_thread_info(self):
info = sys.thread_info

View File

@ -9,6 +9,7 @@ import json
import textwrap
from copy import copy
from test import support
from test.support import (
captured_stdout,
is_android,
@ -455,20 +456,20 @@ class TestSysConfig(unittest.TestCase, VirtualEnvironmentMixin):
library = sysconfig.get_config_var('LIBRARY')
ldlibrary = sysconfig.get_config_var('LDLIBRARY')
major, minor = sys.version_info[:2]
if sys.platform == 'win32':
self.assertTrue(library.startswith(f'python{major}{minor}'))
self.assertTrue(library.endswith('.dll'))
abiflags = sysconfig.get_config_var('ABIFLAGS')
if sys.platform.startswith('win'):
self.assertEqual(library, f'python{major}{minor}{abiflags}.dll')
self.assertEqual(library, ldlibrary)
elif is_apple_mobile:
framework = sysconfig.get_config_var('PYTHONFRAMEWORK')
self.assertEqual(ldlibrary, f"{framework}.framework/{framework}")
else:
self.assertTrue(library.startswith(f'libpython{major}.{minor}'))
self.assertTrue(library.endswith('.a'))
self.assertStartsWith(library, f'libpython{major}.{minor}')
self.assertEndsWith(library, '.a')
if sys.platform == 'darwin' and sys._framework:
self.skipTest('gh-110824: skip LDLIBRARY test for framework build')
else:
self.assertTrue(ldlibrary.startswith(f'libpython{major}.{minor}'))
self.assertStartsWith(ldlibrary, f'libpython{major}.{minor}')
@unittest.skipUnless(sys.platform == "darwin", "test only relevant on MacOSX")
@requires_subprocess()
@ -592,6 +593,63 @@ class TestSysConfig(unittest.TestCase, VirtualEnvironmentMixin):
suffix = sysconfig.get_config_var('EXT_SUFFIX')
self.assertTrue(suffix.endswith('-darwin.so'), suffix)
def test_always_set_py_debug(self):
self.assertIn('Py_DEBUG', sysconfig.get_config_vars())
Py_DEBUG = sysconfig.get_config_var('Py_DEBUG')
self.assertIn(Py_DEBUG, (0, 1))
self.assertEqual(Py_DEBUG, support.Py_DEBUG)
def test_always_set_py_gil_disabled(self):
self.assertIn('Py_GIL_DISABLED', sysconfig.get_config_vars())
Py_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED')
self.assertIn(Py_GIL_DISABLED, (0, 1))
self.assertEqual(Py_GIL_DISABLED, support.Py_GIL_DISABLED)
def test_abiflags(self):
# If this test fails on some platforms, maintainers should update the
# test to make it pass, rather than changing the definition of ABIFLAGS.
self.assertIn('abiflags', sysconfig.get_config_vars())
self.assertIn('ABIFLAGS', sysconfig.get_config_vars())
abiflags = sysconfig.get_config_var('abiflags')
ABIFLAGS = sysconfig.get_config_var('ABIFLAGS')
self.assertIsInstance(abiflags, str)
self.assertIsInstance(ABIFLAGS, str)
self.assertIn(abiflags, ABIFLAGS)
if os.name == 'nt':
self.assertEqual(abiflags, '')
if not sys.platform.startswith('win'):
valid_abiflags = ('', 't', 'd', 'td')
else:
# Windows uses '_d' rather than 'd'; see also test_abi_debug below
valid_abiflags = ('', 't', '_d', 't_d')
self.assertIn(ABIFLAGS, valid_abiflags)
def test_abi_debug(self):
ABIFLAGS = sysconfig.get_config_var('ABIFLAGS')
if support.Py_DEBUG:
self.assertIn('d', ABIFLAGS)
else:
self.assertNotIn('d', ABIFLAGS)
# The 'd' flag should always be the last one on Windows.
# On Windows, the debug flag is used differently with a underscore prefix.
# For example, `python{X}.{Y}td` on Unix and `python{X}.{Y}t_d.exe` on Windows.
if support.Py_DEBUG and sys.platform.startswith('win'):
self.assertEndsWith(ABIFLAGS, '_d')
def test_abi_thread(self):
abi_thread = sysconfig.get_config_var('abi_thread')
ABIFLAGS = sysconfig.get_config_var('ABIFLAGS')
self.assertIsInstance(abi_thread, str)
if support.Py_GIL_DISABLED:
self.assertEqual(abi_thread, 't')
self.assertIn('t', ABIFLAGS)
else:
self.assertEqual(abi_thread, '')
self.assertNotIn('t', ABIFLAGS)
@requires_subprocess()
def test_makefile_overwrites_config_vars(self):
script = textwrap.dedent("""

View File

@ -1402,6 +1402,7 @@ Todd R. Palmer
Juan David Ibáñez Palomar
Nicola Palumbo
Jan Palus
Xuehai Pan
Yongzhi Pan
Martin Panter
Mathias Panzenböck

View File

@ -0,0 +1 @@
Add ``ABIFLAGS`` to :func:`sysconfig.get_config_vars` on Windows. Patch by Xuehai Pan.

View File

@ -67,6 +67,16 @@ _sysconfig_config_vars_impl(PyObject *module)
return NULL;
}
#ifdef Py_DEBUG
PyObject *py_debug = _PyLong_GetOne();
#else
PyObject *py_debug = _PyLong_GetZero();
#endif
if (PyDict_SetItemString(config, "Py_DEBUG", py_debug) < 0) {
Py_DECREF(config);
return NULL;
}
return config;
}