将python程序编译为可在C中导入的库

时间:2018-01-22 01:00:55

标签: python c compilation cython

我今天开始wondering whether it is possible to save a python object for use in a C program,这个提议经过几个小时的阅读看起来很幼稚。这是一个可能的解决方法:

1。创建一个依赖于许多python库的复杂对象,其中包含我需要保留的数据  2.将复杂物体腌制并放置在可接近的位置  3.定义compileme.py:

import pickle
thing = pickle.load(open('thing.pkl', 'r'))# an object with a method query(),
                                           # which takes a numpy array as input

4。 cython --embed -o compileme.c compileme.py生成脚本的.c版本 5.定义main.c:

#include <stdio.h>
#include//(A) something from compileme

int main(void) {
    input = //(B) query takes a numpy array in python. Define something palatable.
    double result = thing.query(input);
    printf("%d", result);
}

6。正确编译main.c,具有所有正确的链接。

我不清楚这个基本的解决方案策略是否合理,我有很多顾虑:

  1. thing是来自此处未提及的库的类,因此其query()方法依赖于外部python。如何确保相关部件也被编译和链接?
  2. 我应该如何在compileme中加入main.c,以便thing可以在那里访问? (代码中的位置(A))
  3. 如何在此处正确定义thing方法的输入?我是否需要使用compileme.c中定义的众多类型之一? (代码中的位置(B))
  4. 如何使用正确的链接编译main.c
  5. 在执行所有这些操作时,似乎我必须包含对python-dev包中的python头文件的引用。为了清楚起见,我实际上并没有通过这样做包括翻译,对吗?
  6. 以下是我在搜索过程中发现的一些资源,证明可以将简单的python脚本编译为可执行的已编译C程序:Compile main Python program using Cython http://masnun.rocks/2016/10/01/creating-an-executable-file-using-cython/

    以下是一些相关的cython文档: http://cython.readthedocs.io/en/latest/src/reference/compilation.html

1 个答案:

答案 0 :(得分:2)

我担心这个答案只是解释了为什么我不认为你想要的是现实的,而不是提供解决方案。值得查看Cython为稍微修改后的compileme.pyx

生成的代码
cdef public get_unpickled():
    import pickle
    return pickle.load(open('thing.pkl', 'r'))

这会创建一个您可以愉快地从C调用的函数(签名在compileme.h中生成,并且是__PYX_EXTERN_C PyObject *get_unpickled(void);)。生成的包含实现的“.c”文件很长,但相关部分如下所示:

__pyx_t_1 = __Pyx_Import(__pyx_n_s_pickle, 0, -1);
__pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_v_pickle, __pyx_n_s_load);
__pyx_t_3 = __Pyx_PyObject_Call(__pyx_builtin_open, __pyx_tuple_, NULL);
__pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_3);

为了清楚起见,我已经将这一点减少了很多(主要是删除了引用计数和一些检查),但你可以看到它使用Python导入机制从Python标准库加载pickle模块,它确实getattr获取函数load。它调用Python内置open,然后调用pickle.load。所有这些操作都需要libpython。

然后我们考虑what pickle does - 它基本上得到你的类来自的.py文件,导入它,并创建你的类的新实例,然后使用文件中的数据填充实例字典(可能会调用一些特殊方法,如果存在)。同样,这完全取决于使用Python。

最后,让我们考虑一下get_unpickled的结果。你有一个PyObject*,一个相当不透明的C结构。它的大部分信息可能存储在其内部Python字典中,您可以通过Python C API PyObject_GetAttrString和相关函数访问它。但是,此数据仍然存储为您需要使用Python C API访问的其他PyObject。 (如果它是一个Cython类,数据可能存储在更易于访问的C结构字段中,这些字段需要较少使用libpython,但可能不需要使用。)

总之,Cython主要使用Python C API实现,它需要访问libpython库,除了绝对最简单的程序。使用诸如pickle之类的Python标准库函数也需要安装Python标准库。因此,如果不需要将Python与C程序捆绑在一起,就无法实现这一目标。您链接的示例属于此类别 - 它们是C程序,但它们依赖于Python存在。

更好的解决方案可能是查看Python和C支持的常见序列化格式,例如JSON,XML或HDF5,以允许您以一种语言保存数据并在另一种语言中以尽可能少的方式将其检索到可能的。