6.2. PikaScript C 模块开发流程
快速开始 -> keil 仿真工程 章节获取工程。
6.2.1. 新建模块接口
编写一个新的模块,首先需要编写模块接口文件,比如编写一个数学计算模块Math,第一步是编写 Math.pyi。
6.2.2. 编写类接口
Adder 类来实现相关的加法运算,我们就可以在 Math.py 里面添加 Adder 类。
Adder 可以为整形、浮点型数据提供加法运算,那么就可以添加 byInt 方法和 byFloat 方法。
# Math.pyiclass Adder: def byInt(self, a:int, b:int)->int: pass def byFloat(self, a:float, b:float)->float: pass
... 代替 pass 的写法也是合法的,例如:
# Math.pyiclass Addr: def byInt(self, a:int, b:int)->int:... def byFloat(self, a:float, b:float)->float:...
Adder 类,并添加了两个方法的声明,byInt(self, a:int, b:int)->int 表示方法名为 byInt ,输入参数为 a 和 b , a 和 b 的类型都是 int 型,而返回值也是 int 型,返回值由 ->int 来确定,这都是 python 的标准语法,是带类型注解的写法。
self 这是 python 的语法所要求的。
Multiplier 类,用来实现乘法,Multiplier 的写法如下所示:
# Math.pyiclass Multiplier: def byInt(self, a:int, b:int)->int: pass def byFloat(self, a:float, b:float)->float: pass
Math 模块,这样 Pika 预编译器就会去预编译 Math 模块了。
# main.pyimport Math
双击运行pika预编译器。 打开 pikascript-api 文件夹可以发现,我们新编写的模块接口对应的头文件已经可以被预编译出来了。
6.2.3. 编写类的实现
直接编译一下试试。
发现编译报错了,提示是有四个函数没有找到定义。
Math 模块的类编写实现,下面我们就来编写这些类的实现。
为了模块管理的方便,我们把实现文件都放在 pikascript-lib 文件夹下,
Math 模块的实现代码。
然后在 Math 文件夹下新建 .c 文件,建议用 “模块名_类名.c” 的命名方式为每一个类新建一个 .c 文件,提高代码的清晰性。
然后我们在这两个 .c 文件里面编写类的方法实现。那么问题来了,我们如何知道应当编写哪些实现呢?
这个很简单,我们打开 Math_Multiplier.h 和 Math_Adder.h 就可以发现,我们需要编写的实现函数已经被自动声明好了。
/* Math_Multiplier.h *//* ******************************** *//* Warning! Don't modify this file! *//* ******************************** */#ifndef __Math_Multiplier__H#define __Math_Multiplier__H#include <stdio.h>#include <stdlib.h>#include "PikaObj.h"PikaObj *New_Math_Multiplier(Args *args);double Math_Multiplier_byFloat(PikaObj *self, double a, double b);int Math_Multiplier_byInt(PikaObj *self, int a, int b);#endif
/* Math_Adder.h *//* ******************************** *//* Warning! Don't modify this file! *//* ******************************** */#ifndef __Math_Adder__H#define __Math_Adder__H#include <stdio.h>#include <stdlib.h>#include "PikaObj.h"PikaObj *New_Math_Adder(Args *args);double Math_Adder_byFloat(PikaObj *self, double a, double b);int Math_Adder_byInt(PikaObj *self, int a, int b);#endif
然后我们直接在 Math_Adder.c 和 Math_Multipler.c 里面去实现这四个函数就 ok 了。
/* Math_Adder.c */#include "pikaScript.h"double Math_Adder_byFloat(PikaObj *self, double a, double b){ return a + b;}int Math_Adder_byInt(PikaObj *self, int a, int b){ return a + b;}
/* Math_Multipler.c */#include "pikaScript.h"double Math_Multiplier_byFloat(PikaObj *self, double a, double b){ return a * b;}int Math_Multiplier_byInt(PikaObj *self, int a, int b){ return a * b;}
这时,再编译项目,就可以通过了。
6.2.4. 测试一下效果
我们用下面的 main.py 来测试一下我们新编写的模块
# main.pyimport Mathadder = Math.Adder()muler = Math.Multiplier()res1 = adder.byInt(1, 2)print('1 + 2')print(res1)res2 = adder.byFloat(2.3, 4.2)print('2.3 + 4.2')print(res2)res3 = muler.byInt(2, 3)print('2 * 3')print(res3)res4 = muler.byFloat(2.3, 44.2)print('2.3 * 44.2')print(res4)
运行的效果如下: 这说明我们编写的模块工作正常了。
6.2.5. 可用的类型注解
下面的表格列出了 PikaScript 支持的所有类型声明,以及它们与 C 语言的原生类型的对应关系。
注意
str作为返回值时,在 c 中返回的是char*,如果要返回的字串是函数中的局部变量,需要用obj_cacheStr进行缓存,避免出函数作用域后发生悬垂引用,如:return obj_cacheStr(self, res);。bytes作为返回值时,在 c 中返回的是Arg*,这是因为bytes需要指定长度,返回uint8_t*不能达到要求。正确返回方式为:return arg_newBytes(bytes, len);。6.2.6. 发布模块
出于开源的精神,发布你自己的模块是一件非常酷且激动人心的事情。 发布模块只需要发布类接口和类实现文件即可。 比如发布刚刚新编写的 Math 模块,就是发布 Math.pyi 文件和 pikascript-lib/Math 文件夹里的文件。 参与社区贡献->贡献模块 部分的文档发布你编写的模块。
