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
1517
1618
19+ SOURCE_DIR = os .path .dirname (__file__ )
1720SOURCES = [
18- os .path .join (os .path .dirname (__file__ ), 'extension.c' ),
21+ os .path .join (SOURCE_DIR , 'extension.c' ),
22+ os .path .join (SOURCE_DIR , 'extension.cpp' ),
23+ os .path .join (SOURCE_DIR , 'setup.py' ),
1924]
20- SETUP = os . path . join ( os . path . dirname ( __file__ ), 'setup.py' )
25+ MSVC = support . MS_WINDOWS
2126
2227
2328# With MSVC on a debug build, the linker fails with: cannot open file
2429# 'python311.lib', it should look 'python311_d.lib'.
25- @unittest .skipIf (support . MS_WINDOWS and support .Py_DEBUG ,
30+ @unittest .skipIf (MSVC and support .Py_DEBUG ,
2631 'test fails on Windows debug build' )
2732# Building and running an extension in clang sanitizing mode is not
2833# straightforward
3439@support .requires_resource ('cpu' )
3540class BaseTests :
3641 TEST_INTERNAL_C_API = False
37-
38- # Default build with no options
39- def test_build (self ):
40- self .check_build ('_test_cext' )
42+ LANGUAGE = None
4143
4244 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 ):
45+ abi3t = False , extra_cflags = None ):
5246 pkg_dir = 'pkg'
5347 os .mkdir (pkg_dir )
54- shutil .copy (SETUP , os .path .join (pkg_dir , os .path .basename (SETUP )))
48+ self .addCleanup (os_helper .rmtree , pkg_dir )
49+
5550 for source in SOURCES :
5651 dest = os .path .join (pkg_dir , os .path .basename (source ))
5752 shutil .copy (source , dest )
5853
5954 def run_cmd (operation , cmd ):
6055 env = os .environ .copy ()
56+ env ['CPYTHON_TEST_EXT_NAME' ] = extension_name
57+ env ['CPYTHON_TEST_LANG' ] = self .LANGUAGE
6158 if std :
6259 env ['CPYTHON_TEST_STD' ] = std
6360 if limited :
6461 env ['CPYTHON_TEST_LIMITED' ] = '1'
6562 if abi3t :
6663 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 ))
64+ if MSVC and sysconfig .is_python_build ():
65+ env ['CPYTHON_TEST_EXTRA_INCDIRS' ] = os .path .split (sysconfig .get_config_h_filename ())[0 ]
66+ env ['CPYTHON_TEST_EXTRA_LIBDIRS' ] = os .path .split (sys .executable )[0 ]
67+ env ['CPYTHON_TEST_INTERNAL_C_API' ] = str (int (self .TEST_INTERNAL_C_API ))
68+ if extra_cflags :
69+ env ['CPYTHON_TEST_EXTRA_CFLAGS' ] = extra_cflags
7270 if support .verbose :
7371 print ('Run:' , ' ' .join (map (shlex .quote , cmd )))
7472 subprocess .run (cmd , check = True , env = env )
@@ -85,6 +83,7 @@ def run_cmd(operation, cmd):
8583 f"{ operation } failed with exit code { proc .returncode } " )
8684
8785 # Build and install the C extension
86+ python_exe = PYTHON_EXE
8887 cmd = [python_exe , '-X' , 'dev' ,
8988 '-m' , 'pip' , 'install' , '--no-build-isolation' ,
9089 os .path .abspath (pkg_dir )]
@@ -101,39 +100,113 @@ def run_cmd(operation, cmd):
101100 '-c' , 'pass' ]
102101 run_cmd ('Reference run' , cmd )
103102
104- # Import the C extension
103+ # Import the C/C++ extension
105104 cmd = [python_exe ,
106105 '-X' , 'dev' ,
107106 '-X' , 'showrefcount' ,
108107 '-c' , f"import { extension_name } " ]
109108 run_cmd ('Import' , cmd )
110109
111110
112- class TestPublicCAPI (BaseTests , unittest .TestCase ):
111+ class TestPublicC (BaseTests , unittest .TestCase ):
112+ LANGUAGE = 'C'
113+
114+ # Default build with no options
115+ def test_build (self ):
116+ self .check_build ('_test_cext' )
117+
118+ @unittest .skipIf (MSVC , "MSVC doesn't support /std:c99" )
119+ def test_build_c99 (self ):
120+ # In public docs, we say C API is compatible with C11. However,
121+ # in practice we do maintain C99 compatibility in public headers.
122+ # Please ask the C API WG before adding a new C11-only feature.
123+ self .check_build ('_test_cext_c99' , std = 'c99' )
124+
125+ def test_build_c11 (self ):
126+ self .check_build ('_test_cext_c11' , std = 'c11' )
127+
113128 def test_build_limited (self ):
114- self .check_build ('_test_limited_cext ' , limited = True )
129+ self .check_build ('_test_cext_limited ' , limited = True )
115130
116131 def test_build_limited_c11 (self ):
117- self .check_build ('_test_limited_c11_cext ' , limited = True , std = 'c11' )
132+ self .check_build ('_test_cext_limited_c11 ' , limited = True , std = 'c11' )
118133
119- def test_build_c11 (self ):
120- self .check_build ('_test_c11_cext' , std = 'c11' )
134+ def test_build_abi3t (self ):
135+ # Test with Py_TARGET_ABI3T
136+ self .check_build ('_test_cext_abi3t' , abi3t = True )
137+
138+
139+ class TestPublicCpp (BaseTests , unittest .TestCase ):
140+ LANGUAGE = 'C++'
141+
142+ def test_build (self ):
143+ self .check_build ('_test_cppext' )
144+
145+ def test_build_cpp03 (self ):
146+ # In public docs, we say C API is compatible with C++11. However,
147+ # in practice we do maintain C++03 compatibility in public headers.
148+ # Please ask the C API WG before adding a new C++11-only feature.
149+ self .check_build ('_test_cppext_cpp03' , std = 'c++03' )
150+
151+ @unittest .skipIf (MSVC , "MSVC doesn't support /std:c++11" )
152+ def test_build_cpp11 (self ):
153+ self .check_build ('_test_cppext_cpp11' , std = 'c++11' )
154+
155+ # Only test C++14 on MSVC.
156+ # On s390x RHEL7, GCC 4.8.5 doesn't support C++14.
157+ @unittest .skipIf (not MSVC , "need MSVC" )
158+ def test_build_cpp14 (self ):
159+ self .check_build ('_test_cppext_cpp14' , std = 'c++14' )
160+
161+ # Test that headers compile with Intel asm syntax, which may conflict
162+ # with inline assembly in free-threading headers that use AT&T syntax.
163+ @unittest .skipIf (MSVC , "MSVC doesn't support -masm=intel" )
164+ @unittest .skipUnless (platform .machine () in ('x86_64' , 'i686' , 'AMD64' ),
165+ "x86-specific flag" )
166+ def test_build_intel_asm (self ):
167+ self .check_build ('_test_cppext_intel_asm' , extra_cflags = '-masm=intel' )
168+
169+ def test_build_limited (self ):
170+ self .check_build ('_test_cppext_limited' , limited = True )
171+
172+ def test_build_limited_cpp03 (self ):
173+ self .check_build ('_test_cppext_limited_cpp03' , std = 'c++03' , limited = True )
121174
122175 def test_build_abi3t (self ):
123176 # Test with Py_TARGET_ABI3T
124- self .check_build ('_test_abi3t ' , abi3t = True )
177+ self .check_build ('_test_cppext_abi3t ' , abi3t = True )
125178
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' )
179+
180+ class TestInteralC (BaseTests , unittest .TestCase ):
181+ LANGUAGE = 'C'
182+ TEST_INTERNAL_C_API = True
183+
184+ # Default build with no options
185+ def test_build (self ):
186+ self .check_build ('_test_cext_internal' )
132187
133188
134- class TestInteralCAPI (BaseTests , unittest .TestCase ):
189+ class TestInteralCpp (BaseTests , unittest .TestCase ):
190+ LANGUAGE = 'C++'
135191 TEST_INTERNAL_C_API = True
136192
193+ def test_build (self ):
194+ kwargs = {}
195+ if sys .platform == 'darwin' :
196+ # Old Apple clang++ default C++ std is gnu++98
197+ kwargs ['std' ] = 'c++11'
198+ self .check_build ('_test_cppext_internal' , ** kwargs )
199+
200+
201+ def setUpModule ():
202+ global VENV_CONTEXT , PYTHON_EXE
203+ VENV_CONTEXT = support .setup_venv_with_pip_setuptools ('env' )
204+ PYTHON_EXE = VENV_CONTEXT .__enter__ ()
205+
206+
207+ def tearDownModule ():
208+ VENV_CONTEXT .__exit__ (None , None , None )
209+
137210
138211if __name__ == "__main__" :
139212 unittest .main ()
0 commit comments