# 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. **阶段一**:对每个源文件生成 `.pyi` 签名存根和 `.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 %".fat32_fileinfo" = type { [13 x i8], i8, i32 } ``` ## 项目 includes 配置 在 `project.json` 中配置模块搜索路径: ```json { "includes": ["../.."], "source_dir": "./Kernel" } ``` 编译器会在 `includes` 指定的目录中搜索导入的模块。