-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Build a basic C++ test extension to check that the Python C API is compatible with C++ and does not emit C++ compiler warnings. * Add Modules/_testcppext.cpp: C++ extension * Add Lib/test/test_cppext.py: test building the C++ extension.
- Loading branch information
Showing
2 changed files
with
141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// gh-91321: Very basic C++ test extension to check that the Python C API is | ||
// compatible with C++ and does not emit C++ compiler warnings. | ||
|
||
#include "Python.h" | ||
|
||
PyDoc_STRVAR(_testcppext_add_doc, | ||
"add(x, y)\n" | ||
"\n" | ||
"Return the sum of two integers: x + y."); | ||
|
||
static PyObject * | ||
_testcppext_add(PyObject *Py_UNUSED(module), PyObject *args) | ||
{ | ||
long i, j; | ||
if (!PyArg_ParseTuple(args, "ll:foo", &i, &j)) { | ||
return nullptr; | ||
} | ||
long res = i + j; | ||
return PyLong_FromLong(res); | ||
} | ||
|
||
|
||
static PyMethodDef _testcppext_methods[] = { | ||
{"add", _testcppext_add, METH_VARARGS, _testcppext_add_doc}, | ||
{nullptr, nullptr, 0, nullptr} /* sentinel */ | ||
}; | ||
|
||
|
||
static int | ||
_testcppext_exec(PyObject *module) | ||
{ | ||
if (PyModule_AddIntMacro(module, __cplusplus) < 0) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
|
||
static PyModuleDef_Slot _testcppext_slots[] = { | ||
{Py_mod_exec, reinterpret_cast<void*>(_testcppext_exec)}, | ||
{0, NULL} | ||
}; | ||
|
||
|
||
PyDoc_STRVAR(_testcppext_doc, "C++ test extension."); | ||
|
||
static struct PyModuleDef _testcppext_module = { | ||
PyModuleDef_HEAD_INIT, // m_base | ||
"_testcppext", // m_name | ||
_testcppext_doc, // m_doc | ||
0, // m_size | ||
_testcppext_methods, // m_methods | ||
_testcppext_slots, // m_slots | ||
NULL, // m_traverse | ||
NULL, // m_clear | ||
nullptr, // m_free | ||
}; | ||
|
||
PyMODINIT_FUNC | ||
PyInit__testcppext(void) | ||
{ | ||
return PyModuleDef_Init(&_testcppext_module); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# gh-91321: Build a basic C++ test extension to check that the Python C API is | ||
# compatible with C++ and does not emit C++ compiler warnings. | ||
import os | ||
import sys | ||
import unittest | ||
import warnings | ||
from test import support | ||
from test.support import os_helper | ||
|
||
with warnings.catch_warnings(): | ||
warnings.simplefilter('ignore', DeprecationWarning) | ||
from distutils.core import setup, Extension | ||
import distutils.sysconfig | ||
|
||
|
||
MS_WINDOWS = (sys.platform == 'win32') | ||
|
||
|
||
SOURCE = support.findfile('_testcppext.cpp') | ||
if not MS_WINDOWS: | ||
# C++ compiler flags for GCC and clang | ||
CPPFLAGS = [ | ||
# Python currently targets C++11 | ||
'-std=c++11', | ||
# gh-91321: The purpose of _testcppext extension is to check that building | ||
# a C++ extension using the Python C API does not emit C++ compiler | ||
# warnings | ||
'-Werror', | ||
] | ||
else: | ||
# Don't pass any compiler flag to MSVC | ||
CPPFLAGS = [] | ||
|
||
|
||
class TestCPPExt(unittest.TestCase): | ||
def build(self): | ||
cpp_ext = Extension( | ||
'_testcppext', | ||
sources=[SOURCE], | ||
language='c++', | ||
extra_compile_args=CPPFLAGS) | ||
|
||
try: | ||
try: | ||
with (support.captured_stdout() as stdout, | ||
support.swap_attr(sys, 'argv', ['setup.py', 'build_ext'])): | ||
setup(name="_testcppext", ext_modules=[cpp_ext]) | ||
return | ||
except: | ||
# Show output on error | ||
print() | ||
print(stdout.getvalue()) | ||
raise | ||
except SystemExit: | ||
self.fail("Build failed") | ||
|
||
# With MSVC, the linker fails with: cannot open file 'python311.lib' | ||
# https://github.com/python/cpython/pull/32175#issuecomment-1111175897 | ||
@unittest.skipIf(MS_WINDOWS, 'test fails on Windows') | ||
def test_build(self): | ||
# save/restore os.environ | ||
def restore_env(old_env): | ||
os.environ.clear() | ||
os.environ.update(old_env) | ||
self.addCleanup(restore_env, dict(os.environ)) | ||
|
||
def restore_sysconfig_vars(old_config_vars): | ||
distutils.sysconfig._config_vars.clear() | ||
distutils.sysconfig._config_vars.update(old_config_vars) | ||
self.addCleanup(restore_sysconfig_vars, | ||
dict(distutils.sysconfig._config_vars)) | ||
|
||
# Build in a temporary directory | ||
with os_helper.temp_cwd(): | ||
self.build() | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main() |