python / cpython

The Python programming language
https://www.python.org
Other
62.34k stars 29.94k forks source link

"template with C linkage" error when including "pycore_interp.h" from C++ file #122584

Open sklam opened 1 month ago

sklam commented 1 month ago

Bug report

Bug description:

Tested on official docker image python3.13.0b4-bullseye. pycore_interp.h causes compiler error when included from C++ file. No problem when included from C file.

mypackage/_good.c:

#include "Python.h"

#define Py_BUILD_CORE 1
#include "internal/pycore_interp.h"

mypackage/_bad.cpp (same content as above):

#include "Python.h"

#define Py_BUILD_CORE 1
#include "internal/pycore_interp.h"

setup.py:

from setuptools import Extension, find_packages, setup

def get_ext_modules():
    ext_good = Extension(name="mypackage.a",
                               sources=['mypackage/_good.c'])

    ext_bad = Extension(name="mypackage.b",
                               sources=['mypackage/_bad.cpp'])

    return [ext_good, ext_bad]

metadata = dict(
    name='debugthis',
    packages=find_packages(include=["mypackage"])
)

metadata['ext_modules'] = get_ext_modules()

setup(**metadata)

Running python setup.py build produces error:

running build
running build_py
copying mypackage/__init__.py -> build/lib.linux-x86_64-cpython-313/mypackage
running build_ext
building 'mypackage.a' extension
creating build/temp.linux-x86_64-cpython-313
creating build/temp.linux-x86_64-cpython-313/mypackage
gcc -pthread -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -I/usr/local/include/python3.13 -c mypackage/_good.c -o build/temp.linux-x86_64-cpython-313/mypackage/_good.o
gcc -pthread -shared build/temp.linux-x86_64-cpython-313/mypackage/_good.o -L/usr/local/lib -o build/lib.linux-x86_64-cpython-313/mypackage/a.cpython-313-x86_64-linux-gnu.so
building 'mypackage.b' extension
gcc -pthread -fno-strict-overflow -Wsign-compare -DNDEBUG -g -O3 -Wall -fPIC -I/usr/local/include/python3.13 -c mypackage/_bad.cpp -o build/temp.linux-x86_64-cpython-313/mypackage/_bad.o
In file included from /usr/local/include/python3.13/internal/mimalloc/mimalloc.h:429,
                 from /usr/local/include/python3.13/internal/pycore_mimalloc.h:39,
                 from /usr/local/include/python3.13/internal/pycore_interp.h:31,
                 from mypackage/_bad.cpp:4:
/usr/include/c++/10/type_traits:56:3: error: template with C linkage
   56 |   template<typename _Tp, _Tp __v>
      |   ^~~~~~~~
In file included from mypackage/_bad.cpp:4:
/usr/local/include/python3.13/internal/pycore_interp.h:4:1: note: ‘extern "C"’ linkage started here
    4 | extern "C" {
      | ^~~~~~~~~~
...

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Linked PRs

mdboom commented 1 month ago

It looks like mimalloc.h is designed to be importable from either a C++ or C context, so it shouldn't be imported from inside an extern "C" { } block.

This fixes the issue, but there might be other cases of this, and it's not clear how to enforce that we don't fall in this trap again.

diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 45d85b2bace..f1dacc3eb3a 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -1,5 +1,8 @@
 #ifndef Py_INTERNAL_INTERP_H
 #define Py_INTERNAL_INTERP_H
+
+#include "pycore_mimalloc.h"      // struct _mimalloc_interp_state
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -28,7 +31,6 @@ extern "C" {
 #include "pycore_import.h"        // struct _import_state
 #include "pycore_instruments.h"   // _PY_MONITORING_EVENTS
 #include "pycore_list.h"          // struct _Py_list_state
-#include "pycore_mimalloc.h"      // struct _mimalloc_interp_state
 #include "pycore_object_state.h"  // struct _py_object_state
 #include "pycore_optimizer.h"     // _PyOptimizerObject
 #include "pycore_obmalloc.h"      // struct _obmalloc_state