在 C 中将 Cython 模块构建为 运行 - ModuleNotFoundError

Building Cython module to run in C - ModuleNotFoundError

我有一个 Cython 模块,我想在 C 中调用 运行,但我收到 ModuleNotFound 错误。据我所知,我正在按照文档和其他 SO 问题中的说明进行操作,但是除了简单的 1 文件示例(即非模块化)之外,使用 Cython 将 Python 转换为 C 的示例有限。

我在 Ubuntu 上 运行ning Python 3.6(通过 Windows 10 WSL1)。

这是一个显示问题的简化示例:

树:

├── Makefile
├── main.c
├── main_cy.pyx
├── mod_dir
│   ├── __init__.pxd    #empty
│   ├── mod.pxd
│   └── mod.pyx
└── setup_cy.py

mod_dir/mod.pxd:

cdef public int say_hello_from_mod() except -1

mod_dir/mod.pyx:

TEXT_TO_SAY = 'Hello from Python!'

cdef public int say_hello_from_mod() except -1:
    print(TEXT_TO_SAY)
    return 0

main_cy.pyx:

print('hello from main_cy')
from mod_dir.mod cimport say_hello_from_mod

cdef public int say_hello_from_main_cy() except -1:
    say_hello_from_mod()
    return 0

main.c:

#include "main_cy.h"

int main(int argc, char *argv[])
{
    PyObject *pmodule;
    wchar_t *program;

    program = Py_DecodeLocale(argv[0], NULL);
    if (program == NULL) {
        fprintf(stderr, "Fatal error: cannot decode argv[0], got %d arguments\n", argc);
        exit(1);
    }

    /* Add a built-in module, before Py_Initialize */
    if (PyImport_AppendInittab("main_cy", PyInit_main_cy) == -1) {
        fprintf(stderr, "Error: could not extend in-built modules table\n");
        exit(1);
    }

    /* Pass argv[0] to the Python interpreter */
    Py_SetProgramName(program);

    /* Initialize the Python interpreter.  Required. If this step fails, it will be a fatal error. */
    Py_Initialize();

    /* Optionally import the module; alternatively, import can be deferred until the main_cy script imports it. */
    pmodule = PyImport_ImportModule("main_cy");
    if (!pmodule) {
        PyErr_Print();
        fprintf(stderr, "Error: could not import module 'main_cy'\n");
        goto exit_with_error;
    }

    printf("Hello from C!\n");

    /* Now call into your module code. */
    if (say_hello_from_main_cy() < 0) {
        PyErr_Print();
        fprintf(stderr, "Error in Python code, exception was printed.\n");
        goto exit_with_error;
    }

    /* Clean up after using CPython. */
    PyMem_RawFree(program);
    Py_Finalize();

    return 0;

    /* Clean up in the error cases above. */
exit_with_error:
    PyMem_RawFree(program);
    Py_Finalize();
    return 1;
}

setup_cy.py:

from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules = cythonize(['mod_dir/mod.pyx', 'main_cy.pyx'], annotate=False,language_level=3, include_path=['./', './mod_dir/'])
)

生成文件:

all:
    gcc -c main_cy.c -o main_cy.o <cflags>
    gcc -c main.c -o main_c.o <cflags>
    gcc main_c.o main_cy.o -o main.o <ldflags> 

当我 运行 Cython 设置 (python setup_cy.py build_ext --inplace) 时,它在主目录和 [=50= 中成功创建了 *.c、*.h 和 *.so 文件].然后,当我 运行 make 时,它​​ 运行 没有错误并创建了所有 *.o 文件。但是,当我 运行 C 可执行文件 (./main.o) 时,我得到以下 运行 时间错误:

Traceback (most recent call last):
  File "main_cy.pyx", line 1, in init main_cy
    # main_cy.pyx
ModuleNotFoundError: No module named 'mod_dir'
Error: could not import module 'main_cy'

谢谢!

好的,我设法找到了解决方案 here(brm 的回答),但我会在此处重新发布,以防其他人有同样的问题。显然 Python shell 会自动将工作目录添加到路径中,但是 Py_Initialize() 在嵌入 C 时不会这样做。要手动执行此操作,我只需要添加main.c 中 Py_Initialize(); 之后的第 import sys\nsys.path.insert(0, '') 行。重新编译后,可执行文件按预期运行。