【问题标题】:Making an executable in Cython在 Cython 中制作可执行文件
【发布时间】:2014-04-25 19:12:07
【问题描述】:

一直在玩 cython。通常使用 Python 编程,但在前世使用过 C。 我不知道如何制作独立的可执行文件。

我已经下载了 cython,我可以制作一个 .pyx 文件(这只是一个带有 .pyx 扩展名的普通 Python 文件),它在 Python shell 中执行,使用: 导入pyximport; pyximport.install()

我可以在命令行生成一个 .c 文件:cython file.pyx 我可以通过构建标准 setup.py 并执行来生成 .so 文件:

setup.py build_ext --inplace

我尝试使用带有各种选项的 gcc 从 .so 文件中制作可执行文件,但总是有大量丢失的文件、头文件等。我尝试从几乎所有地方指向头文件,但没有成功,我不太熟悉所有 gcc 选项的作用,或者即使我应该使用 gcc。

由于我可以在 Python shell 中运行我的程序,但不能在命令行中运行我的程序,所以我在这里有一个断开连接,(我不希望用户必须进入 shell、导入模块等)。

我在这里错过了什么?

【问题讨论】:

  • cython myfile.pyx(不带选项)生成一个 .c 文件。当我使用 --embed 选项时,它会生成一个大 100 行的 .c 文件。对它们进行区分表明添加了一堆 ifdef。我仍然有一个问题:我如何使用这个.so?我似乎无法获得正确的编译器选项组合。阅读 numpy 的 cython 文档,一种方法是制作一个导入 .so 的包装 python 程序。我很惊讶当我隐藏 .c 和 .pyx 文件然后说:import NameOfMyFile without extensions,它似乎选择了 .so 文件。
  • @ostrokach 也链接到Can Cython compile to an EXE?

标签: python packages cython executable


【解决方案1】:

您想要的是 Cython 编译器的 --embed 标志。 没有大量文档,但this 是我能够找到的。它确实链接到一个简单的工作示例。

要将 Cython 源代码编译为 C 文件,然后可以编译为可执行文件,您可以使用 cython myfile.pyx --embed 之类的命令,然后使用您使用的任何 C 编译器进行编译。

当您编译 C 源代码时,您仍然需要包含包含 Python 头文件的目录并链接到您系统上相应的 Python 共享库(如果您是类似 libpython27.so 或 libpython27.a 的文件,则使用 Python 2.7)。

编辑:以下是有关如何获取包含正确标头和链接到正确库的命令的更多说明。

正如我之前所说,您需要像这样运行 Cython 编译器:

cython <cython_file> --embed

要使用 gcc 进行编译,您需要找到系统中 python 头文件的位置(您可以通过运行 distutils.sysconfig.get_python_inc() 获取此位置(您必须先导入它)。 它可能只是 Python 安装目录中的 /include 子目录。

您还必须找到 python 共享库。 对于 Python 2.7,在 Windows 上为 libpython27.a,在 Linux 上为 libpython2.7.so。

你的 gcc 命令将是

gcc <C_file_from_cython> -I<include_directory> -L<directory_containing_libpython> -l<name_of_libpython_without_lib_on_the_front> -o <output_file_name>

包含-fPIC 标志可能是明智之举。 在 Windows 64 位机器上,您还必须包含标志 -D MS_WIN64,告诉 mingw 为 64 位窗口编译。

如果您正在编译依赖于 NumPy 的内容,您还需要包含包含 NumPy 标头的目录。 您可以通过运行 numpy.get_include() 找到此文件夹(同样,在导入 numpy 之后)。 然后你的 gcc 命令就变成了

gcc <C_file_from_cython> -I<include_directory> -I<numpy_include_directory> -L<directory_containing_libpython> -l<name_of_libpython_without_lib_on_the_front> -o <output_file_name>

这个 gcc 命令选项guide 可能会有所帮助。

另外,如果可能,我建议您使用 Cython 内存视图。 这样您就不必包含 NumPy 标头并将 NumPy pxd 文件包含在 Cython 文件中。 它还使 C 编译器更容易优化切片操作。

【讨论】:

  • @HaydenDarcy 我最初使用 MinGW 进行了测试,尽管 MinGW 与最近的 Python 版本不兼容,甚至对于旧版本 libpython.a 可能需要单独安装。类似的方法应该适用于 MSVC。您必须更改为 MSVC 样式标志并链接到 libpython.dll 而不是 libpython.a 或 libpython.so。主要思想是 Cython 可以为独立的可执行文件生成代码,但是当您编译生成的文件时,您必须包含 Python 头文件并链接到 Python 运行时(并确保两者都可以在编译器搜索的路径中找到) .
  • 不要忘记添加 Chrome 驱动程序更改,因为它无法在另一台电脑上运行以及其他问题(正如我发现的那样)。它可以工作,虽然它不像我想象的那么简单。或者,分发 Winpython 准系统 + python 作业。如果您想要安全性,请添加 cython。正如人们会发现的那样,试图让 python 在没有 python 的情况下运行是可以理解的复杂且容易出错
  • Pyinstaller 只要您为 chrome 驱动程序提供正确的路径,就可以很好地工作。但是,当组合 pyinstaller + Cython 时会出现问题。请参阅:stackoverflow.com/questions/47026649/…。该文件令人难以置信的庞大。 Winpython + 标准 python 文件也可以工作。我还没有看到一个有效的独立 cython 或 nuitka 解决方案,尽管两者似乎都无法自行工作
  • 是的,你最终不得不依赖解释器和相应的运行时。重新分发这些文件会使文件变大。甚至静态编译方法也依赖于解释器并专注于编译扩展,而不是进行某种源到源的转换。由于 Python 中的所有动态特性,这种事情对于任意用户代码是不可能的。如果给定的可执行文件可以嵌入任意 Python 语义,那么它已经实现了某种解释器。对于任意用户代码,这是没有办法的。
  • 有没有人在带有 makefile 的 repo 中有完整的可重现示例?
【解决方案2】:

在 Ubuntu 上测试过:

使用以下 (Python 2) 安装 Cython:

sudo apt-get install cython

对于 Python 3:

sudo apt-get install cython3

要将 Python 代码编译为 C 代码运行(将 Python 3 的 cython 更改为 cython3):

cython --embed -o example.c example.py

这将生成example.c 文件。

现在编译example.c文件:

gcc -Os -I /usr/include/python2.7 example.c -lpython2.7 -o example

运行文件:

./example

现在对于 Python 3,这样的东西可以工作(未经测试):

gcc -Os -I /usr/include/python3.6 example.c -lpython3.6 -o example

python3.x 是您机器上安装的 Python 版本。

【讨论】:

  • 这会加载所有使用 cython 制作的导入和模块,对吗?
  • 如果你指的是 Python 导入和模块,是的。
  • 如何从多个 .py 文件生成独立文件?我有多个 python 文件,我想使用 cython 将它们全部编译成单个包。
  • 您是否尝试编译导入所有其他文件的主文件?
  • 并确保您要嵌入的 .py 文件的名称中不包含 -。使用foo_bar.py 之类的名称(而不是foo-bar.py)。
【解决方案3】:

这是 Windows + MS Visual Studio 14 的解决方案(因为还没有人提到 cl.exe 参数)。

首先使用embed参数生成test.c文件:

cython test.pyx --embed

然后编译它:

call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x64
cl test.c /I C:\Python37\include /link C:\Python37\libs\python37.lib

输出是小的可执行文件test.exe(在我的情况下,print("Hello World") 为 140 KB)。

注意事项:

【讨论】:

    猜你喜欢
    • 2016-04-28
    • 2017-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    相关资源
    最近更新 更多