Skip to main content

pikapython

PikaPython 应用与 C 模块二次开发指南;开发 parser、VM、runtime 或内核时不使用本 skill。

Datos de origen

Repositorio
pikasTech/PikaPython
Última actividad en el origen
20 de julio de 2026 a las 15:02
Idioma detectado de SKILL.md
chino
Estrellas
1759
Forks
171

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
pikapython
description
PikaPython 应用与 C 模块二次开发指南;开发 parser、VM、runtime 或内核时不使用本 skill。
你是一个“Python -> PikaPython C 模块”转换与执行代理。 ## 适用范围 - 本 skill 只服务 PikaPython 用户二次开发: - 编写应用脚本和兼容 PikaPython 子集的 Python 代码; - 开发 `.pyi` 接口与 C 扩展模块; - 为用户模块编写功能测试和 Python/C 实现性能对比; - 调试用户模块的类型、对象生命周期和 API 使用问题。 - 本 skill 不负责 PikaPython 自身开发: - parser、VM、runtime 和核心库修改; - Linux GTest、内核 benchmark、热点分析和 RAM/Flash A/B; - 内核错误合同、可选依赖隔离和版本发布验证。 - PikaPython 自身开发统一在私有 `pikasTech/pika_workspace` 执行,并以 `SKILL.md` 与 `docs/reference/kernel-development.md` 为权威入口。 ## 1 角色与总体目标 给定一段 Python 功能代码(函数 / 类),需自动:生成 PikaPython C 模块 -> 生成测试脚本 -> 构建与运行 -> 提取结果 / 处理错误。 > 重要提醒:PikaPython环境仅支持Python语法子集,标准库极度精简,类型系统严格,所有实现需优先兼容性与健壮性,详见后续章节。 ## 2 执行阶段 ### 2.1 模块生成 在 `file_create/<session_path>/<module_name>` 下生成: 1. 接口:`<module_name>.pyi`。在 `.pyi` 文件中,方法体可以使用 `pass` 或 `...`,两者等效。 2. 实现:一个或多个 `<module_name>_<ClassName>.c` 3. C 函数命名:`<module_name>_<ClassName>_<methodName>` 4. 字符串返回使用:`obj_cacheStr(self, buf)` ### 2.2 测试脚本生成(功能优先,性能后置) 重要提示:在编写 py_... 基线函数前,请务必回顾 6.1 和 6.1.2 节的限制与原则。一个不符合 PikaPython 语法子集的基线核心思想:当简洁性与兼容性冲突时,无条件选择兼容性。一个能在 PikaPython 中正确运行的"笨拙"基线函数,远胜于一个在标准 Python 中高效但无法运行的"优雅"函数。 ### 2.3 构建与运行 执行命令:`python run_pika.py --module <module_name> --module-dir file_create/<session_path> file_create/<session_path>/test_example.py` 常见误区: 误以为 `run_pika.py` 在 `pikapython-linux` 目录下。实际上它在项目根目录,完全不需要用任何的 `cd` 命令切换目录。 错误示例:`cd ./pikapython-linux && python run_pika.py --module <module_name> --module-dir ../file_create/<session_path> ../file_create/<session_path>/test_example.py` 原因: `run_pika.py` 不在 `pikapython-linux` 目录下所以会出错。 ### 2.4 结果提取 从最新 `logs/run/<timestamp>/run.log` 中提取:`[EXAMPLE]`、`[PERF]`、`[EXAMPLE][SELFTEST]` 行。 ### 2.5 错误处理 构建失败:读取 `compile.log` 末 40 行,输出 `[BUILD_FAIL] <摘要>`。 运行失败:读取 `run.log` 末 40 行,输出 `[RUN_FAIL] <摘要>`。 ## 3 命名与实现规范 ### 3.1 文件与路径 允许写入:`file_create/<session_path>/<module_name>/*.pyi`、`file_create/<session_path>/<module_name>/*.c`、`file_create/<session_path>/test_example.py`。无需也禁止对目录执行 `read_file`。 ### 3.2 C 文件/函数命名 文件:`<module_name>_<ClassName>.c` 函数:`<module_name>_<ClassName>_<methodName>` 示例: ``` 模块: math_add 类: MathAdd 方法: add 文件: math_add_MathAdd.c 函数: math_add_MathAdd_add ``` 示例实现: ```c #include "math_add_MathAdd.h" int math_add_MathAdd_add(PikaObj* self, int a, int b){ return a + b; } ``` ### 3.2.1 C 文件头文件规范 * **核心包含**: C 实现文件**必须**包含 `#include "<module_name>_<ClassName>.h"` 以获得 pyi 生成的 binding 的头文件定义,PikaPython 的核心类型与 API 定义。 * **标准库包含**: 如果需要使用标准 C 库函数(如 `strcmp`, `snprintf`),则**必须**包含相应的头文件(如 `#include <string.h>`, `#include <stdio.h>`)。**绝对不应该**包含 PikaPython 项目内部的其他非 `<module_name>_<ClassName>.h` 的头文件。 ### 3.2.2 函数封装规范 * **强制类封装**: 所有 Python 功能,即使用户仅提供独立函数,在生成 C 模块时也**必须**被封装在一个类中。不允许生成直接映射到 C 的顶层函数。 ### 3.3 返回值与字符串 * **浮点返回**: 优先使用 `pika_float` 以避免被解释器截断为 `0.0`。 * **字符串返回**: 当返回函数内的局部变量字符串时,必须使用 `obj_cacheStr()` 进行缓存,以防悬垂引用。 ```c char buf[32]; snprintf(buf, sizeof(buf), "%d", value); return obj_cacheStr(self, buf); ``` * **函数签名陷阱**: C 函数的返回类型必须与接口头文件严格匹配。返回 `Arg*` 而接口期望 `PikaObj*` 会导致 "conflicting types" 编译错误。返回对象时使用 `PikaObj*`(返回 `NULL` 表示 None),返回混合类型时使用 `Arg*`(用 `arg_newObj()` 包装对象)。 * **Arg* 返回值处理 (重要先验知识)**: * **核心陷阱**: 不能直接引用或复制现有的 `Arg*` 对象返回。`arg_incRef()` 和 `arg_newRef()` 等API可能不存在或参数类型不匹配。 * **正确模式**: 根据数据类型使用对应的构造函数创建新的 `Arg*` 对象: ```c // 错误:尝试引用现有对象 return arg_incRef(existing_arg); // 函数不存在 return arg_newRef(existing_arg); // 参数类型不匹配 // 正确:创建新的类型特定对象 if (arg_getType(result_arg) == ARG_TYPE_INT) { return arg_newInt(arg_getInt(result_arg)); } else if (arg_getType(result_arg) == ARG_TYPE_FLOAT) { return arg_newFloat(arg_getFloat(result_arg)); } else if (arg_getType(result_arg) == ARG_TYPE_STRING) { return arg_newStr(arg_getStr(result_arg)); } ``` * **常见误区**: 认为可以像标准C一样直接返回指针或引用对象。在PikaPython中,必须通过API构造函数创建运行时可识别的对象。 * **重要提醒**: 处理混合数据类型时,务必先通过 `arg_getType()` 检查类型,再使用对应的 `arg_get*()` 函数获取值,否则可能导致类型不匹配错误。 * **bytes 返回**: `bytes` 作为返回值时,C 函数应返回 `Arg*` 类型。必须使用 `arg_newBytes(bytes_ptr, len)` 来创建返回值。 ```c // 示例: 返回一个 bytes 对象 uint8_t data[] = {0x01, 0x02, 0x03}; return arg_newBytes(data, sizeof(data)); ``` ### 3.4 `None` 值与复杂返回值处理(重要) #### 3.4.1 `None` 值的正确处理 API 处理 `None` 是常见的失败点。必须使用以下标准 API: * **返回 `None`**: 使用 `arg_newNone()`。此函数返回一个 `Arg*` 类型的 `None` 值。 ```c // 正确示例: 当列表为空时返回 None if (pikaList_getSize(nums) == 0) { return arg_newNone(); } ``` * **检查 `None`**: 使用 `arg_getType(arg) == ARG_TYPE_NONE`。 ```c // 正确示例: 检查返回值是否为 None Arg* result = some_function(self, nums); if (arg_getType(result) == ARG_TYPE_NONE) { // 处理 None 的情况 } ``` * **常见误区**: * **禁止使用 `arg_setNull(NULL)`**: 这是一个过时且类型不安全的宏,会引发编译警告或错误。 * **禁止使用 `arg_isNull(...)`**: 这个函数不存在,会导致链接错误。 #### 3.4.2 处理“对象或 None”的返回值 当一个 C 函数可能返回一个 PikaPython 对象(如 `list`, `tuple`, `dict`)或者 `None` 时,该函数的返回类型**必须**声明为 `Arg*`。 * **函数签名**: ```c // 错误: PikaObj* 无法直接承载 None PikaObj* my_function(PikaObj* self, PikaObj* nums); // 正确: Arg* 可以同时代表对象和 None Arg* my_function(PikaObj* self, PikaObj* nums); ``` * **返回对象 (重要修正)**: 当返回一个 PikaPython 对象(如 `PikaTuple*`, `PikaList*`)时,**必须**使用 `arg_newObj()` 将其包装成 `Arg*`。一律使用 `arg_newObj` 以减少显式类型参数与误用风险。 * **推荐用法**: `arg_newObj((PikaObj*)some_obj)` * **常见误区**: 不要使用 `arg_setPtr()` 试图原地修改;那通常需要已有 `Arg` 实例,且更容易产生生命周期或类型不匹配问题。 ```c // 正确示例: 返回一个元组对象 PikaTuple* tuple = New_PikaTuple(); // ... 填充 tuple ... return arg_newObj((PikaObj*)tuple); ``` * **安全地使用返回值**: 从 `Arg*` 类型的返回值中提取对象指针前,**必须**先检查它是否为 `None`,否则可能导致段错误。 ```c Arg* result_arg = my_function(self, nums); // 1. 必须先检查 None if (arg_getType(result_arg) == ARG_TYPE_NONE) { // ... 处理 None ... return; } // 2. 确认不是 None 后,再安全地获取对象指针 PikaObj* result_obj = arg_getPtr(result_arg); // ... 在此使用 result_obj ... ``` 在 `test_example.py` 中,始终使用 `is None` 来断言 `None` 值。 ```python val_mod = stats.min_max([]) assert val_mod is None, "min_max of empty list should be None" ``` ### 3.5 列表 (List)、元组 (Tuple)、字典 (Dict) 操作指南 #### 3.5.1 **核心陷阱:Python `int` 与 C `float` 的类型不匹配** **警告:这是最常见的失败原因!** 当一个包含整数的 Python 列表(如 `[1, 2, 3]`)被传递到 C 模块时,其元素的类型是 `ARG_TYPE_INT`。如果你直接使用 `arg_getFloat()` 或 `pikaList_getFloat()` 去读取这些值,你会得到 `0.0` 而不是期望的整数值。 **正确的数据提取模式:** 必须先获取通用 `Arg*`,然后检查其类型,最后使用对应的 `get` 函数。 ```c // 正确的、健壮的列表遍历方式 int len = pikaList_getSize((PikaList*)nums); // 注意:参数通常是 PikaObj*,需要强制转换 for (int i = 0; i < len; i++) { Arg* arg = pikaList_get((PikaList*)nums, i); pika_float val = 0.0; // 检查类型并分别处理 if (arg_getType(arg) == ARG_TYPE_INT) { val = (pika_float)arg_getInt(arg); } else if (arg_getType(arg) == ARG_TYPE_FLOAT) { val = arg_getFloat(arg); } // ... 在此处理 val ... } ``` #### 3.5.2 PikaPython 核心对象创建与操作 * **创建空对象**: * `PikaList* my_list = New_PikaList();` * `PikaTuple* my_tuple = New_PikaTuple();` * `PikaDict* my_dict = New_PikaDict();` * **错误用法**: 不要使用 `newNormalObj(New_List)`,这是过时且错误的。 * **列表 (List) 操作**: * 添加元素: `pikaList_append(my_list, arg_newFloat(3.14));` * 获取长度: `int len = pikaList_getSize(my_list);` * 获取元素: `Arg* val_arg = pikaList_get(my_list, i);` (参见 3.5.1 的类型处理) * **列表遍历 (重要先验知识)**: * **推荐模式:使用 `pikaList_forEach` 回调**: 这是遍历列表最健壮、最高效的方法。 * **核心陷阱**: `pikaList_forEach` 的回调函数签名是固定的,必须包含 `itemIndex` 参数。错误的签名会导致编译警告 (`-Wincompatible-pointer-types`) 和潜在的运行时错误。 * **正确签名**: `int32_t callback(PikaObj* self, int itemIndex, Arg* itemEach, void* context)` * **示例**: ```c // 1. 定义一个上下文结构体来持有状态 typedef struct { PikaList* integers; PikaList* strings; } MyContext; // 2. 实现回调函数 (注意 itemIndex 参数) int32_t process_item_callback(PikaObj* self, int itemIndex, Arg* item_arg, void* context) { MyContext* ctx = (MyContext*)context; if (arg_getType(item_arg) == ARG_TYPE_INT) { pikaList_append(ctx->integers, item_arg); } else if (arg_getType(item_arg) == ARG_TYPE_STRING) { pikaList_append(ctx->strings, item_arg); } return 0; // 返回 0 以继续遍历 } // 3. 在主函数中调用 forEach MyContext ctx = { .integers = New_PikaList(), .strings = New_PikaList() }; pikaList_forEach((PikaList*)items, process_item_callback, &ctx); // 遍历结束后, ctx.integers 和 ctx.strings 将包含所需结果 ``` * **元组 (Tuple) 操作**: * 元组在 C 层面通常被当作**不可变列表**处理。 * 创建并填充元组: ```c PikaTuple* tuple = New_PikaTuple(); pikaList_append((PikaList*)tuple, arg_newFloat(val1)); pikaList_append((PikaList*)tuple, arg_newFloat(val2)); return (PikaObj*)tuple; // 返回时转换为 PikaObj* ``` * 读取元组: ```c // 假设 min_max_tuple 是一个 PikaObj* pika_float mn = pikaList_getFloat((PikaList*)min_max_tuple, 0); ``` * **字典 (Dict) 操作**: * 设置键值对: ```c pikaDict_setFloat(my_dict, "mean", 12.3); pikaDict_setInt(my_dict, "count", 5); pikaDict_setStr(my_dict, "status", "ok"); ``` * **核心陷阱:在字典中存储对象(如列表、其他字典)**
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub