259 lines
8.3 KiB
Markdown
259 lines
8.3 KiB
Markdown
# 10 - 模块与导入系统
|
||
|
||
Viper 的模块系统基于 Python 的 `import` 语法,但编译时通过 TransPyC 的符号表和类型系统实现跨模块的类型解析。
|
||
|
||
## 导入语法
|
||
|
||
### 标准导入
|
||
|
||
```python
|
||
import t, c # Viper 内置类型和操作模块
|
||
import asm # 汇编辅助模块
|
||
import string # 字符串操作模块
|
||
```
|
||
|
||
### 模块导入
|
||
|
||
```python
|
||
import bootinfo
|
||
import intr
|
||
import platform.pch as pch
|
||
import drivers.serial.uart.serial as serial
|
||
```
|
||
|
||
### from 导入
|
||
|
||
```python
|
||
from stdint import * # 导入所有 stdint 类型别名
|
||
from drivers.video.vesafb.vga import _VGAScreenDriver
|
||
```
|
||
|
||
### 相对导入
|
||
|
||
```python
|
||
from . import submodule
|
||
from .. import parent_module
|
||
```
|
||
|
||
## 特殊模块
|
||
|
||
### `t` 模块
|
||
|
||
类型定义模块,提供所有 C 类型对应的 Viper 类型。每个 Viper 文件通常都需要导入:
|
||
|
||
```python
|
||
import t
|
||
```
|
||
|
||
### `c` 模块
|
||
|
||
C 语言操作模块,提供指针操作、内联汇编、预处理指令等:
|
||
|
||
```python
|
||
import c
|
||
```
|
||
|
||
### `asm` 模块
|
||
|
||
汇编辅助模块,提供常用汇编指令的封装:
|
||
|
||
```python
|
||
import asm
|
||
|
||
asm.sti() # __asm__ __volatile__("sti");
|
||
asm.hlt() # __asm__ __volatile__("hlt");
|
||
asm.cli() # __asm__ __volatile__("cli");
|
||
asm.nop() # __asm__ __volatile__("nop");
|
||
asm.BSSClean() # 清零 BSS 段
|
||
```
|
||
|
||
### `string` 模块
|
||
|
||
字符串/内存操作模块,对应 C 标准库的 `string.h`:
|
||
> string 部分使用 x86_64 专有汇编进行加速,因此某些函数在其它架构可能需要手动重新编写。
|
||
|
||
```python
|
||
import string
|
||
|
||
string.memset(c.Addr(buf), 0, 64) # memset(&buf, 0, 64);
|
||
string.memcpy(dst, src, size) # memcpy(dst, src, size);
|
||
string.memmove(dst, src, size) # memmove(dst, src, size);
|
||
string.memcmp(a, b, size) # memcmp(a, b, size);
|
||
string.strcmp(a, b) # strcmp(a, b);
|
||
string.strcpy(dst, src) # strcpy(dst, src);
|
||
```
|
||
|
||
### `stdint` 模块
|
||
|
||
提供 C `stdint.h` 中的类型别名:
|
||
|
||
```python
|
||
from stdint import *
|
||
|
||
# 提供以下类型别名:
|
||
# UINT8PTR, UINT16PTR, UINT32PTR, UINT64PTR
|
||
# INT8PTR, INT16PTR, INT32PTR, INT64PTR
|
||
# 等等
|
||
```
|
||
|
||
### `viperlib` 模块
|
||
|
||
ViperOS 标准库,提供常用 C 库函数:
|
||
|
||
```python
|
||
import viperlib
|
||
|
||
viperlib.snprintf(c.Addr(buf), 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42);
|
||
```
|
||
|
||
### `vpsdk` 模块
|
||
|
||
> vpsdk 模块 专供于基于 Viper 开发的示例操作系统 ViperOS,不可用于其它平台,且需要特殊配置。
|
||
|
||
ViperOS 应用 SDK,提供系统调用和窗口管理:
|
||
|
||
```python
|
||
import vpsdk.window as window
|
||
import vpsdk.process as process
|
||
import vpsdk.dynlib as dynlib
|
||
import vpsdk.syscall as syscall
|
||
```
|
||
|
||
### `ast` 模块(自研解析器)
|
||
|
||
[includes/ast](../includes/ast) 是**完全自研的 Python 解析器**(词法器 + 语法器 + AST 构造,约 4176 LOC),覆盖 CPython 几乎全部语法。这是向 `TransPyV` 完全自举的关键组件——自举后编译器不再依赖 Python 运行时解析源文件。
|
||
|
||
```python
|
||
from ast import parse, parse_expression
|
||
|
||
root: AST | t.CPtr = parse(src, pool) # 解析整个源文件
|
||
expr: AST | t.CPtr = parse_expression(src, pool) # 解析单个表达式
|
||
```
|
||
|
||
AST 采用**胖节点**设计:70+ 变体共用一个 struct,用 `vtype`(`ASTVType` 枚举)区分类型,通用字段直接属性访问。详见 [13-bootstrapping.md](13-bootstrapping.md) 和 [Test/AstTest](../Test/AstTest)。
|
||
|
||
### `llvmlite` 模块(自研 IR 生成库)
|
||
|
||
[includes/llvmlite](../includes/llvmlite) 是**完全自研的 LLVM IR 文本生成库**(约 1500 LOC),封装类型/值/模块/函数/基本块/构造器的创建与打印。同样是自举的关键组件。
|
||
|
||
```python
|
||
from llvmlite import LLVMTypeCore, LLVMModuleCore
|
||
|
||
type_core: LLVMTypeCore = LLVMTypeCore(pool)
|
||
i32: LLVMType | t.CPtr = type_core.Int32()
|
||
ptr_ty: LLVMType | t.CPtr = type_core.Ptr(i32)
|
||
|
||
mod_core: LLVMModuleCore = LLVMModuleCore(pool)
|
||
mod: Module | t.CPtr = mod_core.NewModule("main")
|
||
func: Function | t.CPtr = mod_core.CreateFunction(mod, "main", ret_ty)
|
||
```
|
||
|
||
类型系统用 `t.REnum`(`LLVMType`,少变体适合 match),指令 opcode 用 `t.CEnum`(`IROp`),对象分配用普通类 + `mpool`。详见 [includes/llvmlite/README.md](../includes/llvmlite/README.md) 的选型论证。
|
||
|
||
### `linkedlist` 模块(NoVTable + PEP 695 泛型示范)
|
||
|
||
[includes/linkedlist](../includes/linkedlist.py) 提供链表实现,是 `@t.NoVTable` 非多态继承和 PEP 695 递归泛型继承的典范用例:
|
||
|
||
```python
|
||
from linkedlist import LinkedNode, GSList
|
||
|
||
@t.NoVTable
|
||
class Node(LinkedNode): # 非多态继承,零 vtable 开销
|
||
value: t.CInt
|
||
|
||
lst: GSList[Node] | t.CPtr = GSList[Node]()
|
||
node: Node | t.CPtr = Node()
|
||
node.value = 42
|
||
lst.append(node) # 类型安全:append 只接受 Node
|
||
```
|
||
|
||
包含 `LinkedNode`/`SListNode`(双向/单向节点)和 `GSList[T]`(泛型链表,支持递归泛型继承 `class GNode(GSListNode[GNode])`)。详见 [05-classes.md 的泛型类章节](05-classes.md#泛型类pep-695-语法) 和 [06-oop.md 的 NoVTable 章节](06-oop.md#tnovtable-非多态继承)。
|
||
|
||
### `w32` 模块(Win32 FFI 绑定)
|
||
|
||
[includes/w32](../includes/w32) 提供 Win32 API 绑定,全部通过 `t.State` 的 FFI 机制声明(零特殊语法):
|
||
|
||
```python
|
||
from w32.win32file import CreateFileA, ReadFile, WriteFile
|
||
from w32.win32console import WriteConsole
|
||
from w32.win32memory import HeapAlloc, HeapFree
|
||
from w32.win32process import CreateProcess
|
||
from w32.win32sync import CreateMutex, WaitForSingleObject
|
||
|
||
handle: HANDLE = CreateFileA("test.txt", GENERIC_READ, FILE_SHARE_READ,
|
||
None, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, None)
|
||
```
|
||
|
||
子模块:`win32base`(基础类型/常量)、`win32file`(文件 IO)、`win32console`(控制台)、`win32memory`(内存)、`win32process`(进程/线程)、`win32sync`(同步对象)、`fileio`(高层文件操作封装)。详见 [08-c-operations.md 的 FFI 章节](08-c-operations.md#ffi-外部函数声明)。
|
||
|
||
## 模块解析流程
|
||
|
||
### 编译时模块加载
|
||
|
||
Viper 的 `import` 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合:
|
||
|
||
1. **阶段一**:从入口文件出发,通过 `import` 语句递归发现所有可达的源文件
|
||
2. **阶段一**:对每个源文件生成 `<SHA1>.pyi` 签名存根和 `<SHA1>.stub.ll` LLVM IR 声明
|
||
3. **阶段二**:加载所有 `.pyi` 和 `.stub.ll`,构建共享符号表
|
||
4. **阶段二**:翻译源文件时,通过符号表解析跨模块的类型和函数引用
|
||
5. **阶段二**:将被引用模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部
|
||
|
||
### 类型存根文件(.pyi)
|
||
|
||
`.pyi` 文件是模块的声明接口,由 `PythonToStubConverter` 在阶段一生成。存根文件的内容规则:
|
||
|
||
| 元素 | 存根表示 |
|
||
|------|---------|
|
||
| `t.CDefine` 常量 | 保留完整定义(含赋值) |
|
||
| `t.CDefine` 函数 | 保留完整函数体 |
|
||
| 普通函数 | 仅签名 + `t.State` |
|
||
| 全局变量 | 添加 `t.CExtern` |
|
||
| 类定义 | 保留成员类型注解和方法签名 |
|
||
|
||
存根文件还自动添加宏守卫(`c.CIfndef`/`c.CEndif()`),防止重复包含。
|
||
|
||
### SHA1 命名空间与导入
|
||
|
||
每个模块的函数和结构体在 LLVM IR 中自动加上 SHA1 前缀,消除跨模块符号冲突。只有标记为 `t.CExport` 的函数保持原始名称。详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。
|
||
|
||
### 符号表
|
||
|
||
所有模块的类型信息统一存储在 `SymbolTable` 中,包含:
|
||
- 结构体/联合体/枚举定义
|
||
- 函数签名
|
||
- 全局变量
|
||
- typedef 别名
|
||
- `t.CDefine` 常量
|
||
|
||
### 跨模块类型引用
|
||
|
||
```python
|
||
# 在 fat32_types.py 中定义
|
||
class fat32_fileinfo:
|
||
fname: list[t.CChar, 13]
|
||
attr: t.CUInt8T
|
||
file_size: t.CUInt32T
|
||
|
||
# 在其他模块中引用
|
||
import fat32_types
|
||
info: fat32_types.fat32_fileinfo
|
||
```
|
||
|
||
跨模块引用的结构体在 LLVM IR 中使用 SHA1 前缀的类型名:
|
||
```llvm
|
||
%"<SHA1_of_fat32_types>.fat32_fileinfo" = type { [13 x i8], i8, i32 }
|
||
```
|
||
|
||
## 项目 includes 配置
|
||
|
||
在 `project.json` 中配置模块搜索路径:
|
||
|
||
```json
|
||
{
|
||
"includes": ["../.."],
|
||
"source_dir": "./Kernel"
|
||
}
|
||
```
|
||
|
||
编译器会在 `includes` 指定的目录中搜索导入的模块。
|