1# gh-91321: Build a basic C test extension to check that the Python C API is 2# compatible with C and does not emit C compiler warnings. 3import os 4import platform 5import shlex 6import sys 7import sysconfig 8from test import support 9 10from setuptools import setup, Extension 11 12 13SOURCE = 'extension.c' 14if not support.MS_WINDOWS: 15 # C compiler flags for GCC and clang 16 CFLAGS = [ 17 # The purpose of test_cext extension is to check that building a C 18 # extension using the Python C API does not emit C compiler warnings. 19 '-Werror', 20 ] 21 if not support.Py_GIL_DISABLED: 22 CFLAGS.append( 23 # gh-116869: The Python C API must be compatible with building 24 # with the -Werror=declaration-after-statement compiler flag. 25 '-Werror=declaration-after-statement', 26 ) 27else: 28 # Don't pass any compiler flag to MSVC 29 CFLAGS = [] 30 31 32def main(): 33 std = os.environ.get("CPYTHON_TEST_STD", "") 34 module_name = os.environ["CPYTHON_TEST_EXT_NAME"] 35 limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", "")) 36 37 cflags = list(CFLAGS) 38 cflags.append(f'-DMODULE_NAME={module_name}') 39 40 # Add -std=STD or /std:STD (MSVC) compiler flag 41 if std: 42 if support.MS_WINDOWS: 43 cflags.append(f'/std:{std}') 44 else: 45 cflags.append(f'-std={std}') 46 47 # Remove existing -std or /std options from CC command line. 48 # Python adds -std=c11 option. 49 cmd = (sysconfig.get_config_var('CC') or '') 50 if cmd is not None: 51 if support.MS_WINDOWS: 52 std_prefix = '/std' 53 else: 54 std_prefix = '-std' 55 cmd = shlex.split(cmd) 56 cmd = [arg for arg in cmd if not arg.startswith(std_prefix)] 57 cmd = shlex.join(cmd) 58 # CC env var overrides sysconfig CC variable in setuptools 59 os.environ['CC'] = cmd 60 61 # Define Py_LIMITED_API macro 62 if limited: 63 version = sys.hexversion 64 cflags.append(f'-DPy_LIMITED_API={version:#x}') 65 66 # On Windows, add PCbuild\amd64\ to include and library directories 67 include_dirs = [] 68 library_dirs = [] 69 if support.MS_WINDOWS: 70 srcdir = sysconfig.get_config_var('srcdir') 71 machine = platform.uname().machine 72 pcbuild = os.path.join(srcdir, 'PCbuild', machine) 73 if os.path.exists(pcbuild): 74 # pyconfig.h is generated in PCbuild\amd64\ 75 include_dirs.append(pcbuild) 76 # python313.lib is generated in PCbuild\amd64\ 77 library_dirs.append(pcbuild) 78 print(f"Add PCbuild directory: {pcbuild}") 79 80 # Display information to help debugging 81 for env_name in ('CC', 'CFLAGS'): 82 if env_name in os.environ: 83 print(f"{env_name} env var: {os.environ[env_name]!r}") 84 else: 85 print(f"{env_name} env var: <missing>") 86 print(f"extra_compile_args: {cflags!r}") 87 88 ext = Extension( 89 module_name, 90 sources=[SOURCE], 91 extra_compile_args=cflags, 92 include_dirs=include_dirs, 93 library_dirs=library_dirs) 94 setup(name=f'internal_{module_name}', 95 version='0.0', 96 ext_modules=[ext]) 97 98 99if __name__ == "__main__": 100 main() 101