Skip to content

Commit b71989d

Browse files
authored
gh-157649: Merge test_cppext into test_cext (#158176)
* 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(). * On macOS, use C++11 by default.
1 parent 198bc76 commit b71989d

9 files changed

Lines changed: 582 additions & 781 deletions

File tree

‎Lib/test/pythoninfo.py‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -917,18 +917,17 @@ def collect_support_threading_helper(info_add):
917917
copy_attributes(info_add, threading_helper, 'support_threading_helper.%s', attributes)
918918

919919

920-
def collect_cc(info_add):
920+
def get_compiler_version(sysconfig_var):
921921
import sysconfig
922-
923-
CC = sysconfig.get_config_var('CC')
924-
if not CC:
922+
program = sysconfig.get_config_var(sysconfig_var)
923+
if not program:
925924
return
926925

927926
try:
928927
import shlex
929-
args = shlex.split(CC)
928+
args = shlex.split(program)
930929
except ImportError:
931-
args = CC.split()
930+
args = program.split()
932931
args.append('--version')
933932

934933
stdout = run_command(args)
@@ -942,7 +941,21 @@ def collect_cc(info_add):
942941

943942
text = first_line(stdout)
944943
text = normalize_text(text)
945-
info_add('CC.version', text)
944+
if text:
945+
text = f'[{program}] {text}'
946+
return text
947+
948+
949+
def collect_cc(info_add):
950+
# C compiler
951+
version = get_compiler_version('CC')
952+
if version:
953+
info_add('CC.version', version)
954+
955+
# C++ compiler
956+
version = get_compiler_version('CXX')
957+
if version:
958+
info_add('CXX.version', version)
946959

947960

948961
def collect_gdbm(info_add):

‎Lib/test/test_cext/__init__.py‎

Lines changed: 116 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
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
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__)
1724
SOURCES = [
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
@@ -34,41 +43,38 @@
3443
@support.requires_resource('cpu')
3544
class 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

138215
if __name__ == "__main__":
139216
unittest.main()

0 commit comments

Comments
 (0)