我正在努力将Python模块移植到Windows.我有一个玩具示例如下.
文件夹结构是:
foo/ libfoo/ foo.c setup.py
setup.py
from setuptools import setup, Extension sources = ['libfoo/foo.c'] foo = Extension('libfoo', sources = sources, define_macros = None, include_dirs = ['./libfoo'], libraries = None, library_dirs = None, ) setup(name = 'foo', ext_modules = [foo], install_requires = ['setuptools'], )
libfoo/foo.c(完整性)
#includevoid foo() { printf("Hello World!"); }
当我尝试安装包时,遇到错误.
C:\Users\user\foo>python setup.py install running install running bdist_egg running egg_info creating foo.egg-info writing requirements to foo.egg-info\requires.txt writing foo.egg-info\PKG-INFO writing top-level names to foo.egg-info\top_level.txt writing dependency_links to foo.egg-info\dependency_links.txt writing manifest file 'foo.egg-info\SOURCES.txt' reading manifest file 'foo.egg-info\SOURCES.txt' writing manifest file 'foo.egg-info\SOURCES.txt' installing library code to build\bdist.win32\egg running install_lib running build_ext building 'libfoo' extension creating build creating build\temp.win32-2.7 creating build\temp.win32-2.7\Release creating build\temp.win32-2.7\Release\libfoo c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\cl.exe /c /nologo /Ox /MD /W3 /GS- /DNDEBUG -I./libfoo -IC:\Python27\include -IC:\Python27\PC /Tclibfo o/foo.c /Fobuild\temp.win32-2.7\Release\libfoo/foo.obj foo.c creating build\lib.win32-2.7 c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:C:\Python27\libs /LIBPATH:C:\Python27\PCbuild /EXPORT:i nitlibfoo build\temp.win32-2.7\Release\libfoo/foo.obj /OUT:build\lib.win32-2.7\l ibfoo.pyd /IMPLIB:build\temp.win32-2.7\Release\libfoo\libfoo.lib /MANIFESTFILE:b uild\temp.win32-2.7\Release\libfoo\libfoo.pyd.manifest LINK : error LNK2001: unresolved external symbol initlibfoo build\temp.win32-2.7\Release\libfoo\libfoo.lib : fatal error LNK1120: 1 unresolv ed externals error: command 'c:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\BIN\\l ink.exe' failed with exit status 1120
似乎distutils包(在本例中为setuputils)将始终从共享扩展中导出一个符号,即"init + extension_name" [Link].
它在Windows链接器"导出"选项[链接]中指定,但找不到该符号.
救命?
编辑:C代码不使用Python C API,即"#include".这是因为该项目的目标是获取现有的C库并通过Python扩展包含在Python包装器中.该软件包适用于Unix/Linux.
经过大量的游戏,我能够理解这个问题.
解决方案:在Windows中,您必须为扩展定义初始化函数,因为setuptools将构建.pyd文件,而不是DLL要在Python 2中解决此问题,请initlibfoo()
在源中定义方法.
#includePyMODINIT_FUNC initlibfoo(void) { // do stuff... }
要在Python 3中解决此问题,请PyInit_libfoo()
在源中定义方法.
#includePyMODINIT_FUNC PyInit_libfoo(void) { // do stuff... }
所以现在,foo.c看起来像:
#include#include void foo() { printf("Hello World!"); } PyMODINIT_FUNC initlibfoo(void) // Python 2.7 //PyMODINIT_FUNC PyInit_libfoo(void) // Python 3.5 { // do stuff... }
在为Windows编译Python扩展时,Extension类将告诉链接器为其他要调用的程序导出函数.这可以在终端输出中看到:
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:C:\Python27\libs /LIBPATH:C:\Python27\PCbuild /EXPORT:i nitlibfoo build\temp.win32-2.7\Release\libfoo/foo.obj /OUT:build\lib.win32-2.7\l ibfoo.pyd /IMPLIB:build\temp.win32-2.7\Release\libfoo\libfoo.lib /MANIFESTFILE:b uild\temp.win32-2.7\Release\libfoo\libfoo.pyd.manifest
(强调/EXPORT:initlibfoo
)
现在,这是C/C++ Extensions的必需功能,因此可以将它们作为模块导入.换句话说,当你import libfoo
将Python initlibfoo
作为模块初始化的一部分调用.pyd上的函数时.这里遇到的错误是由于链接器被告知导出函数initlibfoo
但是它无法在C对象文件中找到符号,因为它从未在源中定义过!
当然,人们应该能够拒绝出口符号的选择吗?显然不是.回到Extension类文档,有一个参数export_symbols
.我尝试传递None
给它并且仍在使用链接器选项.似乎没有办法绕过这个链接器选项.
不推荐:如果由于某种原因,需要Python.h
困扰你,那就有办法解决这个问题.你仍然需要定义上面的"init"方法,但你可以这样做:
void initlibfoo() {} //Python 2.7 void PyInit_libfoo() {} //Python 3.5
但是现在,您无法使用库import libfoo
.您可以使用ctypes模块并加载它ctypes.PyDLL('/path/to/pyd')
.基本上,您使用Python为您构建DLL,在这种情况下,它会,但它构建一个称为.pyd文件的特殊DLL.然后要使用它,您必须在via ctypes模块中加载它.