python - 动态加载的 DLL 导致 Python 初始化失败
问题描述
我和同事一起尝试通过 Cython 将 Python 文件转换为 C 文件。之后,我们尝试从 C 文件中制作一个 DLL。但是,这不起作用,Python 文件的初始化失败。
为了完整起见,这里是我的代码和我执行的步骤:
Python 文件:hello.pyx
cdef public int sayHello ():
print("hello out there")
cdef int a = 5
return a
为了从 hello.pyx 创建一个 C 文件,我们在终端中使用了以下命令:
Cython -3 hello.pyx
然后创建一个 hello.h 文件和一个 hello.c 文件。hello.c 文件包含大量代码,我是 C 编程的非常非常初学者。因此,我并不完全了解其中发生的一切。我的同事支持我对以下文件进行更改。
为了使这些方法可以在 DLL 中访问,我们在最后的hello.c文件中添加:
__declspec(dllexport) int Py_sayHello()
{
return __Pyx_PyInt_As_int(sayHello());
}
并通过以下方式替换了hello.h文件中的方法:
#ifndef __PYX_HAVE__hello
#define __PYX_HAVE__hello
#include "Python.h"
extern "C"
{
__declspec(dllexport) int Py_sayHello();
__declspec(dllexport) void Py_init();
}
#endif /* !__PYX_HAVE__hello */
我们将 hello.c 文件中的第 203 行更改为:
enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
至
enum { __pyx_check_sizeof_voidp = (int)(SIZEOF_VOID_P == sizeof(void*)) };
修复错误。
之后我们执行以下两个命令来创建 dll。
gcc -c -DBUILD_DLL hello.c -IC:/Users/hannah/Anaconda3/include
gcc -shared -o hello.dll hello.o -LC:/Users/hannah/Anaconda3/libs -lpyhton38
这成功地创建了 hello.dll。如果我用 Dependency Walker 打开这个 DLL,我看到有 2 种方法可用: 依赖 Walker 中的方法
当我们尝试通过 DLL 调用函数时,程序在 Python 文件的初始化处停止。要调用函数,我们使用以下代码:
#ifndef DLLHANDLER_C_
#define DLLHANDLER_C_
#include <windows.h>
#include <winbase.h>
#include <windef.h>
#include <stdio.h>
typedef int (*pFunHello)();
typedef void (*pFunInit)(void);
int loadDLL();
int main(){
//int x = 100;
//int x = loadDLL();
loadDLL();
}
int loadDLL( ) {
int status = 10;
pFunHello _TestFunc;
pFunInit _Py_init;
HMODULE testLibrary = LoadLibrary("hello.dll");
if (testLibrary != NULL)
{
printf("Library successfully loaded.\n");
_Py_init = (pFunInit)GetProcAddress(testLibrary, "PyInit_hello");
if (_Py_init != NULL)
{
printf("PyInit_hello successfully cached.\n");
_Py_init();
printf("Python initialization successful.\n");
_TestFunc = (pFunHello)GetProcAddress(testLibrary, "Py_sayHello");
if (_TestFunc != NULL)
{
printf("Py_sayHello successfully cached.\n");
status = _TestFunc();
printf("Py_sayHello returned %d\n", status);
}
else
{
printf("Error when caching Py_sayHello: %d\n", GetLastError());
}
}
else
{
printf("Error when caching PyInit_hello: %d\n", GetLastError());
}
FreeLibrary(testLibrary);
}
else
{
printf("Error occurred when loading library: %d\n", GetLastError());
}
return status;
}
#endif
输出是:
Library successfully loaded.
PyInit_hello successfully cached.
Calling PyModuleDef_Init...
在命令行中通过命令:
echo %Error Level%
出现错误代码-1073741819,表示“访问冲突错误”。我的同事能够确定,错误来自 python38.dll 中的 PyModuleDef_Init。
希望你们中的一些人可以帮助我们解决这个问题。有人对cython有很多经验吗?我们如何修复这个错误并使 hello.dll 正常工作?
解决方案
推荐阅读
- node.js - 如何登录保护节点/反应中的静态 html 页面?
- python - 不确定为什么当它是一种方法时它是不可调用的
- python - 每个数组中的元素数量如何最终少于其父数组(数组数组)中的元素数量
- php - 在php中提交表单时页面挂起
- powerbi - Power BI - 带有过滤器的 rankx
- asp.net-mvc - 如何将毫秒转换为 hh mm ss 格式并将其保存在 Db 中
- reactjs - 无法读取未定义反应挂钩的属性“位置”
- sqlite - Microsoft Access 与 SQLite 后端 #DELETED 记录问题 - 另一种解决方案
- r - 如何在具有多个 data.frame 的列表中进一步过滤变量
- java - ClassGraph,如何过滤类路径的内容