I have a Cython project with the following modules:
CythonModule.pyx:
cdef int CPyFuncSwo():
print("Do some stuff in cython")
return 0
cdef public void PyFuncSwo()
CPyFuncSwo()
print("Do some stuff but in pure python only")
CythonModule.pxd:
cdef int CPyFuncSwo()
Setup.py:
from distutils.core import setup, Extension
from Cython.Build import cythonize
ext_modules = [
Extension(
"CythonModule",
sources=["CythonModule.pyx",],
),
]
setup(
name="CythonModule",
ext_modules=cythonize(ext_modules),
compiler_directives={'language_level': 3, "unraisable_tracebacks": True}
)
run.py:
import os
import sys
from CythonModule import PyFuncSwo
sys.path.insert(0, os.path.abspath("."))
if __name__ == '__main__':
PyFuncSwo()
This works perfectly fine and when I run python setup.py build_ext --inplace && python run.py
, the code compiles and runs while also giving me a new CythonModule.cp39-win_amd64.pyd
file. Now I need to call PyFuncSwo()
from the .pyd module in a pure C/C++ code. Surfing through the web, I came across the following example:
RunCythonInC.c:
#include <windows.h>
#include <stdio.h>
typedef (add_proc)(int a, int b);
int main(){
add_proc *add;
HANDLE h_dll;
int a = 1, b = 2, c;
h_dll = LoadLibrary("CythonModule.cp39-win_amd64.pyd");
if(h_dll)
{
add = GetProcAddress(h_dll, "PyFuncSwo");
if(add)
{
c = add(a, b); /*Explicit Call*/
}
else
{
printf("PyFuncSwo not found in CythonModule.cp39-win_amd64.pyd");
}
FreeLibrary(h_dll);
}
else
{
printf("Unable to load CythonModule.cp39-win_amd64.pyd");
exit(-1);
}
return 0;
}
Compiling this code with gcc as gcc -g RunCythonInC.c -o RunCythonInC.exe
compiles with the following warnings, but when I run RunCythonInC.exe, I always get PyFuncSwo not found in CythonModule.cp39-win_amd64.pyd
.
I also changed GetProcAddress(h_dll, "PyFuncSwo")
to GetProcAddress(h_dll, "CPyFuncSwo")
but am I still getting the same error. Other things I tried was calling cython functions with an _ as GetProcAddress(h_dll, "_PyFuncSwo")
but still got the same result. Can anyone tell me, how do I call my cython functions from the .pyd module in a pure C code?
Update:
As per the Cython's documentation Here, it seems that the proper way to declare cython functions in C is to define the cython function type as public and build it. This will generate a "CythonModule.h" header file, which can be included in your C code and then can call the cython functions.
following this instruction, I came up with the following C code:
run.c:
#include <windows.h>
#include <stdio.h>
#include <Python.h>
#include "CythonModule.h"
int main(){
PyImport_AppendInittab("PyFuncSwo", PyInit_CythonModule);
Py_Initialize();
PyImport_ImportModule("PyFuncSwo");
return 0;
}
and changed def PyFuncSwo()
to cdef public void PyFuncSwo()
.
Now I get the following errors:
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\username\AppData\Local\Temp\ccaMLv6A.o:run.c:(.rdata$.refptr.PyInit_CythonModule[.refptr.PyInit_CythonModule]+0x0): undefined reference to `PyInit_CythonModule'
collect2.exe: error: ld returned 1 exit status
CythonModule.h:
/* Generated by Cython 0.29.23 */
#ifndef __PYX_HAVE__CythonModule
#define __PYX_HAVE__CythonModule
#include "Python.h"
#ifndef __PYX_HAVE_API__CythonModule
#ifndef __PYX_EXTERN_C
#ifdef __cplusplus
#define __PYX_EXTERN_C extern "C"
#else
#define __PYX_EXTERN_C extern
#endif
#endif
#ifndef DL_IMPORT
#define DL_IMPORT(_T) _T
#endif
__PYX_EXTERN_C void __pyx_f_13CythonModule_PyFuncSwo(void);
#endif /* !__PYX_HAVE_API__CythonModule */
/* WARNING: the interface of the module init function changed in CPython 3.5. */
/* It now returns a PyModuleDef instance instead of a PyModule instance. */
#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC initCythonModule(void);
#else
PyMODINIT_FUNC PyInit_CythonModule(void);
#endif
#endif /* !__PYX_HAVE__CythonModule */