本文檔適用於但願使用基於SylixOS進行Python擴展庫開發的用戶。python
Python是一門面向對象的解釋型的腳本語言,Python具備豐富和強大的庫。它常被暱稱爲膠水語言,可以把用其餘語言製做的各類模塊(尤爲是C/C++)很輕鬆地聯結在一塊兒。常見的一種應用情形是,使用Python快速生成程序的原型(有時甚至是程序的最終界面),而後對其中有特別要求的部分,用更合適的語言改寫,好比3D遊戲中的圖形渲染模塊,性能要求特別高,就能夠用C/C++重寫,然後封裝爲Python能夠調用的擴展類庫。數組
目前SylixOS支持的Python爲3.6.4版本,支持絕大多數內建庫,但並未移植擴展庫。編輯器
可擴展性是Python的一大特點,Python的擴展庫能夠基於Python語言開發,也可經過C、JAVA等語言進行開發。函數
本文將介紹如何使用RealEvo-IDE開發C語言版本的SylixOS Python擴展庫。C語言版本Python擴展庫開發有如下兩種方式。性能
SylixOS下的Python支持ctypes內建模塊。此模塊的CDLL方法會調用SylixOS操做系統的dlopen()函數,從而導入用戶開發的C/C++動態庫。ui
編寫簡單的動態庫lib_demo,代碼如程序清單 3.1所示。spa
程序清單 3.1 動態庫demo操作系統
#include <stdio.h>對象
void lib_func (void)blog
{
printf("lib_func call!\n");
}
void hello (void)
{
printf("Hello SylixOS!\n");
}
int fact(int n)
{
if (n <= 1)
return 1;
else
return n * fact(n - 1);
}
將lib_demo編譯上傳至目標設備中。新建一個Python腳本test.py,使用VI編輯器編輯python腳本,內容以下:
import ctypes
demo=ctypes.CDLL("/lib/lib_demo.so")
print("-------------")
demo.lib_func()
print("-------------")
demo.hello()
print("-------------")
print(demo.fact(10))
print("-------------")
保存後執行「python test.py」,結果如圖 3.1 所示。
圖 3.1 python腳本執行結果
腳本執行結果顯示,動態庫內的函數被成功調用。
除了使用ctypes直接導入SylixOS動態庫外,python自己也提供自定義擴展庫的模板。經過模板封裝的C/C++動態庫,能夠直接使用python的「import」方法導入模塊。
依然以lib_demo爲例,首先須要添加所需頭文件的路徑。頭文件在SylixOS的/lib/python3/include目錄下提供,可自行拷貝至開發的動態庫目錄下。環境配置(以實際環境爲準)如圖 3.2 所示。
圖 3.2 選擇動態庫頭文件路徑
接着封裝動態庫,主要分爲4步:
a、包含Python頭文件;
添加頭文件:#include <Python.h>
b、利用樣板來包裝函數;
將lib_demo中的fact()函數封裝以下(並不是修改原函數,而是添加封裝函數)
static PyObject *lib_demo_fact(PyObject *self,PyObject *args) {
int num;
if(!(PyArg_ParseTuple(args,"i",&num))) { //獲取Python傳遞的參數
return NULL;
}
return (PyObject*)Py_BuildValue("i",fact(num));
//將結果轉換爲Python類型並返回
}
c、爲每一個模塊增長PyMethodDef ModuleMethods[]數組;
static PyMethodDef lib_demoMethods [] = {
{"fact",lib_demo_fact,METH_VARARGS}, //函數名,包裝函數名,解析
{"hello",lib_demo_hello,METH_NOARGS},
{"lib_func",lib_demo_lib_func,METH_NOARGS},
{NULL,NULL}, //做爲結束
};
d、編寫初始化函數。
static struct PyModuleDef lib_demoModule = {
PyModuleDef_HEAD_INIT, //默認
"lib_demo", //模塊名
NULL,
-1,
lib_demoMethods //上面的數組
};
PyMODINIT_FUNC
PyInit_lib_demo(void)
{
return PyModule_Create(&lib_demoModule);
}
封裝完成後的lib_demo如程序清單 3.2 所示。
程序清單 3.2 封裝完成的lib_demo
#include <Python.h>
#include <stdio.h>
int lib_func (void)
{
printf("lib_func call!\n");
return 0;
}
int hello (void)
{
printf("Hello SylixOS!\n");
return 0;
}
int fact(int n)
{
if (n <= 1)
return 1;
else
return n * fact(n - 1);
}
static PyObject *lib_demo_fact(PyObject *self,PyObject *args) {
int num;
if(!(PyArg_ParseTuple(args,"i",&num))) { //獲取Python傳遞的參數
return NULL;
}
return (PyObject*)Py_BuildValue("i",fact(num)); //將結果轉換爲Python類型並返回
}
static PyObject *lib_demo_hello(PyObject *self,PyObject *args) {
return (PyObject*)Py_BuildValue("i",hello());
}
static PyObject *lib_demo_lib_func(PyObject *self,PyObject *args) {
return (PyObject*)Py_BuildValue("i",lib_func());
}
static PyMethodDef lib_demoMethods[] = {
{"fact",lib_demo_fact,METH_VARARGS},//函數名,包裝函數名,解析
{"hello",lib_demo_hello,METH_NOARGS},
{"lib_func",lib_demo_lib_func,METH_NOARGS},
{NULL,NULL},//做爲結束
};
static struct PyModuleDef lib_demoModule = {
PyModuleDef_HEAD_INIT, //默認
"lib_demo", //模塊名
NULL,
-1,
lib_demoMethods //上面的數組
};
PyMODINIT_FUNC
PyInit_lib_demo(void)
{
return PyModule_Create(&lib_demoModule);
}
將編譯完成後的lib_demo.so上傳至目標設備的/lib/python3/lib/python3.6/lib-dynload目錄下。建立並編輯python腳本test2.py,內容以下。
import lib_demo as demo
print("-------------")
demo.lib_func()
print("-------------")
demo.hello()
print("-------------")
print(demo.fact(10))
print("-------------")
保存後執行「python test2.py」,輸出結果如圖 3.3 所示。
圖 3.3 test2腳本執行結果
腳本運行結果顯示,lib_demo模塊能被成功導入。