使用 WINAPI 的 Cython DLL 扩展编译在链接期间失败,并出现错误 LNK2001

Cython DLL extension compilation using WINAPI fails during linking with error LNK2001

提问人:user3324315 提问时间:1/3/2022 更新时间:1/7/2022 访问量:137

问:

我正在尝试将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 文档明确指出支持调用约定,因此我尝试:

  1. 将 WINAPI 调用约定添加到 pxd 文件,但在文件循环化期间,我在 C 变量声明中出现语法错误
  2. 直接添加__stdcall调用约定,因为程序无论如何都应该以 64 位编译。但我仍然得到LNK2001线在寻找__cdecl就好像 Cython 绕过了调用约定一样。实际上,这是生成的 cpp 文件中的行:
    __pyx_v_ret = PDC_CloseDevice(__pyx_v_self->device_nb, (&__pyx_v_error_code));

__cdecl警告也可能是一条红鲱鱼,但我没有其他线索,而且我通常不在 Windows 下编译,所以我对这些工具的了解有限。

Windows WinAPI Cython 链接器错误

评论

1赞 ead 1/4/2022
链接器找不到所需的符号。可能库名称或它们的路径是错误的。 应该只具有库的名称(即PDCLIB),应该是路径(以硬编码名称开头,以确保没有错误)。还要重新检查 python 确实是 64 位而不是 32 位。librarieslibrary_dirs
0赞 user3324315 1/4/2022
@ead我检查了 python 版本,环境确实是 64 位。 我还检查了(并对其进行了检查)以检查它是否正确。我将库修改为仅名称(尝试小写和大写)但无济于事。有趣的是,如果我故意在库名称中引入拼写错误,它会触发一个LNK1181错误,指出它找不到库,如果没有拼写错误,这种情况就不会发生。[这个问题]stackoverflow.com/q/47740418/3324315 很接近,但它不起作用。>>> import struct;print( 8 * struct.calcsize("P")) 64 library_dirsos.path.exists

答:

0赞 user3324315 1/7/2022 #1

在尝试了其他所有方法(包括正确编译的 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

我在编译中看到的主要区别是

  1. 它现在用 C 语言编译,因为没有更多的扩展类型(cdef 类)
  2. pyx 文件与 pxd 文件同名

安装文件中的编译和链接选项如下:

extra_compile_args=['/Gz', '/fp:precise', '/Zc:wchar_t', '/Zc:forScope', '/Zc:inline'],
extra_link_args=['/DEBUG', '/MACHINE:X64'],