提问人:user3324315 提问时间:1/3/2022 更新时间:1/7/2022 访问量:137
使用 WINAPI 的 Cython DLL 扩展编译在链接期间失败,并出现错误 LNK2001
Cython DLL extension compilation using WINAPI fails during linking with error LNK2001
问:
我正在尝试将Cython接口写入(Photron)相机驱动程序DLL。此库提供了一个 SDK,其中包含 32 位和 64 位的头文件和 Windows 库。我已经在 VisualStudio 中使用这个库成功编译了一个 C++ 示例。另一方面,Cython 编译在链接时失败。
自定义 Cython 代码由包含类型的 typedefs.pxd 文件、包含 SDK 标头中的常量和函数声明的 photron.pxd 文件以及 camera.pyx 文件中的包装器 cdef 类组成。
在 setup.py 文件中,在“扩展”(从 setuptools 导入)部分中,我包含以下部分:
include_dirs=[s.path.abspath(os.path.normpath('./include'))],
libraries=[os.path.join(os.path.abspath(os.curdir), 'Lib', '64bit(x64)', 'PDCLIB')],
library_dirs=[os.path.abspath(os.path.normpath('./Lib/64bit(x64)'))],
我还尝试了成功编译 C++ 的命令行中的标志。 为了让初始的cythonization步骤正常工作(生成cpp文件),我还必须将其添加到SDK的标题中:
#include <windows.h>
以下是 pxd 文件的相关摘录:
from typedefs cimport ulong, uint
cdef extern from "PDCFUNC.h":
ulong PDC_CloseDevice(ulong nDeviceNo, ulong *pErrorCode)
当我尝试编译代码时,我得到了cpp文件,但是当尝试链接时,我得到了一系列行,如下,对于我在pxd文件中声明的每个函数,如下所示:
camera.obj : error LNK2001: unresolved external symbol "unsigned long __cdecl PDC_CloseDevice(unsigned long,unsigned long *)" (?PDC_CloseDevice@@YAKKPEAK@Z)
我想这是因为链接器试图在指定的标头中查找__cdecl函数,尽管这些函数在头文件中是这样声明的:
unsigned long WINAPI PDC_CloseDevice(unsigned long nDeviceNo, unsigned long *pErrorCode);
由于 Cython 文档明确指出支持调用约定,因此我尝试:
- 将 WINAPI 调用约定添加到 pxd 文件,但在文件循环化期间,我在 C 变量声明中出现语法错误。
- 直接添加__stdcall调用约定,因为程序无论如何都应该以 64 位编译。但我仍然得到LNK2001线在寻找__cdecl就好像 Cython 绕过了调用约定一样。实际上,这是生成的 cpp 文件中的行:
__pyx_v_ret = PDC_CloseDevice(__pyx_v_self->device_nb, (&__pyx_v_error_code));
__cdecl警告也可能是一条红鲱鱼,但我没有其他线索,而且我通常不在 Windows 下编译,所以我对这些工具的了解有限。
答:
在尝试了其他所有方法(包括正确编译的 Visual Studio 项目中的所有选项)之后,我重新启动了一个最小的示例,其中 pxd 文件中只有以下内容
cdef extern from "PDCLIB.h"
ulong __stdcall PDC_Init(ulong *pErrorCode)
ulong __stdcall PDC_CloseDevice(ulong nDeviceNo, ulong *pErrorCode)
以及一个更简单的 pyx 文件,除了扩展名之外,名称相同。
from pyphotron_pdclib cimport *
from typedefs cimport ulong, uint
cpdef init_pdc_lib():
cdef ulong error_code = 0
success = PDC_Init(&error_code)
assert success != 0
cpdef close_cam(ulong dev_num):
cdef ulong error_code = 0
success = PDC_CloseDevice(dev_num, &error_code)
assert success != 0
我在编译中看到的主要区别是
- 它现在用 C 语言编译,因为没有更多的扩展类型(cdef 类)
- pyx 文件与 pxd 文件同名
安装文件中的编译和链接选项如下:
extra_compile_args=['/Gz', '/fp:precise', '/Zc:wchar_t', '/Zc:forScope', '/Zc:inline'],
extra_link_args=['/DEBUG', '/MACHINE:X64'],
评论
libraries
library_dirs
>>> import struct;print( 8 * struct.calcsize("P")) 64
library_dirs
os.path.exists