Skip to content

Commit 2c9a801

Browse files
authored
gh-135906: Test the internal C API in test_cext (#136247)
Remove duplicated definition: atexit_datacallbackfunc type is already defined by Include/cpython/pylifecycle.h.
1 parent cbf007b commit 2c9a801

File tree

7 files changed

+103
-36
lines changed

7 files changed

+103
-36
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ struct _atexit_runtime_state {
130130
//###################
131131
// interpreter atexit
132132

133-
typedef void (*atexit_datacallbackfunc)(void *);
134-
135133
typedef struct atexit_callback {
136134
atexit_datacallbackfunc func;
137135
void *data;

Lib/test/test_cext/__init__.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,13 @@
2828
@support.requires_venv_with_pip()
2929
@support.requires_subprocess()
3030
@support.requires_resource('cpu')
31-
class TestExt(unittest.TestCase):
31+
class BaseTests:
32+
TEST_INTERNAL_C_API = False
33+
3234
# Default build with no options
3335
def test_build(self):
3436
self.check_build('_test_cext')
3537

36-
def test_build_c11(self):
37-
self.check_build('_test_c11_cext', std='c11')
38-
39-
@unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c99")
40-
def test_build_c99(self):
41-
# In public docs, we say C API is compatible with C11. However,
42-
# in practice we do maintain C99 compatibility in public headers.
43-
# Please ask the C API WG before adding a new C11-only feature.
44-
self.check_build('_test_c99_cext', std='c99')
45-
46-
@support.requires_gil_enabled('incompatible with Free Threading')
47-
def test_build_limited(self):
48-
self.check_build('_test_limited_cext', limited=True)
49-
50-
@support.requires_gil_enabled('broken for now with Free Threading')
51-
def test_build_limited_c11(self):
52-
self.check_build('_test_limited_c11_cext', limited=True, std='c11')
53-
5438
def check_build(self, extension_name, std=None, limited=False):
5539
venv_dir = 'env'
5640
with support.setup_venv_with_pip_setuptools(venv_dir) as python_exe:
@@ -70,6 +54,7 @@ def run_cmd(operation, cmd):
7054
if limited:
7155
env['CPYTHON_TEST_LIMITED'] = '1'
7256
env['CPYTHON_TEST_EXT_NAME'] = extension_name
57+
env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API))
7358
if support.verbose:
7459
print('Run:', ' '.join(map(shlex.quote, cmd)))
7560
subprocess.run(cmd, check=True, env=env)
@@ -110,5 +95,29 @@ def run_cmd(operation, cmd):
11095
run_cmd('Import', cmd)
11196

11297

98+
class TestPublicCAPI(BaseTests, unittest.TestCase):
99+
@support.requires_gil_enabled('incompatible with Free Threading')
100+
def test_build_limited(self):
101+
self.check_build('_test_limited_cext', limited=True)
102+
103+
@support.requires_gil_enabled('broken for now with Free Threading')
104+
def test_build_limited_c11(self):
105+
self.check_build('_test_limited_c11_cext', limited=True, std='c11')
106+
107+
def test_build_c11(self):
108+
self.check_build('_test_c11_cext', std='c11')
109+
110+
@unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c99")
111+
def test_build_c99(self):
112+
# In public docs, we say C API is compatible with C11. However,
113+
# in practice we do maintain C99 compatibility in public headers.
114+
# Please ask the C API WG before adding a new C11-only feature.
115+
self.check_build('_test_c99_cext', std='c99')
116+
117+
118+
class TestInteralCAPI(BaseTests, unittest.TestCase):
119+
TEST_INTERNAL_C_API = True
120+
121+
113122
if __name__ == "__main__":
114123
unittest.main()

Lib/test/test_cext/extension.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,31 @@
11
// gh-116869: Basic C test extension to check that the Python C API
22
// does not emit C compiler warnings.
3+
//
4+
// Test also the internal C API if the TEST_INTERNAL_C_API macro is defined.
35

46
// Always enable assertions
57
#undef NDEBUG
68

9+
#ifdef TEST_INTERNAL_C_API
10+
# define Py_BUILD_CORE_MODULE 1
11+
#endif
12+
713
#include "Python.h"
814

15+
#ifdef TEST_INTERNAL_C_API
16+
// gh-135906: Check for compiler warnings in the internal C API.
17+
// - Cython uses pycore_frame.h.
18+
// - greenlet uses pycore_frame.h, pycore_interpframe_structs.h and
19+
// pycore_interpframe.h.
20+
# include "internal/pycore_frame.h"
21+
# include "internal/pycore_gc.h"
22+
# include "internal/pycore_interp.h"
23+
# include "internal/pycore_interpframe.h"
24+
# include "internal/pycore_interpframe_structs.h"
25+
# include "internal/pycore_object.h"
26+
# include "internal/pycore_pystate.h"
27+
#endif
28+
929
#ifndef MODULE_NAME
1030
# error "MODULE_NAME macro must be defined"
1131
#endif

Lib/test/test_cext/setup.py

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@
1414

1515
if not support.MS_WINDOWS:
1616
# C compiler flags for GCC and clang
17-
CFLAGS = [
17+
BASE_CFLAGS = [
1818
# The purpose of test_cext extension is to check that building a C
1919
# extension using the Python C API does not emit C compiler warnings.
2020
'-Werror',
21+
]
22+
23+
# C compiler flags for GCC and clang
24+
PUBLIC_CFLAGS = [
25+
*BASE_CFLAGS,
2126

2227
# gh-120593: Check the 'const' qualifier
2328
'-Wcast-qual',
@@ -26,27 +31,40 @@
2631
'-pedantic-errors',
2732
]
2833
if not support.Py_GIL_DISABLED:
29-
CFLAGS.append(
34+
PUBLIC_CFLAGS.append(
3035
# gh-116869: The Python C API must be compatible with building
3136
# with the -Werror=declaration-after-statement compiler flag.
3237
'-Werror=declaration-after-statement',
3338
)
39+
INTERNAL_CFLAGS = [*BASE_CFLAGS]
3440
else:
3541
# MSVC compiler flags
36-
CFLAGS = [
37-
# Display warnings level 1 to 4
38-
'/W4',
42+
BASE_CFLAGS = [
3943
# Treat all compiler warnings as compiler errors
4044
'/WX',
4145
]
46+
PUBLIC_CFLAGS = [
47+
*BASE_CFLAGS,
48+
# Display warnings level 1 to 4
49+
'/W4',
50+
]
51+
INTERNAL_CFLAGS = [
52+
*BASE_CFLAGS,
53+
# Display warnings level 1 to 3
54+
'/W3',
55+
]
4256

4357

4458
def main():
4559
std = os.environ.get("CPYTHON_TEST_STD", "")
4660
module_name = os.environ["CPYTHON_TEST_EXT_NAME"]
4761
limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", ""))
62+
internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0")))
4863

49-
cflags = list(CFLAGS)
64+
if not internal:
65+
cflags = list(PUBLIC_CFLAGS)
66+
else:
67+
cflags = list(INTERNAL_CFLAGS)
5068
cflags.append(f'-DMODULE_NAME={module_name}')
5169

5270
# Add -std=STD or /std:STD (MSVC) compiler flag
@@ -75,6 +93,9 @@ def main():
7593
version = sys.hexversion
7694
cflags.append(f'-DPy_LIMITED_API={version:#x}')
7795

96+
if internal:
97+
cflags.append('-DTEST_INTERNAL_C_API=1')
98+
7899
# On Windows, add PCbuild\amd64\ to include and library directories
79100
include_dirs = []
80101
library_dirs = []

Lib/test/test_cppext/__init__.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
@support.requires_venv_with_pip()
2525
@support.requires_subprocess()
2626
@support.requires_resource('cpu')
27-
class TestCPPExt(unittest.TestCase):
27+
class BaseTests:
2828
def test_build(self):
2929
self.check_build('_testcppext')
3030

@@ -34,10 +34,6 @@ def test_build_cpp03(self):
3434
# Please ask the C API WG before adding a new C++11-only feature.
3535
self.check_build('_testcpp03ext', std='c++03')
3636

37-
@support.requires_gil_enabled('incompatible with Free Threading')
38-
def test_build_limited_cpp03(self):
39-
self.check_build('_test_limited_cpp03ext', std='c++03', limited=True)
40-
4137
@unittest.skipIf(support.MS_WINDOWS, "MSVC doesn't support /std:c++11")
4238
def test_build_cpp11(self):
4339
self.check_build('_testcpp11ext', std='c++11')
@@ -48,10 +44,6 @@ def test_build_cpp11(self):
4844
def test_build_cpp14(self):
4945
self.check_build('_testcpp14ext', std='c++14')
5046

51-
@support.requires_gil_enabled('incompatible with Free Threading')
52-
def test_build_limited(self):
53-
self.check_build('_testcppext_limited', limited=True)
54-
5547
def check_build(self, extension_name, std=None, limited=False):
5648
venv_dir = 'env'
5749
with support.setup_venv_with_pip_setuptools(venv_dir) as python_exe:
@@ -111,5 +103,19 @@ def run_cmd(operation, cmd):
111103
run_cmd('Import', cmd)
112104

113105

106+
class TestPublicCAPI(BaseTests, unittest.TestCase):
107+
@support.requires_gil_enabled('incompatible with Free Threading')
108+
def test_build_limited_cpp03(self):
109+
self.check_build('_test_limited_cpp03ext', std='c++03', limited=True)
110+
111+
@support.requires_gil_enabled('incompatible with Free Threading')
112+
def test_build_limited(self):
113+
self.check_build('_testcppext_limited', limited=True)
114+
115+
116+
class TestInteralCAPI(BaseTests, unittest.TestCase):
117+
TEST_INTERNAL_C_API = True
118+
119+
114120
if __name__ == "__main__":
115121
unittest.main()

Lib/test/test_cppext/extension.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,17 @@
66
// Always enable assertions
77
#undef NDEBUG
88

9+
#ifdef TEST_INTERNAL_C_API
10+
# define Py_BUILD_CORE 1
11+
#endif
12+
913
#include "Python.h"
1014

15+
#ifdef TEST_INTERNAL_C_API
16+
// gh-135906: Check for compiler warnings in the internal C API
17+
# include "internal/pycore_frame.h"
18+
#endif
19+
1120
#ifndef MODULE_NAME
1221
# error "MODULE_NAME macro must be defined"
1322
#endif

Lib/test/test_cppext/setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def main():
4747
std = os.environ.get("CPYTHON_TEST_CPP_STD", "")
4848
module_name = os.environ["CPYTHON_TEST_EXT_NAME"]
4949
limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", ""))
50+
internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0")))
5051

5152
cppflags = list(CPPFLAGS)
5253
cppflags.append(f'-DMODULE_NAME={module_name}')
@@ -82,6 +83,9 @@ def main():
8283
version = sys.hexversion
8384
cppflags.append(f'-DPy_LIMITED_API={version:#x}')
8485

86+
if internal:
87+
cppflags.append('-DTEST_INTERNAL_C_API=1')
88+
8589
# On Windows, add PCbuild\amd64\ to include and library directories
8690
include_dirs = []
8791
library_dirs = []

0 commit comments

Comments
 (0)