Search code examples
pythonccpythonpython-extensions

Multifile C Python Extension Organization Issue


Currently, I am trying to write a C Python extension. Specifically, I am trying to create a python module that has a couple of classes in it. Basically, I want it to look something like this:

my_module
     class foo
     class bar

Here's some context as to what I'm working with now.

So far, my source tree looks something like this:

src/
    my_module_main.c
    my_module_defs.h
    my_module_foo.c
    my_module.bar.c

The file my_module_main.c contains the module initialization. This includes the initmy_module function, the definition of my PyTypeObjects for each class, and their corresponding method tables.

The file my_module_defs.h contains all of the definition of functions and types. It contains the

typedef struct {
    PyObject_HEAD
    ...
} foo;

object definitions as well.

Both the my_module_foo.c and my_module_bar.c files contains the definition of the functions for each of the classes. These files contain the actual functions used by these functions (i.e allocators, constructors, destructors, and methods).

Now for my actual problem.

One thing that I am trying to do within this project is access the underlying objects of the class structures (the structs with PyObject_HEAD in them). To do this, you need to use the PyTypeObject structure. That object, however, is located in my_module_main.c and is declared as static, so it is not accessible in my other C files.

My question is this: is there a way that I can share this PyObjectType across multiple source files? Do I have to declare things as extern? I know that I could put the entire module into one source file, but this would be a pain because the file would be too large and have too much going on.

Thanks for your help. If there are any glaring issues with my setup, feel free to comment on it as I am new to this process and could use some pointers. Thanks!


Solution

  • The way the CPython implementation handles this for its own API types is to define the type object in their C file (like you have) and then extern its type objects in their header files. For instance, for the float object you have:

    floatobject.h

    #ifndef Py_FLOATOBJECT_H
    #define Py_FLOATOBJECT_H
    
    ...
    
    PyAPI_DATA(PyTypeObject) PyFloat_Type;
    
    ...
    
    #endif
    

    floatobject.c

    PyTypeObject PyFloat_Type = {
        ...
    };
    

    Where PyAPI_DATA has a default implementation of simply (in Include/pyport.h):

    #define PyAPI_DATA(RTYPE) extern RTYPE
    

    This only really changes if you are on windows.