1

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

Code

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'])])

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Side-note: I suspect your build environment is messed up (e.g. Python 2 include directories have been forcibly added to CPATH or otherwise added you the include path in setup.py or the like), because you used Py_InitModule3 and it translated to a dependency on _Py_InitModule4_64, which implies a remapping from a header that knows what Py_InitModule3 is, and no Python 3 header should recognize that API name. I'm guessing you tried to force your way through some compiler errors, with "success" just guaranteeing the result was unusable anyway. Don't do that.
Ah! Yes, the header is incorrect. I was using the answer from this post, where I use #include <Python/Python.h> instead of #include <Python.h> for when I was compiling with gcc. 'Py_InitModule3' is now unknown upon compilation, like you stated.
After following the module tutorial explicitly, everything works like expected. Thank you for all the resources!
@TarasPalczynski: You're welcome. Glad it was enough to get you on the right track. I've had to write cross-version (as in, compiles for both Py2 and Py3) portable Python C extensions, so I'm really familiar with the discrepancies, and module initialization is one of the biggies (the changes are so extreme that the two APIs are best treated as completely unrelated).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.