我正在尝试使用distutils模块在Linux for Windows(mingw32)上交叉编译一个简单的SWIG Python扩展。
最终目标是为某些库编译Python包装器并能够在Windows上使用它。显然,我从最基本的例子开始,不幸的是它失败了。
以下是我正在使用的文件:
example.c
/* File : example.c */
/* A global variable */
double Foo = 3.0;
/* Compute the greatest common divisor of positive integers */
int gcd(int x, int y) {
int g;
g = y;
while (x > 0) {
g = x;
x = y % x;
y = g;
}
return g;
}
example.i - SWIG界面文件
/* File : example.i */
%module example
%inline %{
extern int gcd(int x, int y);
extern double Foo;
%}
setup.py
# setup.py
import distutils
from distutils.core import setup, Extension
setup(name = "SWIG example",
version = "1.0",
ext_modules = [Extension("_example", ["example.i","example.c"])])
为了使用本机(Linux)gcc编译器进行编译,我正在调用:
python setup.py build
一切都像魅力一样!不幸的是,在尝试指定Windows目标时:
python setup.py build --compiler=mingw32
我收到错误消息,指出gcc无法识别-mdll开关:
running build
running build_ext
building '_example' extension
swigging example.i to example_wrap.c
swig -python -o example_wrap.c example.i
creating build
creating build/temp.linux-x86_64-2.7
gcc -mdll -O -Wall -I/home/jojek/anaconda/include/python2.7 -c example_wrap.c -o build/temp.linux-x86_64-2.7/example_wrap.o
gcc: error: unrecognized command line option ‘-mdll’
error: command 'gcc' failed with exit status 1
很公平,因为工具链无效,所以很有道理。我确保在我的计算机上安装了mingw32
。通过调用dpkg -L mingw32
,我知道编译器位于/usr/bin/i586-mingw32msvc-gcc
。
我的下一步是用我的编译器的实际路径覆盖CC环境变量。当我尝试再次编译它时,我收到以下错误,缺少sys/select.h
头文件:
running build
running build_ext
building '_example' extension
swigging example.i to example_wrap.c
swig -python -o example_wrap.c example.i
creating build
creating build/temp.linux-x86_64-2.7
/usr/bin/i586-mingw32msvc-gcc -fno-strict-aliasing -g -O2 -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -I/home/jojek/anaconda/include/python2.7 -c example_wrap.c -o build/temp.linux-x86_64-2.7/example_wrap.o
example_wrap.c:1: warning: -fPIC ignored for target (all code is position independent)
In file included from /home/jojek/anaconda/include/python2.7/Python.h:58,
from example_wrap.c:125:
/home/jojek/anaconda/include/python2.7/pyport.h:351:24: error: sys/select.h: No such file or directory
error: command '/usr/bin/i586-mingw32msvc-gcc' failed with exit status 1
有没有人知道如何管理这项任务?
答案 0 :(得分:4)
使用distutils编译Python模块时,幕后有很多事情要做。您在问题中的每次尝试都越来越近了,但是您现在遇到的问题是您正在使用带有Windows(交叉)编译器的Linux头文件。 (sys/select.h isn't supported with mingw32,cygwin可能是一个不同的故事)。实际上,缺少配置头文件导致您的交叉编译尝试使用POSIX接口而不是Win32替代品。
我的回答回过头来,开始简单地手工构建模块,在Linux上使用mingw32,然后我们会在我们证明我们已经完成了所有这些工作之后使用distutils。
我还假设您没有Windows构建盒(甚至是VM)可用于在Windows上本地构建扩展,因为这比交叉编译简单得多。如果您正在阅读本文并且可以选择使用Windows框来构建Windows Python扩展,请执行此操作,以节省时间和精力。也就是说,只使用Linux机器就可以构建Windows Python模块。
从mingw32开始已经安装并在Linux机器上工作(例如使用Debian / Ubuntu软件包),第一步是获取Windows头文件(或配置更具体)。我假设您的目标是大多数人在搜索引擎中键入“python windows”时所获得的构建,因此我从python.org下载了Windows MSI安装程序并从那里提取了它们。
我们希望从Python发行版中获得两件事:
在Linux下,有几种不同的方法可以提取它。您可以使用Wine来安装MSI文件。我在测试中使用了cabextract和7z,但是使用了cabextract:
cabextract /tmp/python-2.7.10.msi -F '*.h'
cabextract /tmp/python-2.7.10.msi -F 'python27.dll'
(注意:如果您使用7z,您将在名为'python'的第二个内部存档中找到您真正想要的文件。)
此时你还可以解压缩文件'libpython27.a',它通常位于c:\ python27 \ libs \中,但是这个文件对于使用mingw32进行链接是不够的,甚至没用。
鉴于头文件我们现在已经足够编译我们的扩展,虽然如上所述让mingw32链接到python27.dll我们需要先做一些工作。我们需要一个名为pexports的工具来列出Python DLL中的所有导出符号,然后让dlltool生成一个存根库,供mingw32链接。我直接下载了pexports,然后用以下内容解压缩:
tar xvf ~/Downloads/pexports-0.47-mingw32-bin.tar.xz
一旦提取完毕,我们就会获得一个Windows可执行文件。我在这里的例子中使用Wine直接运行它;或者,您可以提取源代码,并将其构建为在Linux主机上本机运行的工具:
tar xvf ~/Downloads/pexports-0.47-mingw32-src.tar.xz
(cd pexports-0.47 && ./configure && make)
或者您可以使用Python模块pefile(运行良好的跨平台)复制该工具的功能,以提取我们关心的导出,如果您还希望避免使用Wine。
无论如何使用pexports,你可以生成一个包含dlltool所需信息的.def文件:
wine bin/pexports.exe -v python27.dll > python27.def
或,(如果你已经将pexports作为本机工具构建),只需:
./pexports-0.47/pexports -v python27.dll > python27.def
其中python27.dll是我们之前从.msi文件中提取的内容。
(这是我的pexports reference)
获得.def文件后,您可以使用mingw32 dlltool生成一个.a文件,稍后我们将用它来链接我们的Python模块:
i586-mingw32msvc-dlltool -A --dllname python27.dll --def python27.def --output-lib libpython27.a
现在我们已经达到了这样的程度,我们可以考虑运行SWIG本身来生成代码供我们编译。我进一步简化了你的示例界面:
%module test
%inline %{
int gcd(int x, int y) {
int g;
g = y;
while (x > 0) {
g = x;
x = y % x;
y = g;
}
return g;
}
%}
然后在我的Linux机器上运行SWIG:
swig -Wall -python test.i
这生成了我编译的test_wrap.c:
i586-mingw32msvc-gcc test_wrap.c -I../include -Wall -Wextra -shared -o _test.pyd ./libpython27.a
我们有一个仅使用Linux构建的Windows Python模块。
要检查它是否真正运行,我将test.py和_test.pyd复制到Windows框中,然后执行:
Python 2.7.10 (default, May 23 2015, 09:40:32) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> test.gcd(1024, 512)
512
>>>
现在剩下的就是确保distutils可以通过操纵路径来找到要链接的正确包含文件和库。
答案 1 :(得分:1)
对于64位,我无法使其与pexports一起使用,因此我使用gendef生成了python27.def文件。
gendef 是一个从DLL生成def文件的工具。 def文件是DLL导出的符号列表。此工具的主要用途是允许创建由非GCC编译器创建的DLL导入库。它可以同时处理x86(win32)和amd64(win64)可执行文件。
https://sourceforge.net/p/mingw-w64/wiki2/gendef/
希望有帮助!