8.3 KiB
10 - 模块与导入系统
Viper 的模块系统基于 Python 的 import 语法,但编译时通过 TransPyC 的符号表和类型系统实现跨模块的类型解析。
导入语法
标准导入
import t, c # Viper 内置类型和操作模块
import asm # 汇编辅助模块
import string # 字符串操作模块
模块导入
import bootinfo
import intr
import platform.pch as pch
import drivers.serial.uart.serial as serial
from 导入
from stdint import * # 导入所有 stdint 类型别名
from drivers.video.vesafb.vga import _VGAScreenDriver
相对导入
from . import submodule
from .. import parent_module
特殊模块
t 模块
类型定义模块,提供所有 C 类型对应的 Viper 类型。每个 Viper 文件通常都需要导入:
import t
c 模块
C 语言操作模块,提供指针操作、内联汇编、预处理指令等:
import c
asm 模块
汇编辅助模块,提供常用汇编指令的封装:
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 专有汇编进行加速,因此某些函数在其它架构可能需要手动重新编写。
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 中的类型别名:
from stdint import *
# 提供以下类型别名:
# UINT8PTR, UINT16PTR, UINT32PTR, UINT64PTR
# INT8PTR, INT16PTR, INT32PTR, INT64PTR
# 等等
viperlib 模块
ViperOS 标准库,提供常用 C 库函数:
import viperlib
viperlib.snprintf(c.Addr(buf), 64, "value=%d", 42) # snprintf(&buf, 64, "value=%d", 42);
vpsdk 模块
vpsdk 模块 专供于基于 Viper 开发的示例操作系统 ViperOS,不可用于其它平台,且需要特殊配置。
ViperOS 应用 SDK,提供系统调用和窗口管理:
import vpsdk.window as window
import vpsdk.process as process
import vpsdk.dynlib as dynlib
import vpsdk.syscall as syscall
ast 模块(自研解析器)
includes/ast 是完全自研的 Python 解析器(词法器 + 语法器 + AST 构造,约 4176 LOC),覆盖 CPython 几乎全部语法。这是向 TransPyV 完全自举的关键组件——自举后编译器不再依赖 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 和 Test/AstTest。
llvmlite 模块(自研 IR 生成库)
includes/llvmlite 是完全自研的 LLVM IR 文本生成库(约 1500 LOC),封装类型/值/模块/函数/基本块/构造器的创建与打印。同样是自举的关键组件。
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 的选型论证。
linkedlist 模块(NoVTable + PEP 695 泛型示范)
includes/linkedlist 提供链表实现,是 @t.NoVTable 非多态继承和 PEP 695 递归泛型继承的典范用例:
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 的泛型类章节 和 06-oop.md 的 NoVTable 章节。
w32 模块(Win32 FFI 绑定)
includes/w32 提供 Win32 API 绑定,全部通过 t.State 的 FFI 机制声明(零特殊语法):
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 章节。
模块解析流程
编译时模块加载
Viper 的 import 是编译时操作,不涉及运行时模块加载。完整的模块解析流程与两阶段编译紧密耦合:
- 阶段一:从入口文件出发,通过
import语句递归发现所有可达的源文件 - 阶段一:对每个源文件生成
<SHA1>.pyi签名存根和<SHA1>.stub.llLLVM IR 声明 - 阶段二:加载所有
.pyi和.stub.ll,构建共享符号表 - 阶段二:翻译源文件时,通过符号表解析跨模块的类型和函数引用
- 阶段二:将被引用模块的
.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 命名空间机制。
符号表
所有模块的类型信息统一存储在 SymbolTable 中,包含:
- 结构体/联合体/枚举定义
- 函数签名
- 全局变量
- typedef 别名
t.CDefine常量
跨模块类型引用
# 在 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 前缀的类型名:
%"<SHA1_of_fat32_types>.fat32_fileinfo" = type { [13 x i8], i8, i32 }
项目 includes 配置
在 project.json 中配置模块搜索路径:
{
"includes": ["../.."],
"source_dir": "./Kernel"
}
编译器会在 includes 指定的目录中搜索导入的模块。