1- # gh-116869: Build a basic C test extension to check that the Python C API
2- # does not emit C compiler warnings.
1+ # gh-116869: Build a C/C++ test extension to check that the Python C API does
2+ # not emit compiler warnings.
33#
44# The Python C API must be compatible with building
55# with the -Werror=declaration-after-statement compiler flag.
66
77import os .path
8+ import platform
89import shlex
910import shutil
1011import subprocess
11- import sysconfig
1212import sys
13+ import sysconfig
1314import unittest
1415from test import support
16+ from test .support import os_helper
17+
18+
19+ if not support .has_subprocess_support :
20+ raise unittest .SkipTest ("requires subprocess support" )
1521
1622
23+ SOURCE_DIR = os .path .dirname (__file__ )
1724SOURCES = [
18- os .path .join (os .path .dirname (__file__ ), 'extension.c' ),
25+ os .path .join (SOURCE_DIR , 'extension.c' ),
26+ os .path .join (SOURCE_DIR , 'extension.cpp' ),
27+ os .path .join (SOURCE_DIR , 'setup.py' ),
1928]
20- SETUP = os . path . join ( os . path . dirname ( __file__ ), 'setup.py' )
29+ MSVC = support . MS_WINDOWS
2130
2231
2332# With MSVC on a debug build, the linker fails with: cannot open file
2433# 'python311.lib', it should look 'python311_d.lib'.
25- @unittest .skipIf (support . MS_WINDOWS and support .Py_DEBUG ,
34+ @unittest .skipIf (MSVC and support .Py_DEBUG ,
2635 'test fails on Windows debug build' )
2736# Building and running an extension in clang sanitizing mode is not
2837# straightforward
3443@support .requires_resource ('cpu' )
3544class BaseTests :
3645 TEST_INTERNAL_C_API = False
37-
38- # Default build with no options
39- def test_build (self ):
40- self .check_build ('_test_cext' )
46+ LANGUAGE = None
4147
4248 def check_build (self , extension_name , std = None , limited = False ,
43- abi3t = False ):
44- venv_dir = 'env'
45- with support .setup_venv_with_pip_setuptools (venv_dir ) as python_exe :
46- self ._check_build (extension_name , python_exe ,
47- std = std , limited = limited ,
48- abi3t = abi3t )
49-
50- def _check_build (self , extension_name , python_exe , std , limited ,
51- abi3t ):
49+ abi3t = False , extra_cflags = None ):
50+ if self .LANGUAGE == 'C++' and not std and sys .platform == 'darwin' :
51+ # Old Apple clang++ default C++ std is gnu++98, use C++11 instead
52+ std = 'c++11'
53+
5254 pkg_dir = 'pkg'
5355 os .mkdir (pkg_dir )
54- shutil .copy (SETUP , os .path .join (pkg_dir , os .path .basename (SETUP )))
56+ self .addCleanup (os_helper .rmtree , pkg_dir )
57+
5558 for source in SOURCES :
5659 dest = os .path .join (pkg_dir , os .path .basename (source ))
5760 shutil .copy (source , dest )
5861
5962 def run_cmd (operation , cmd ):
6063 env = os .environ .copy ()
64+ env ['CPYTHON_TEST_EXT_NAME' ] = extension_name
65+ env ['CPYTHON_TEST_LANG' ] = self .LANGUAGE
6166 if std :
6267 env ['CPYTHON_TEST_STD' ] = std
6368 if limited :
6469 env ['CPYTHON_TEST_LIMITED' ] = '1'
6570 if abi3t :
6671 env ['CPYTHON_TEST_ABI3T' ] = '1'
67- if support .MS_WINDOWS and sysconfig .is_python_build ():
68- env ['CPYTHON_EXTRA_INCDIRS' ] = os .path .split (sysconfig .get_config_h_filename ())[0 ]
69- env ['CPYTHON_EXTRA_LIBDIRS' ] = os .path .split (sys .executable )[0 ]
70- env ['CPYTHON_TEST_EXT_NAME' ] = extension_name
71- env ['TEST_INTERNAL_C_API' ] = str (int (self .TEST_INTERNAL_C_API ))
72+ if MSVC and sysconfig .is_python_build ():
73+ env ['CPYTHON_TEST_EXTRA_INCDIRS' ] = os .path .split (sysconfig .get_config_h_filename ())[0 ]
74+ env ['CPYTHON_TEST_EXTRA_LIBDIRS' ] = os .path .split (sys .executable )[0 ]
75+ env ['CPYTHON_TEST_INTERNAL_C_API' ] = str (int (self .TEST_INTERNAL_C_API ))
76+ if extra_cflags :
77+ env ['CPYTHON_TEST_EXTRA_CFLAGS' ] = extra_cflags
7278 if support .verbose :
7379 print ('Run:' , ' ' .join (map (shlex .quote , cmd )))
7480 subprocess .run (cmd , check = True , env = env )
@@ -85,6 +91,7 @@ def run_cmd(operation, cmd):
8591 f"{ operation } failed with exit code { proc .returncode } " )
8692
8793 # Build and install the C extension
94+ python_exe = PYTHON_EXE
8895 cmd = [python_exe , '-X' , 'dev' ,
8996 '-m' , 'pip' , 'install' , '--no-build-isolation' ,
9097 os .path .abspath (pkg_dir )]
@@ -101,39 +108,109 @@ def run_cmd(operation, cmd):
101108 '-c' , 'pass' ]
102109 run_cmd ('Reference run' , cmd )
103110
104- # Import the C extension
111+ # Import the C/C++ extension
105112 cmd = [python_exe ,
106113 '-X' , 'dev' ,
107114 '-X' , 'showrefcount' ,
108115 '-c' , f"import { extension_name } " ]
109116 run_cmd ('Import' , cmd )
110117
111118
112- class TestPublicCAPI (BaseTests , unittest .TestCase ):
119+ class TestPublicC (BaseTests , unittest .TestCase ):
120+ LANGUAGE = 'C'
121+
122+ # Default build with no options
123+ def test_build (self ):
124+ self .check_build ('_test_cext' )
125+
126+ @unittest .skipIf (MSVC , "MSVC doesn't support /std:c99" )
127+ def test_build_c99 (self ):
128+ # In public docs, we say C API is compatible with C11. However,
129+ # in practice we do maintain C99 compatibility in public headers.
130+ # Please ask the C API WG before adding a new C11-only feature.
131+ self .check_build ('_test_cext_c99' , std = 'c99' )
132+
133+ def test_build_c11 (self ):
134+ self .check_build ('_test_cext_c11' , std = 'c11' )
135+
113136 def test_build_limited (self ):
114- self .check_build ('_test_limited_cext ' , limited = True )
137+ self .check_build ('_test_cext_limited ' , limited = True )
115138
116139 def test_build_limited_c11 (self ):
117- self .check_build ('_test_limited_c11_cext ' , limited = True , std = 'c11' )
140+ self .check_build ('_test_cext_limited_c11 ' , limited = True , std = 'c11' )
118141
119- def test_build_c11 (self ):
120- self .check_build ('_test_c11_cext' , std = 'c11' )
142+ def test_build_abi3t (self ):
143+ # Test with Py_TARGET_ABI3T
144+ self .check_build ('_test_cext_abi3t' , abi3t = True )
145+
146+
147+ class TestPublicCpp (BaseTests , unittest .TestCase ):
148+ LANGUAGE = 'C++'
149+
150+ def test_build (self ):
151+ self .check_build ('_test_cppext' )
152+
153+ def test_build_cpp03 (self ):
154+ # In public docs, we say C API is compatible with C++11. However,
155+ # in practice we do maintain C++03 compatibility in public headers.
156+ # Please ask the C API WG before adding a new C++11-only feature.
157+ self .check_build ('_test_cppext_cpp03' , std = 'c++03' )
158+
159+ @unittest .skipIf (MSVC , "MSVC doesn't support /std:c++11" )
160+ def test_build_cpp11 (self ):
161+ self .check_build ('_test_cppext_cpp11' , std = 'c++11' )
162+
163+ # Only test C++14 on MSVC.
164+ # On s390x RHEL7, GCC 4.8.5 doesn't support C++14.
165+ @unittest .skipIf (not MSVC , "need MSVC" )
166+ def test_build_cpp14 (self ):
167+ self .check_build ('_test_cppext_cpp14' , std = 'c++14' )
168+
169+ # Test that headers compile with Intel asm syntax, which may conflict
170+ # with inline assembly in free-threading headers that use AT&T syntax.
171+ @unittest .skipIf (MSVC , "MSVC doesn't support -masm=intel" )
172+ @unittest .skipUnless (platform .machine () in ('x86_64' , 'i686' , 'AMD64' ),
173+ "x86-specific flag" )
174+ def test_build_intel_asm (self ):
175+ self .check_build ('_test_cppext_intel_asm' , extra_cflags = '-masm=intel' )
176+
177+ def test_build_limited (self ):
178+ self .check_build ('_test_cppext_limited' , limited = True )
179+
180+ def test_build_limited_cpp03 (self ):
181+ self .check_build ('_test_cppext_limited_cpp03' , std = 'c++03' , limited = True )
121182
122183 def test_build_abi3t (self ):
123184 # Test with Py_TARGET_ABI3T
124- self .check_build ('_test_abi3t ' , abi3t = True )
185+ self .check_build ('_test_cppext_abi3t ' , abi3t = True )
125186
126- @unittest .skipIf (support .MS_WINDOWS , "MSVC doesn't support /std:c99" )
127- def test_build_c99 (self ):
128- # In public docs, we say C API is compatible with C11. However,
129- # in practice we do maintain C99 compatibility in public headers.
130- # Please ask the C API WG before adding a new C11-only feature.
131- self .check_build ('_test_c99_cext' , std = 'c99' )
187+
188+ class TestInteralC (BaseTests , unittest .TestCase ):
189+ LANGUAGE = 'C'
190+ TEST_INTERNAL_C_API = True
191+
192+ # Default build with no options
193+ def test_build (self ):
194+ self .check_build ('_test_cext_internal' )
132195
133196
134- class TestInteralCAPI (BaseTests , unittest .TestCase ):
197+ class TestInteralCpp (BaseTests , unittest .TestCase ):
198+ LANGUAGE = 'C++'
135199 TEST_INTERNAL_C_API = True
136200
201+ def test_build (self ):
202+ self .check_build ('_test_cppext_internal' )
203+
204+
205+ def setUpModule ():
206+ global VENV_CONTEXT , PYTHON_EXE
207+ VENV_CONTEXT = support .setup_venv_with_pip_setuptools ('env' )
208+ PYTHON_EXE = VENV_CONTEXT .__enter__ ()
209+
210+
211+ def tearDownModule ():
212+ VENV_CONTEXT .__exit__ (None , None , None )
213+
137214
138215if __name__ == "__main__" :
139216 unittest .main ()
0 commit comments