Search code examples
ccpythoncalling-convention

How is a C extension compiled with the correct native calling convention?


Suppose we're writing a CPython extension module in C.

When defining an extension, we are required to supply a PyMODINIT_FUNC PyInit_<module_name>(void). Nowhere in this declaration is a native calling convention specified.

Whether on Linux or on Windows, how can the extension developer ensure that the PyInit_ function is compiled using the correct calling convention, so that the interpreter calls it successfuly during runtime? Is there some magic in the Python headers that takes care of this for us? Or something else?

The same question applies to native functions contained in the extension module, and exposed to Python wrapped as function objects. How do we ensure that these are compiled in a manner compatible with the Python interpreter calling convention?


Solution

  • You're literally writing PyMODINIT_FUNC PyInit_<module_name>(void). Now PyMODINIT_FUNC is a macro that expands to different things that are controlled by various #ifdefs in pyport.h. In current HEAD revision in the Github revision Python 3.9 development version has these 6 defines:

    #define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
    #define PyMODINIT_FUNC PyObject*
    #define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
    #define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
    #define PyMODINIT_FUNC extern "C" Py_EXPORTED_SYMBOL PyObject*
    #define PyMODINIT_FUNC Py_EXPORTED_SYMBOL PyObject*
    

    I.e. it expands to PyObject * as the return type but also extern "C" if compiled with a C++ compiler to ensure C linkage against this symbol, and includes the Py_EXPORTED_SYMBOL on some platforms.

    Py_EXPORTED_SYMBOL is defined in exports.h as one of

    #define Py_EXPORTED_SYMBOL __declspec(dllexport)
    #define Py_EXPORTED_SYMBOL __attribute__ ((visibility ("default")))
    #define Py_EXPORTED_SYMBOL
    

    None of these specify the calling convention, instead letting the function default to the cdecl convention as they should... - also do note that calling conventions are mostly a thing only in Windows.