Skip to content

Commit 18d8ef5

Browse files
committed
gh-157649: Merge test_cppext into test_cext
* test_cext now uses a single virtual environment for all tests. It makes the test way faster since creating a virtual environment is quite slow. * Add Py_TARGET_ABI3T test on C++. * Move macro tests from module exec function to test_macros(). * Call Py_BEGIN_CRITICAL_SECTION() on a fresh dictionary object, rather than on the module. * Rename some environment variables to always use "CPYTHON_TEST_" prefix. * Replace support.MS_WINDOWS with MSVC to be more explicit. * Move macro tests to test_macros().
1 parent 64d315a commit 18d8ef5

7 files changed

Lines changed: 558 additions & 773 deletions

File tree

‎Lib/test/test_cext/__init__.py‎

Lines changed: 112 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
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

77
import os.path
8+
import platform
89
import shlex
910
import shutil
1011
import subprocess
11-
import sysconfig
1212
import sys
13+
import sysconfig
1314
import unittest
1415
from test import support
16+
from test.support import os_helper
1517

1618

19+
SOURCE_DIR = os.path.dirname(__file__)
1720
SOURCES = [
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
@@ -34,41 +39,34 @@
3439
@support.requires_resource('cpu')
3540
class 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

138211
if __name__ == "__main__":
139212
unittest.main()

0 commit comments

Comments
 (0)