在 Python 中编译和连接 C DLL 可以在 Unix 上运行,但不能在 Windows 上运行。这样做的正确方法是什么?
Compiling and interfacing with a C DLL within Python works on Unix, but not Windows. What is the correct way to do this?
所以,我有以下文件:
addone.c
long int addone(long int x){
return x+1;
}
然后通过 windows 安装 GCC 7.2.0 将其编译成 DLL(在将函数更改为 extern "C" long int addone(long int x)
之后,我也尝试使用 Intel C++ 编译器,但是当我尝试将其加载到 Python):
时不会改变结果
gcc -c addone.c
gcc -shared -o addone.dll addone.o
然后我尝试加载到 python 3.6.7:
import ctypes
_addone = ctypes.CDLL("addone.dll")
虽然我设法获得了 CDLL 对象,但它缺少函数 "addone"。我试过使用 ctypes.WinDLL()
和 ctypes.windll.LoadLibrary
方法导入 C DLL,但这些都实现了相同的最终结果:我从 ctypes 获得了一个没有 public 方法的对象,并且 none 的私有方法(在 Python 对象中,而不是 DLL)似乎与 addone 函数有关。
为了仔细检查我的编译器是否按照我的预期进行,我反汇编了生成的 DLL,它看起来像一个典型的 DLL。在内部,该函数甚至没有名称错误:
0000000530ce1030 <add_one>:
530ce1030: 55 push %rbp
530ce1031: 48 89 e5 mov %rsp,%rbp
530ce1034: 48 89 4d 10 mov %rcx,0x10(%rbp)
530ce1038: 48 8b 45 10 mov 0x10(%rbp),%rax
530ce103c: 48 83 c0 01 add [=15=]x1,%rax
530ce1040: 5d pop %rbp
530ce1041: c3 retq
530ce1042: 90 nop
<Everything between these two instructions is just more no-ops>
530ce104f: 90 nop
我已经能够在 Unix 系统上完成这项工作,并且在该平台上将 C DLL 与 Python 连接起来没有任何问题。然而,移动到 Windows,我觉得我缺少了一些东西。即使在不同的机器上尝试所有这些,我仍然无法访问我编写的函数。
我觉得我在这里遗漏了什么。我做错了什么?
尝试导出函数:
#include "addone.h"
EXPORT long int addone(long int x){
return x+1;
}
并制作头文件addone.h
:
#define EXPORT __declspec(dllexport)
EXPORT long int addone(long int x);
经过一番摆弄,我明白了是怎么回事。
函数确实正确编写,正确编译成DLL,正确创建ctypes.CDLL对象。
ctypes.CDLL 对象没有立即 "see" 函数名,因此它不在方法列表中。我所做的是忽略该方法不在对象的名称空间中这一事实,我大胆地调用了 _addone.addone(x)
。这使对象意识到该函数在DLL中,并将其添加到命名空间中。
我怀疑 ctypes 中有一些后端正在进行,调用函数会导致它检查该名称是否确实存在于库中。也许这是为了防止命名空间被编译器放置到 DLL 中的各种其他函数弄乱。
所以,我有以下文件:
addone.c
long int addone(long int x){
return x+1;
}
然后通过 windows 安装 GCC 7.2.0 将其编译成 DLL(在将函数更改为 extern "C" long int addone(long int x)
之后,我也尝试使用 Intel C++ 编译器,但是当我尝试将其加载到 Python):
gcc -c addone.c
gcc -shared -o addone.dll addone.o
然后我尝试加载到 python 3.6.7:
import ctypes
_addone = ctypes.CDLL("addone.dll")
虽然我设法获得了 CDLL 对象,但它缺少函数 "addone"。我试过使用 ctypes.WinDLL()
和 ctypes.windll.LoadLibrary
方法导入 C DLL,但这些都实现了相同的最终结果:我从 ctypes 获得了一个没有 public 方法的对象,并且 none 的私有方法(在 Python 对象中,而不是 DLL)似乎与 addone 函数有关。
为了仔细检查我的编译器是否按照我的预期进行,我反汇编了生成的 DLL,它看起来像一个典型的 DLL。在内部,该函数甚至没有名称错误:
0000000530ce1030 <add_one>:
530ce1030: 55 push %rbp
530ce1031: 48 89 e5 mov %rsp,%rbp
530ce1034: 48 89 4d 10 mov %rcx,0x10(%rbp)
530ce1038: 48 8b 45 10 mov 0x10(%rbp),%rax
530ce103c: 48 83 c0 01 add [=15=]x1,%rax
530ce1040: 5d pop %rbp
530ce1041: c3 retq
530ce1042: 90 nop
<Everything between these two instructions is just more no-ops>
530ce104f: 90 nop
我已经能够在 Unix 系统上完成这项工作,并且在该平台上将 C DLL 与 Python 连接起来没有任何问题。然而,移动到 Windows,我觉得我缺少了一些东西。即使在不同的机器上尝试所有这些,我仍然无法访问我编写的函数。
我觉得我在这里遗漏了什么。我做错了什么?
尝试导出函数:
#include "addone.h"
EXPORT long int addone(long int x){
return x+1;
}
并制作头文件addone.h
:
#define EXPORT __declspec(dllexport)
EXPORT long int addone(long int x);
经过一番摆弄,我明白了是怎么回事。
函数确实正确编写,正确编译成DLL,正确创建ctypes.CDLL对象。
ctypes.CDLL 对象没有立即 "see" 函数名,因此它不在方法列表中。我所做的是忽略该方法不在对象的名称空间中这一事实,我大胆地调用了 _addone.addone(x)
。这使对象意识到该函数在DLL中,并将其添加到命名空间中。
我怀疑 ctypes 中有一些后端正在进行,调用函数会导致它检查该名称是否确实存在于库中。也许这是为了防止命名空间被编译器放置到 DLL 中的各种其他函数弄乱。