【问题标题】:Compile main Python program using Cython使用 Cython 编译主要 Python 程序
【发布时间】:2011-02-24 13:48:32
【问题描述】:

我有一个 Python2.6 程序,可以加载使用 Cython 编译为 .so 文件的 Python 模块。我使用 Cython 将 .py 模块编译为 .so 文件,一切正常。

这是我在 Cython 中使用的 setup.py 文件:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_modules = [
    Extension("ldap", ["ldap.pyx"]),
    Extension("checker", ["checker.pyx"]),
    Extension("finder", ["finder.pyx"]),
    Extension("utils", ["utils.pyx"]),
]

setup(
  name = 'bchecker',
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules
)

所以我知道我可以使用 Cython 编译 Python 模块(我猜 Cython 从我的 Python 文件创建“C”文件然后编译它们),但是我可以将我的主要 Python 程序编译成我可以在 Linux 平台上执行的东西吗?如果是这样,将不胜感激 Cython 命令行示例。谢谢。

【问题讨论】:

  • 这些答案有用吗?你得到这个工作了吗?如果有,请采纳答案
  • 我怀疑这是否会被标记 - 用户最后一次被看到是在问题的编辑日期之后的一天。

标签: python cython


【解决方案1】:

与 Adam Matan 和其他人所断言的相反,您实际上可以使用 Cython 从纯 Python (.py) 文件创建单个可执行二进制文件。

是的,Cython 旨在按规定使用 - 作为一种简化为 CPython python 运行时编写 C/C++ 扩展模块的方式。

但是,正如 nudzo 在此 comment 中提到的那样,您可以在命令行提示符处使用 --embed 开关。

这是一个非常简单的例子。我正在使用 python3 和 cython3 从 Debian Sid 工作站执行此操作..

确保您事先安装了 python-devpython3-dev 软件包。

1) 创建一个非常简单的 Python 程序,名为 hello.py

$ cat hello.py

print("Hello World!")

2) 使用 Cython 将你的 python 程序编译成 C...

cython3 --embed -o hello.c hello.py

3) 使用 GCC 将 hello.c 编译成一个名为 hello...

的可执行文件
gcc -Os -I /usr/include/python3.3m -o hello hello.c -lpython3.3m -lpthread -lm -lutil -ldl

4) 你最终会得到一个名为 hello ...

的文件

$文件你好

你好:ELF 64 位 LSB 可执行文件,x86-64,版本 1 (SYSV), 动态链接(使用共享库),对于 GNU/Linux 2.6.32, BuildID[sha1]=006f45195a26f1949c6ed051df9cbd4433e1ac23,未剥离

$ ldd hello
linux-vdso.so.1 (0x00007fff273fe000)
libpython3.3m.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython3.3m.so.1.0 (0x00007fc61dc2c000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fc61da0f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fc61d70b000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fc61d508000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fc61d304000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc61cf5a000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fc61cd52000)
libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fc61cb28000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fc61c90f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc61e280000)

在这种情况下,可执行文件动态链接到我的 Debian 系统上的 Python 3.3。

5) 运行 hello...

$ ./你好

世界你好!

如您所见,使用这种方法,您基本上可以使用 Cython 将纯 Python 应用程序转换为可执行的编译目标代码。

我将这种方法用于更复杂的应用程序 - 例如,成熟的 Python/PySide/Qt 应用程序。

对于不同版本的 Python,您可以定制 gcc -I-l 开关以适合。

然后您可以将可执行文件打包为分发(.deb 等)文件,而无需打包 Python/PySide/Qt 文件 - 优点是即使在分发更新后您的应用程序仍应能够运行到该发行版上相同版本的 Python 等。

【讨论】:

  • 这种嵌入方式可以用来生成动态库而不是可执行文件吗?
  • 它不会将模块编译成可执行文件。是否有可能拥有一个可移植的可执行文件,即在源代码中导入的每个模块都将被编译到该可执行文件中。 @BrokenMan
  • @DeveshSaini 我没有花时间试图弄清楚这一点。我设法让一个成熟的 python+Pyside 应用程序像上面那样编译的唯一方法是以正常方式开发程序 - 大量的 include 语句 + 使用解释器进行测试。然后当一切准备就绪时,我手动粘贴所有包含的代码并注释掉它们替换的相关包含语句。是的,这是不可取的,但就像我一开始说的那样,我没有花时间看看如何只编译主例程并将包含的模块链接在一起。
  • libpython的静态链接呢?
  • 对于 python 2.7 cython --embed -o /tmp/a.c a.pygcc -Os -I /usr/include/python2.7 -o /tmp/a/tmp/a.c -lpython2.7 -lpthread -lm -lutil -ldl
【解决方案2】:

查看Can Cython compile to an EXE? 的答案,与此处所有其他答案相反,可以编译为可执行文件。

Embedding Cython 上的链接似乎是一个不错的起点,但这不是 Cython 的主要目的,所以我不知道它有多简单。

【讨论】:

  • 感谢您的链接。我也怀疑这可能是因为我使用 Python 创建包含可执行代码的 .so 文件。
【解决方案3】:

我不知道这是否会有所帮助,但 Nudzo 是正确的。你可以用cython --embed -o main.o main.py 得到它,然后我尝试用 cl/EHsc 编译结果

【讨论】:

    【解决方案4】:

    this发帖:

    cython <cython_file> --embed
    

    然后只是

    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>
    

    这里是一个例子:

    cython3 main.py --embed
    gcc main.c -I /usr/include/python3.8/ -L /lib/x86_64-linux-gnu/ -l python3.8 -o main
    

    【讨论】:

      【解决方案5】:

      你不能,Cython 不是用来编译 Python 也不是把它变成可执行文件。

      要生成 .exe 文件,请使用 py2exe

      要为 Mac 或 Linux 生成包,请使用常规打包系统进程,因为 Unix 环境中的脚本语言程序没有任何特定内容。

      【讨论】:

      • 它允许我将 .py 文件转换为 .so 文件。请参阅我使用的上述脚本。 .so 文件不包含可执行代码吗?
      • 这不是目的。 Cython 用于编译 C/C++ Python 扩展,而不是将 Python 脚本转换为可执行文件。
      • 错误信息。有cython --embed 可以生成嵌入Python 的可执行文件。
      • 生成的可执行文件仍然依赖于 libpython,除非您静态链接它。此外,它不会从您的所有文件中生成一个可执行文件,而是从您的入口点生成一个可执行文件。
      • @e-satis 是的,可执行文件将动态链接到当时编译它的 libpython 版本。有什么问题?如果它是针对 Linux 的,并且如果您打算分发您的应用程序,您只需将其打包为您所针对的任何 linux 分发格式 - 就像所有其他二进制包一样。例如myapp_1_wheezy_amd64.deb 将是您编译的 python 应用程序,链接到该发行版的 python2 或 python3。对于 Windows,只需提供所需的 python。同样,我看不到这里的问题或反对意见。
      猜你喜欢
      • 2014-09-01
      • 1970-01-01
      • 2011-05-24
      • 1970-01-01
      • 1970-01-01
      • 2014-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多