Skip to content

Commit 1d0f58b

Browse files
authored
[3.14] gh-157649: Merge test_cppext into test_cext (#158176) (#159264) (#159276)
* [3.15] gh-157649: Merge test_cppext into test_cext (#158176) (#159264) * 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. (cherry picked from commit b71989d) (cherry picked from commit 364db5d) * Fix warning about unused dict
1 parent 1f06ef7 commit 1d0f58b

9 files changed

Lines changed: 577 additions & 756 deletions

File tree

‎Lib/test/pythoninfo.py‎

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

881881

882-
def collect_cc(info_add):
882+
def get_compiler_version(sysconfig_var):
883883
import sysconfig
884-
885-
CC = sysconfig.get_config_var('CC')
886-
if not CC:
884+
program = sysconfig.get_config_var(sysconfig_var)
885+
if not program:
887886
return
888887

889888
try:
890889
import shlex
891-
args = shlex.split(CC)
890+
args = shlex.split(program)
892891
except ImportError:
893-
args = CC.split()
892+
args = program.split()
894893
args.append('--version')
895894

896895
stdout = run_command(args)
@@ -904,7 +903,21 @@ def collect_cc(info_add):
904903

905904
text = first_line(stdout)
906905
text = normalize_text(text)
907-
info_add('CC.version', text)
906+
if text:
907+
text = f'[{program}] {text}'
908+
return text
909+
910+
911+
def collect_cc(info_add):
912+
# C compiler
913+
version = get_compiler_version('CC')
914+
if version:
915+
info_add('CC.version', version)
916+
917+
# C++ compiler
918+
version = get_compiler_version('CXX')
919+
if version:
920+
info_add('CXX.version', version)
908921

909922

910923
def collect_gdbm(info_add):

‎Lib/test/test_cext/__init__.py‎

Lines changed: 112 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +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
12+
import sys
13+
import sysconfig
1114
import unittest
1215
from test import support
16+
from test.support import os_helper
1317

1418

19+
if not support.has_subprocess_support:
20+
raise unittest.SkipTest("requires subprocess support")
21+
22+
23+
SOURCE_DIR = os.path.dirname(__file__)
1524
SOURCES = [
16-
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'),
1728
]
18-
SETUP = os.path.join(os.path.dirname(__file__), 'setup.py')
29+
MSVC = support.MS_WINDOWS
1930

2031

2132
# With MSVC on a debug build, the linker fails with: cannot open file
2233
# 'python311.lib', it should look 'python311_d.lib'.
23-
@unittest.skipIf(support.MS_WINDOWS and support.Py_DEBUG,
34+
@unittest.skipIf(MSVC and support.Py_DEBUG,
2435
'test fails on Windows debug build')
2536
# Building and running an extension in clang sanitizing mode is not
2637
# straightforward
@@ -32,33 +43,36 @@
3243
@support.requires_resource('cpu')
3344
class BaseTests:
3445
TEST_INTERNAL_C_API = False
46+
LANGUAGE = None
3547

36-
# Default build with no options
37-
def test_build(self):
38-
self.check_build('_test_cext')
39-
40-
def check_build(self, extension_name, std=None, limited=False):
41-
venv_dir = 'env'
42-
with support.setup_venv_with_pip_setuptools(venv_dir) as python_exe:
43-
self._check_build(extension_name, python_exe,
44-
std=std, limited=limited)
48+
def check_build(self, extension_name, std=None, limited=False,
49+
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'
4553

46-
def _check_build(self, extension_name, python_exe, std, limited):
4754
pkg_dir = 'pkg'
4855
os.mkdir(pkg_dir)
49-
shutil.copy(SETUP, os.path.join(pkg_dir, os.path.basename(SETUP)))
56+
self.addCleanup(os_helper.rmtree, pkg_dir)
57+
5058
for source in SOURCES:
5159
dest = os.path.join(pkg_dir, os.path.basename(source))
5260
shutil.copy(source, dest)
5361

5462
def run_cmd(operation, cmd):
5563
env = os.environ.copy()
64+
env['CPYTHON_TEST_EXT_NAME'] = extension_name
65+
env['CPYTHON_TEST_LANG'] = self.LANGUAGE
5666
if std:
5767
env['CPYTHON_TEST_STD'] = std
5868
if limited:
5969
env['CPYTHON_TEST_LIMITED'] = '1'
60-
env['CPYTHON_TEST_EXT_NAME'] = extension_name
61-
env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API))
70+
if MSVC and sysconfig.is_python_build():
71+
env['CPYTHON_TEST_EXTRA_INCDIRS'] = os.path.split(sysconfig.get_config_h_filename())[0]
72+
env['CPYTHON_TEST_EXTRA_LIBDIRS'] = os.path.split(sys.executable)[0]
73+
env['CPYTHON_TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API))
74+
if extra_cflags:
75+
env['CPYTHON_TEST_EXTRA_CFLAGS'] = extra_cflags
6276
if support.verbose:
6377
print('Run:', ' '.join(map(shlex.quote, cmd)))
6478
subprocess.run(cmd, check=True, env=env)
@@ -75,6 +89,7 @@ def run_cmd(operation, cmd):
7589
f"{operation} failed with exit code {proc.returncode}")
7690

7791
# Build and install the C extension
92+
python_exe = PYTHON_EXE
7893
cmd = [python_exe, '-X', 'dev',
7994
'-m', 'pip', 'install', '--no-build-isolation',
8095
os.path.abspath(pkg_dir)]
@@ -91,37 +106,102 @@ def run_cmd(operation, cmd):
91106
'-c', 'pass']
92107
run_cmd('Reference run', cmd)
93108

94-
# Import the C extension
109+
# Import the C/C++ extension
95110
cmd = [python_exe,
96111
'-X', 'dev',
97112
'-X', 'showrefcount',
98113
'-c', f"import {extension_name}"]
99114
run_cmd('Import', cmd)
100115

101116

102-
class TestPublicCAPI(BaseTests, unittest.TestCase):
103-
@support.requires_gil_enabled('incompatible with Free Threading')
104-
def test_build_limited(self):
105-
self.check_build('_test_limited_cext', limited=True)
117+
class TestPublicC(BaseTests, unittest.TestCase):
118+
LANGUAGE = 'C'
106119

107-
@support.requires_gil_enabled('broken for now with Free Threading')
108-
def test_build_limited_c11(self):
109-
self.check_build('_test_limited_c11_cext', limited=True, std='c11')
110-
111-
def test_build_c11(self):
112-
self.check_build('_test_c11_cext', std='c11')
120+
# Default build with no options
121+
def test_build(self):
122+
self.check_build('_test_cext')
113123

114-
@unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c99")
124+
@unittest.skipIf(MSVC, "MSVC doesn't support /std:c99")
115125
def test_build_c99(self):
116126
# In public docs, we say C API is compatible with C11. However,
117127
# in practice we do maintain C99 compatibility in public headers.
118128
# Please ask the C API WG before adding a new C11-only feature.
119-
self.check_build('_test_c99_cext', std='c99')
129+
self.check_build('_test_cext_c99', std='c99')
130+
131+
def test_build_c11(self):
132+
self.check_build('_test_cext_c11', std='c11')
133+
134+
def test_build_limited(self):
135+
self.check_build('_test_cext_limited', limited=True)
136+
137+
def test_build_limited_c11(self):
138+
self.check_build('_test_cext_limited_c11', limited=True, std='c11')
139+
140+
141+
class TestPublicCpp(BaseTests, unittest.TestCase):
142+
LANGUAGE = 'C++'
120143

144+
def test_build(self):
145+
self.check_build('_test_cppext')
146+
147+
def test_build_cpp03(self):
148+
# In public docs, we say C API is compatible with C++11. However,
149+
# in practice we do maintain C++03 compatibility in public headers.
150+
# Please ask the C API WG before adding a new C++11-only feature.
151+
self.check_build('_test_cppext_cpp03', std='c++03')
152+
153+
@unittest.skipIf(MSVC, "MSVC doesn't support /std:c++11")
154+
def test_build_cpp11(self):
155+
self.check_build('_test_cppext_cpp11', std='c++11')
156+
157+
# Only test C++14 on MSVC.
158+
# On s390x RHEL7, GCC 4.8.5 doesn't support C++14.
159+
@unittest.skipIf(not MSVC, "need MSVC")
160+
def test_build_cpp14(self):
161+
self.check_build('_test_cppext_cpp14', std='c++14')
162+
163+
# Test that headers compile with Intel asm syntax, which may conflict
164+
# with inline assembly in free-threading headers that use AT&T syntax.
165+
@unittest.skipIf(MSVC, "MSVC doesn't support -masm=intel")
166+
@unittest.skipUnless(platform.machine() in ('x86_64', 'i686', 'AMD64'),
167+
"x86-specific flag")
168+
def test_build_intel_asm(self):
169+
self.check_build('_test_cppext_intel_asm', extra_cflags='-masm=intel')
170+
171+
def test_build_limited(self):
172+
self.check_build('_test_cppext_limited', limited=True)
121173

122-
class TestInteralCAPI(BaseTests, unittest.TestCase):
174+
def test_build_limited_cpp03(self):
175+
self.check_build('_test_cppext_limited_cpp03', std='c++03', limited=True)
176+
177+
178+
class TestInteralC(BaseTests, unittest.TestCase):
179+
LANGUAGE = 'C'
123180
TEST_INTERNAL_C_API = True
124181

182+
# Default build with no options
183+
def test_build(self):
184+
self.check_build('_test_cext_internal')
185+
186+
187+
class TestInteralCpp(BaseTests, unittest.TestCase):
188+
LANGUAGE = 'C++'
189+
TEST_INTERNAL_C_API = True
190+
191+
def test_build(self):
192+
self.check_build('_test_cppext_internal')
193+
194+
195+
@support.requires_venv_with_pip()
196+
def setUpModule():
197+
global VENV_CONTEXT, PYTHON_EXE
198+
VENV_CONTEXT = support.setup_venv_with_pip_setuptools('env')
199+
PYTHON_EXE = VENV_CONTEXT.__enter__()
200+
201+
202+
def tearDownModule():
203+
VENV_CONTEXT.__exit__(None, None, None)
204+
125205

126206
if __name__ == "__main__":
127207
unittest.main()

0 commit comments

Comments
 (0)