【发布时间】:2022-01-10 15:19:14
【问题描述】:
是否可以(以及如何)使用 MinGW-w64 为 Python 构建 C 扩展或在 Windows 上嵌入 Python?
我们以下面的 cython-extension foo.pyx 为例:
print("foo loaded")
如果应该嵌入解释器,则可以通过cython -3 foo.pyx 或cython -3 --embed foo.pyx 从中生成 C 代码。
【问题讨论】:
是否可以(以及如何)使用 MinGW-w64 为 Python 构建 C 扩展或在 Windows 上嵌入 Python?
我们以下面的 cython-extension foo.pyx 为例:
print("foo loaded")
如果应该嵌入解释器,则可以通过cython -3 foo.pyx 或cython -3 --embed foo.pyx 从中生成 C 代码。
【问题讨论】:
虽然 mingw-w64-compiler 并不真正受支持(唯一支持的 Windows 编译器是 MSVC),但它可用于创建 C 扩展或嵌入 Python。但是不能保证,这不会在未来的版本中中断。
distutils 不支持mingw-w64,因此设置 setup.py 文件没有任何好处 - 必须手动执行这些步骤。
首先我们需要distutils提供的一些信息:
pythonXY.dll 的路径,通常在python.exe 旁边。创建/生成 C 代码后,可以通过以下方式构建扩展
x86_64-w64-mingw32-gcc -shared foo.c -DMS_WIN64 -O2 <other_options> -I <path_to_python_include> -L <path_to_python_dll> -lpython37 -o foo.pyd
重要的细节是:
-O2 进行优化并将<other_options> 留空-MS_WIN64-macro 很重要(例如,通过-DMS_WIN64)。为了在 Windows 上构建 x64,必须设置它,但它只能开箱即用 for MSVC(定义 _WIN64 可能会产生略微不同的结果):#ifdef _WIN64
#define MS_WIN64
#endif
如果不这样做,至少对于 Cython 生成的文件,编译器将生成以下错误消息:
error: enumerator value for ‘__pyx_check_sizeof_voidp’ is not an integer constant
201 | enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
pyd只是一个伪装的dll,因此我们需要-shared选项,这意味着将创建一个动态库(即Linux世界中的共享对象)。
重要的是,python 库 (pythonXY) 应该是 dll 本身,而不是 lib(参见 SO-post)。我们使用pythonXY.dll(在我的例子中是python37)的路径而不是pythonXY.lib,因为它是MSVC的情况。
可能应该为生成的 pyd 文件添加正确的后缀,为了简单起见,我在这里使用旧的约定。
嵌入式 Python:
在这种情况下,应该构建一个可执行文件(例如,C 文件由 Cython 生成,带有--embed 选项:cython -3 --embed foo.pyx),因此命令行如下所示:
x86_64-w64-mingw32-gcc foo.c -DMS_WIN64 -O2 <other_options> -I <path_to_python_include> -L <path_to_python_dll> -lpython37 -o foo.exe -municode
有两个重要的区别:
-shared 不应再使用,因为结果不再是动态库(毕竟 *.pyd-file 就是这样),而是可执行文件。-municode 是必需的,因为对于 Windows,Cython 定义 int wmain(int argc, wchar_t **argv) 而不是 int main(int argc, char** argv)。如果没有此选项,则会出现类似的错误消息/build/mingw-w64-_1w3Xm/mingw-w64-4.0.4/mingw-w64-crt/crt/crt0_c.c:18: undefined reference to 'WinMain'
collect2: error: ld returned 1 exit status
会出现(有关详细信息,请参阅此SO-post)。
注意:要运行生成的可执行文件,需要一个完整的 python 分发版(不仅是 dll)(另请参阅SO-post),否则生成的可执行文件将因错误而中止(没有找到 python dll 或 python 安装或站点包 - 取决于运行 exe 的机器的配置)。
mingw-w64 也可以在 Linux 上用于 Windows 的交叉编译,请参阅此SO-post。
【讨论】: