# 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 ``` ## 模块解析流程 ### 编译时模块加载 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` 函数 | 保留完整函数体 | | 普通函数 | 仅签名 + `c.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` 指定的目录中搜索导入的模块。