|
| 1 | +# gh-116869: Build a basic C test extension to check that the Python C API |
| 2 | +# does not emit C compiler warnings. |
| 3 | + |
| 4 | +import os.path |
| 5 | +import shutil |
| 6 | +import subprocess |
| 7 | +import sysconfig |
| 8 | +import unittest |
| 9 | +from test import support |
| 10 | + |
| 11 | + |
| 12 | +SOURCE = os.path.join(os.path.dirname(__file__), 'extension.c') |
| 13 | +SETUP = os.path.join(os.path.dirname(__file__), 'setup.py') |
| 14 | + |
| 15 | + |
| 16 | +# gh-110119: pip does not currently support 't' in the ABI flag use by |
| 17 | +# --disable-gil builds. Once it does, we can remove this skip. |
| 18 | +@unittest.skipIf(support.Py_GIL_DISABLED, |
| 19 | + 'test does not work with --disable-gil') |
| 20 | +@support.requires_subprocess() |
| 21 | +@support.requires_resource('cpu') |
| 22 | +class TestExt(unittest.TestCase): |
| 23 | + def test_build_c99(self): |
| 24 | + self.check_build('c99', '_test_c99_ext') |
| 25 | + |
| 26 | + def test_build_c11(self): |
| 27 | + self.check_build('c11', '_test_c11_ext') |
| 28 | + |
| 29 | + # With MSVC, the linker fails with: cannot open file 'python311.lib' |
| 30 | + # https://github.com/python/cpython/pull/32175#issuecomment-1111175897 |
| 31 | + @unittest.skipIf(support.MS_WINDOWS, 'test fails on Windows') |
| 32 | + # Building and running an extension in clang sanitizing mode is not |
| 33 | + # straightforward |
| 34 | + @unittest.skipIf( |
| 35 | + '-fsanitize' in (sysconfig.get_config_var('PY_CFLAGS') or ''), |
| 36 | + 'test does not work with analyzing builds') |
| 37 | + # the test uses venv+pip: skip if it's not available |
| 38 | + @support.requires_venv_with_pip() |
| 39 | + def check_build(self, clang_std, extension_name): |
| 40 | + venv_dir = 'env' |
| 41 | + with support.setup_venv_with_pip_setuptools_wheel(venv_dir) as python_exe: |
| 42 | + self._check_build(clang_std, extension_name, python_exe) |
| 43 | + |
| 44 | + def _check_build(self, clang_std, extension_name, python_exe): |
| 45 | + pkg_dir = 'pkg' |
| 46 | + os.mkdir(pkg_dir) |
| 47 | + shutil.copy(SETUP, os.path.join(pkg_dir, os.path.basename(SETUP))) |
| 48 | + shutil.copy(SOURCE, os.path.join(pkg_dir, os.path.basename(SOURCE))) |
| 49 | + |
| 50 | + def run_cmd(operation, cmd): |
| 51 | + env = os.environ.copy() |
| 52 | + env['CPYTHON_TEST_STD'] = clang_std |
| 53 | + env['CPYTHON_TEST_EXT_NAME'] = extension_name |
| 54 | + if support.verbose: |
| 55 | + print('Run:', ' '.join(cmd)) |
| 56 | + subprocess.run(cmd, check=True, env=env) |
| 57 | + else: |
| 58 | + proc = subprocess.run(cmd, |
| 59 | + env=env, |
| 60 | + stdout=subprocess.PIPE, |
| 61 | + stderr=subprocess.STDOUT, |
| 62 | + text=True) |
| 63 | + if proc.returncode: |
| 64 | + print(proc.stdout, end='') |
| 65 | + self.fail( |
| 66 | + f"{operation} failed with exit code {proc.returncode}") |
| 67 | + |
| 68 | + # Build and install the C extension |
| 69 | + cmd = [python_exe, '-X', 'dev', |
| 70 | + '-m', 'pip', 'install', '--no-build-isolation', |
| 71 | + os.path.abspath(pkg_dir)] |
| 72 | + run_cmd('Install', cmd) |
| 73 | + |
| 74 | + # Do a reference run. Until we test that running python |
| 75 | + # doesn't leak references (gh-94755), run it so one can manually check |
| 76 | + # -X showrefcount results against this baseline. |
| 77 | + cmd = [python_exe, |
| 78 | + '-X', 'dev', |
| 79 | + '-X', 'showrefcount', |
| 80 | + '-c', 'pass'] |
| 81 | + run_cmd('Reference run', cmd) |
| 82 | + |
| 83 | + # Import the C extension |
| 84 | + cmd = [python_exe, |
| 85 | + '-X', 'dev', |
| 86 | + '-X', 'showrefcount', |
| 87 | + '-c', f"import {extension_name}"] |
| 88 | + run_cmd('Import', cmd) |
| 89 | + |
| 90 | + |
| 91 | +if __name__ == "__main__": |
| 92 | + unittest.main() |
0 commit comments