我有一个简单的hello world脚本,如果我想将其编译为在Linux机器上执行的二进制文件,该如何使用? 即使使用不同的体系结构,也必须能够在不同的计算机上执行相同的文件
这必须编译python3.6文件
我尝试过这些:
Pyinstaller. 2 problems, too big when compiled and won't run on different archs to the compiled one
Nuitka. Size is perfectly fine but it won't run on machines with a different arch type to the original one that compiled it
Cython. Same problem as Nuitka
还有其他建议吗?
结果应为:
python3 hello.py
Hello World
--compiled--
./hello
Hello World
答案 0 :(得分:1)
我今天开始扩展此答案,以提供示例代码。在这样做的过程中,我偶然发现了a recent blog post by Gregory Szorc的PyOxidizer工具,从表面上看,它可以完成您在OP中寻找的更多任务。它使用Rust将Python简化为机器代码,尽管它仍然在技术上需要运行时,但它将运行时嵌入可执行文件中,因此您无需捆绑文件。如果您尝试一下,我会对您的想法感兴趣。
由于我仍然认为我以前的答案可能有用,所以这里是更新:
我不知道100%的覆盖率解决方案。我认为这很大程度上取决于您的代码,复杂性,依赖关系和目标。
您提到尝试Cython。我认为除了您所看到的之外,还有更多东西。我对Cython不熟悉;当我阅读有关该主题的信息时,这只是一个选择。但是我认为您可以根据运行时要求使用它来构建本机可执行文件。
有关其他选项,请参见Is it feasible to compile Python to machine code?。
您还可以编写一个小型C程序来实例化python解释器,并从单独的文件或已编译的字节串中加载已编译的python字节码,从而自己构建可执行文件。有关详细信息,请参见Python embedding/extending documentation。
将Python代码构建到本机可执行文件中很容易(这称为 embeddding ),但是您说对了,您仍然需要Python运行时。但这是一个复杂性问题。对于足够小的用例,例如您的简单问候世界,您可以将实际依赖的元素捆绑到代码中。 (例如,静态链接到python库。)
如果您正在寻找一个可任意扩展的解决方案,那么一个常见的解决方案(从商业游戏到备份软件,我已经看到了这一解决方案)是将为目标平台预先编译的足够的python二进制运行时捆绑在一起,您可以预测或控制的安装前缀(即不是/usr
)。该捆绑软件通常包括任何机器代码(共享库)和根据需要编译的python字节码(.pyc
或.pyo
),而没有任何.py
文件。这不一定包括python安装的全部内容-仅仅是应用程序所需的机器代码和字节码。
这是一个非常简单的hello世界,用Python编写,但嵌入到C骨架中:
#include <Python.h>
int
main(int argc, char *argv[])
{
wchar_t *name = Py_DecodeLocale(argv[0], NULL);
if (name == NULL) {
fprintf(stderr, "error: cannot decode program name\n");
exit(1);
}
/* Setup */
Py_SetProgramName(name);
Py_Initialize();
/* Load and run code */
if (argc > 1)
PyRun_SimpleString(argv[1]);
else
PyRun_SimpleString("print('Hello, world')");
/* Importing and running code from a file is also possible.
* See https://docs.python.org/3/c-api/veryhigh.html
* and https://docs.python.org/3/c-api/import.html
*/
/* Clean up */
Py_Finalize();
PyMem_RawFree(name);
/* Ideally we should get a result from the interpreter
* and evaluate it, returning conditionally. Py_FinalizeEx()
* is a good way but it's only in Python 3.6+, so I'm leaving
* it out of this example. */
return 0;
}
为此,makefile
可能如下:
PY=python3
PC=$(PY)-config
all: py
py: py.o
$(CC) $$($(PC) --ldflags) -o $@ $< $$($(PC) --libs)
py.o: py.c
$(CC) $$($(PC) --cflags) -c $<
构建并运行:
$ make
gcc $(python3-config --cflags) -c py.c
gcc $(python3-config --ldflags) -o py py.o $(python3-config --libs)
$ ./py
Hello, world
$ ./py 'print("hi")'
hi
您可以在strace
下运行此命令,以查看运行时要求是什么:
$ strace -e trace=open ./py 2>&1 | grep py
...,然后您知道需要捆绑哪些文件。如果要拾取cpio文件中的每个文件,则将有一个可移植的应用程序。 (它只需要安装在同一位置即可。解决方法包括如上所述使用--prefix
从源代码构建python,并使用ldconfig和PYTHON_PATH玩奇怪的游戏。)