Cython编译调用厂商DLL时extern语句相关报错问题求助
问题描述
编写Cython代码调用厂商提供的DLL文件时,运行构建脚本出现无法自行解决的错误,执行命令python setup.py build_ext -i的输出如下:
PS C:\Users\Ben\Documents\UCLA\Research\Hardware\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\cython_attempt_2> python setup.py build_ext -i running build_ext cythoning FWB5180_pythonWrapper.pyx to FWB5180_pythonWrapper.c C:\Users\Ben\AppData\Local\Programs\Python\Python39\lib\site-packages\Cython\Compiler\Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: C:\Users\Ben\Documents\UCLA\Research\Hardware\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\cython_attempt_2\FWB5180_pythonWrapper.pyx tree = Parsing.p_module(s, pxd, full_module_name) building 'fwb' extension creating build creating build\temp.win-amd64-3.9 creating build\temp.win-amd64-3.9\Release C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -IC:\Users\Ben\AppData\Local\Programs\Python\Python39\include -IC:\Users\Ben\AppData\Local\Programs\Python\Python39\include -IC:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326\ATLMFC\include -IC:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.32.31326\include -IC:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um -IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt -IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared -IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um -IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt -IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt /TcFWB5180_pythonWrapper.c /Fobuild\temp.win-amd64-3.9\Release\FWB5180_pythonWrapper.obj FWB5180_pythonWrapper.c C:\Users\Ben\Documents\UCLA\Research\Hardware\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\cython_attempt_2\FWB5180.h(15): error C2059: syntax error: 'string' C:\Users\Ben\Documents\UCLA\Research\Hardware\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\cython_attempt_2\FWB5180.h(16): error C2059: syntax error: 'string' C:\Users\Ben\Documents\UCLA\Research\Hardware\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\cython_attempt_2\FWB5180.h(17): error C2059: syntax error: 'string' FWB5180_pythonWrapper.c(1112): warning C4013: 'openUSB5100' undefined; assuming extern returning int error: command 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.32.31326\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2
其中字符串语法错误指向extern声明中的"C"字段,同时伴随openUSB5100未定义的告警,已按规则编写相关函数声明。
所有相关文件、依赖的usb5100.dll、libusb0.dll均存放在同一目录下,使用Microsoft Visual Studio 2022作为编译器,此前已成功构建其他示例项目,可排除基础环境配置问题。
涉及文件代码
- 头文件
FWB5180.h
#ifdef USB5100_EXPORTS #define USB5100_API __declspec(dllexport) #else #define USB5100_API __declspec(dllimport) #endif extern "C" USB5100_API unsigned int openUSB5100(void); extern "C" USB5100_API void closeUSB5100(unsigned int fwb5000ID); extern "C" USB5100_API int scpiCommand(unsigned int usbID,char* cmd, char* result, int len);
- Cython适配声明文件
c_FWB5180.pxd
cdef extern from "FWB5180.h": int openUSB5100() void closeUSB5100(int devID) int scpiCommand(int devID,char* cmd, char* result, int length)
- Python包装实现文件
FWB5180_pythonWrapper.pyx
cimport c_FWB5180 def open_connection(): devID = c_FWB5180.openUSB5100() print(devID) return devID
- 构建脚本
setup.py
from distutils.core import setup from distutils.extension import Extension from Cython.Distutils import build_ext ext_modules = [ Extension('fwb', ['FWB5180_pythonWrapper.pyx'], language="c", libraries=['usb5100.dll','libusb0.dll'], library_dirs=['.']) ] setup( name = 'FWB python wrapper', cmdclass = {'build_ext': build_ext}, ext_modules = ext_modules )
问题原因与修复方案
核心报错原因
setup.py中明确指定了language="c",MSVC编译器会按照纯C标准编译生成的C文件,但厂商提供的头文件里使用了C++专属的extern "C"语法,纯C编译器无法识别该写法,直接把"C"判定为非法语法抛出C2059错误。头文件解析失败后,内部声明的函数自然无法被编译器识别,进而触发后续openUSB5100未定义的告警。
修复步骤
- 修改头文件兼容C编译环境
给extern "C"添加C++环境判断宏,纯C编译时自动忽略该段语法,修改后的FWB5180.h代码如下:
#ifdef USB5100_EXPORTS #define USB5100_API __declspec(dllexport) #else #define USB5100_API __declspec(dllimport) #endif #ifdef __cplusplus extern "C" { #endif USB5100_API unsigned int openUSB5100(void); USB5100_API void closeUSB5100(unsigned int fwb5000ID); USB5100_API int scpiCommand(unsigned int usbID,char* cmd, char* result, int len); #ifdef __cplusplus } #endif
- 修正函数类型不匹配问题
厂商头文件中openUSB5100返回值、closeUSB5100入参均为unsigned int,pxd中声明为int会引发类型不匹配问题,极端情况会导致运行时异常,修改c_FWB5180.pxd为:
cdef extern from "FWB5180.h": ctypedef unsigned int uint uint openUSB5100() void closeUSB5100(uint devID) int scpiCommand(uint devID, char* cmd, char* result, int length)
同步调整FWB5180_pythonWrapper.pyx中的变量类型适配即可。
3. 消除版本兼容警告
在FWB5180_pythonWrapper.pyx第一行添加编译指令,指定Python3语法规则,避免默认使用Py2兼容模式触发的FutureWarning:
# cython: language_level=3 cimport c_FWB5180 def open_connection(): devID = c_FWB5180.openUSB5100() print(devID) return devID
- 修正链接库配置
Windows下MSVC链接动态库不需要带.dll后缀,直接填写库名即可,将setup.py中libraries参数修改为libraries=['usb5100','libusb0'],否则会触发找不到链接库的错误。
完成上述修改后重新执行python setup.py build_ext -i即可正常完成编译。
内容的提问来源于stack exchange,提问作者bpound
相关产品推荐
相关产品推荐

