无法找到通过 C 语言构建的 cython 函数

问题描述 投票:0回答:1

我有一个包含以下模块的 Cython 项目:

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()

设置.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}
)

运行.py:

import os
import sys
from CythonModule import PyFuncSwo
sys.path.insert(0, os.path.abspath("."))


if __name__ == '__main__':
    PyFuncSwo()

这工作得很好,当我运行

python setup.py build_ext --inplace && python run.py
时,代码编译并运行,同时还为我提供了一个新的
CythonModule.cp39-win_amd64.pyd
文件。现在我需要在纯 C/C++ 代码中从 .pyd 模块调用
PyFuncSwo()
。通过网络冲浪,我遇到了以下示例:

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;
}

使用 gcc 编译此代码,因为

gcc -g RunCythonInC.c -o RunCythonInC.exe
编译时出现以下警告,但是当我运行 RunCythonInC.exe 时,我总是得到
PyFuncSwo not found in CythonModule.cp39-win_amd64.pyd
.

我也将

GetProcAddress(h_dll, "PyFuncSwo")
更改为
GetProcAddress(h_dll, "CPyFuncSwo")
但我仍然遇到同样的错误。我尝试的其他事情是用 _ 作为
GetProcAddress(h_dll, "_PyFuncSwo")
调用 cython 函数,但仍然得到相同的结果。谁能告诉我,如何在纯 C 代码中从 .pyd 模块调用我的 cython 函数?

更新:

根据 Cython 的文档Here,似乎在 C 中声明 cython 函数的正确方法是将 cython 函数类型定义为 public 并构建它。这将生成一个“CythonModule.h”头文件,可以将其包含在您的 C 代码中,然后可以调用 cython 函数。

按照这个指令,我想出了以下 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;
}

并将

def PyFuncSwo()
更改为
cdef public void PyFuncSwo()
.

现在我得到以下错误:

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: in function `main':
Z:\pathto\cython/run.c:7: undefined reference to `__imp_PyImport_AppendInittab'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: Z:\pathto\cython/run.c:8: undefined reference to `__imp_Py_Initialize'
c:/mingw/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: Z:\pathto\cython/run.c:9: undefined reference to `__imp_PyImport_ImportM
odule'
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 */

c cython
1个回答
1
投票

您的直接问题是符号可见性。这些功能需要

cdef public
并且可能 需要在 Windows 上手动导出.

然而

你想做的是错误的而且不太可能奏效。

Cython 不创建独立的 C 函数。相反,它生成 Python 模块。 Cython 函数有两个重要的先决条件:

  1. Python 解释器正在运行。
  2. Cython 模块的模块导入函数必须已经被调用。

如果不满足这些先决条件,函数可能会以意想不到和令人困惑的方式崩溃。

从 C 调用 Cython 函数的正确方法 在 Cython 文档 中有介绍,不涉及

GetProcAddress
.

© www.soinside.com 2019 - 2024. All rights reserved.