I am beginning the process of writing Python 3 module in C. The C I have written already compiles fine (code I compiled at bottom of post). I compile with:
python3 setup.py build_ext --inplace
The built .so file is placed in the current directory. After launching python3, when I import my module I get this error (tripple dot used to truncate paths):
>>> import helloWorld
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: dlopen(..., 2): Symbol not found: _Py_InitModule4_64
Referenced from: .../helloWorld.cpython-36m-darwin.so
Expected in: flat namespace
in .../helloWorld.cpython-36m-darwin.so
How do I got about getting symbol _Py_InitModule4_64 implemented?
I am running macOS High Sierra if that means anything
Running nm for helloWorld.cpython-36m-darwin.so shows _Py_InitModule4_64 is undefined, so does that prove there is an issue in the compilation process?
nm helloWorld.cpython-36m-darwin.so
U _Py_BuildValue
U _Py_InitModule4_64
0000000000000eb0 t _helloWorld
0000000000001060 d _helloWorld_docs
0000000000001020 d _helloworld_funcs
0000000000000e80 T _inithelloWorld
U dyld_stub_binder
test.c:
#include <Python/Python.h>
static PyObject* helloWorld(PyObject* self) {
return Py_BuildValue("s", "Hello, Python extensions!!");
}
static char helloWorld_docs[] =
"helloWorld( ): Any message you want to put here!!\n";
static PyMethodDef helloworld_funcs[] = {
{"helloWorld", (PyCFunction)helloWorld,
METH_NOARGS, helloWorld_docs},
{NULL}
};
void inithelloWorld(void) {
Py_InitModule3("helloworld", helloworld_funcs, "Extension module example!");
}
setup.py:
from distutils.core import setup, Extension
setup(name = 'helloWorld', version = '1.0', \
ext_modules = [Extension('helloWorld', ['test.c'])])
You wrote your module against the Python 2 C API (the various Py_InitModule
functions are purely for Python 2), but you're trying to compile it and run it with Python 3. The C layer for CPython changed a lot between Python 2 and 3, and there is no 2to3
tool for the C code to my knowledge.
You need to write Python 3 API compatible code to work on Python 3; the simplest (and only approach supported on 3.0-3.4) translation is to single-phase initialization (with PyModule_Create
), but multi-phase initialization gets behavior more like modules defined in Python (e.g. it's possible to completely unload them in a way that isn't possible with single-phase modules). The structure of the entry point name changed as well, from initMODULENAME
to PyInit_MODULENAME
, so you'll need to update that as well.
I'd strongly recommend reading the Python 3 extension module tutorial.