【问题标题】:How to create C-extension/embed Python with MinGW-w64 on Windows如何在 Windows 上使用 MinGW-w64 创建 C 扩展/嵌入 Python
【发布时间】:2022-01-10 15:19:14
【问题描述】:

是否可以(以及如何)使用 MinGW-w64 为 Python 构建 C 扩展或在 Windows 上嵌入 Python?

我们以下面的 cython-extension foo.pyx 为例:

print("foo loaded")

如果应该嵌入解释器,则可以通过cython -3 foo.pyxcython -3 --embed foo.pyx 从中生成 C 代码。

【问题讨论】:

    标签: python cython mingw-w64


    【解决方案1】:

    虽然 mingw-w64-compiler 并不真正受支持(唯一支持的 Windows 编译器是 MSVC),但它可用于创建 C 扩展或嵌入 Python。但是不能保证,这不会在未来的版本中中断。

    distutils 不支持mingw-w64,因此设置 setup.py 文件没有任何好处 - 必须手动执行这些步骤。

    首先我们需要distutils提供的一些信息:

    • 标题: 我们需要 Python 包含的路径。有关找到它们的方法,请参阅SO-post
    • DLL: mingw-w64 的链接器与 MSVC 的工作方式不同:需要 python-dll 和 not python-lib。所以我们需要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 进行优化并将&lt;other_options&gt; 留空-
    • 定义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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-16
      • 2011-04-12
      • 1970-01-01
      • 2017-02-13
      • 2010-11-04
      • 2012-03-11
      相关资源
      最近更新 更多