diff --git a/test cases/python/12 extmodule limited api ft/limited.c b/test cases/python/12 extmodule limited api ft/limited.c new file mode 100644 index 000000000000..e9e95726b3ed --- /dev/null +++ b/test cases/python/12 extmodule limited api ft/limited.c @@ -0,0 +1,36 @@ +#include + +#ifndef Py_LIMITED_API +#error Py_LIMITED_API must be defined. +#elif Py_LIMITED_API != 0x030f0000 +#error Wrong value for Py_LIMITED_API +#endif + +static PyObject * +hello(PyObject * Py_UNUSED(self), PyObject * Py_UNUSED(args)) { + return PyUnicode_FromString("hello world"); +} + +static struct PyMethodDef methods[] = { + { "hello", hello, METH_NOARGS, NULL }, + { NULL, NULL, 0, NULL }, +}; + +PyABIInfo_VAR(abi_info); + +static PySlot limited_module_slots[] = { + PySlot_STATIC_DATA(Py_mod_name, "limited"), + PySlot_STATIC_DATA(Py_mod_methods, methods), + PySlot_STATIC_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), + PySlot_STATIC_DATA(Py_mod_abi, &abi_info), + PySlot_END, +}; + +PyMODEXPORT_FUNC PyModExport_limited(void) { + return limited_module_slots; +} + +PyMODINIT_FUNC PyInit_limited(void) { + PyErr_SetString(PyExc_NotImplementedError, "legacy init not supported"); + return NULL; +} diff --git a/test cases/python/12 extmodule limited api ft/meson.build b/test cases/python/12 extmodule limited api ft/meson.build new file mode 100644 index 000000000000..d77a12a23099 --- /dev/null +++ b/test cases/python/12 extmodule limited api ft/meson.build @@ -0,0 +1,22 @@ +project('Python limited api ft', 'c', + default_options : ['buildtype=release', 'werror=true']) + +py_mod = import('python') +py = py_mod.find_installation() + +if py.language_version().version_compare('<3.15') + error('MESON_SKIP_TEST: Py_TARGET_ABI3T is supported since 3.15.0a8') +endif + +ext_mod_limited = py.extension_module('limited', + 'limited.c', + limited_api: '3.15', + install: true, +) + +test('load-test', + py, + args: [files('test_limited.py')], + env: { 'PYTHONPATH': meson.current_build_dir() }, + workdir: meson.current_source_dir() +) diff --git a/test cases/python/12 extmodule limited api ft/test.json b/test cases/python/12 extmodule limited api ft/test.json new file mode 100644 index 000000000000..5a53d5218e39 --- /dev/null +++ b/test cases/python/12 extmodule limited api ft/test.json @@ -0,0 +1,6 @@ +{ + "installed": [ + {"type": "python_limited_lib", "file": "usr/@PYTHON_PLATLIB@/limited"}, + {"type": "py_limited_implib", "file": "usr/@PYTHON_PLATLIB@/limited"} + ] +} diff --git a/test cases/python/12 extmodule limited api ft/test_limited.py b/test cases/python/12 extmodule limited api ft/test_limited.py new file mode 100644 index 000000000000..fcbf67b536e1 --- /dev/null +++ b/test cases/python/12 extmodule limited api ft/test_limited.py @@ -0,0 +1,6 @@ +from limited import hello + +def test_hello(): + assert hello() == "hello world" + +test_hello() diff --git a/test cases/python/9 extmodule limited api/meson.build b/test cases/python/9 extmodule limited api/meson.build index 95851241e1d2..2f19292f847a 100644 --- a/test cases/python/9 extmodule limited api/meson.build +++ b/test cases/python/9 extmodule limited api/meson.build @@ -4,8 +4,8 @@ project('Python limited api', 'c', py_mod = import('python') py = py_mod.find_installation() -if py.get_variable('Py_GIL_DISABLED', 0) == 1 and py.language_version().version_compare('<3.15') - error('MESON_SKIP_TEST: Freethreading Python does not support limited API') +if py.get_variable('Py_GIL_DISABLED', 0) == 1 + error('MESON_SKIP_TEST: Freethreading Python does not support (old) limited API') endif ext_mod_limited = py.extension_module('limited', diff --git a/unittests/pythontests.py b/unittests/pythontests.py index a24f776cf2d2..daabfd612d3b 100644 --- a/unittests/pythontests.py +++ b/unittests/pythontests.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: Apache-2.0 # Copyright 2016-2021 The Meson development team -import glob, os, pathlib, shutil, subprocess, sys, unittest +import glob, os, pathlib, shutil, subprocess, sys, sysconfig, unittest from run_tests import ( Backend @@ -121,3 +121,34 @@ def test_limited_api_linked_correct_lib(self): self.assertIn(limited_dep_name, output.decode()) else: raise self.skipTest('Test needs either dumpbin(MSVC) or objdump(mingw).') + + def test_abi3t_linked_correct_lib(self): + if sysconfig.get_config_var('Py_GIL_DISABLED') != 1: + return self.skipTest('Test only run with freethreading Python') + if not is_windows(): + return self.skipTest('Test only run on Windows.') + + testdir = os.path.join(self.src_root, 'test cases', 'python', '12 extmodule limited api ft') + + self.init(testdir) + self.build() + + from importlib.machinery import EXTENSION_SUFFIXES + limited_suffix = EXTENSION_SUFFIXES[1] + + limited_library_path = os.path.join(self.builddir, f'limited{limited_suffix}') + self.assertPathExists(limited_library_path) + + limited_dep_name = 'python3t.dll' + if shutil.which('dumpbin'): + # MSVC + output = subprocess.check_output(['dumpbin', '/DEPENDENTS', limited_library_path], + stderr=subprocess.STDOUT) + self.assertIn(limited_dep_name, output.decode()) + elif shutil.which('objdump'): + # mingw + output = subprocess.check_output(['objdump', '-p', limited_library_path], + stderr=subprocess.STDOUT) + self.assertIn(limited_dep_name, output.decode()) + else: + raise self.skipTest('Test needs either dumpbin(MSVC) or objdump(mingw).')