# 12 - 项目配置与构建 Viper 项目使用 `project.vpj` 配置文件管理编译和链接参数(Python 单文件模式仍接受 `project.json`)。 ## project.vpj 结构 ```json { "name": "Kernel", "version": "1.0.0", "source_dir": "./Kernel", "build_dir": "./.tpv_build", "compiler": { "cmd": "llc", "flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"] }, "linker": { "cmd": "ld.lld.exe", "flags": [ "-m", "elf_x86_64", "-T", "linker.ld", "--oformat", "elf64-x86-64", "--strip-all" ], "output": "kernel.bin" }, "includes": ["../../includes"], "target": { "triple": "x86_64-none-elf", "datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" }, "options": { "slice_level": 3, "sha1_slice_level": 1, "target": "llvm", "strict_mode": true } } ``` ## 配置项说明 ### 基本信息字段 | 字段 | 类型 | 说明 | |------|------|------| | `name` | string | 项目名称 | | `version` | string | 项目版本 | | `source_dir` | string | 源代码目录(相对于 project.vpj 所在目录) | | `build_dir` | string | 构建目录(默认 `./.tpv_build`);`temp`/`output` 均由它派生 | ### 编译器配置 | 字段 | 类型 | 说明 | |------|------|------| | `compiler.cmd` | string | 编译器命令(通常为 `llc`) | | `compiler.flags` | string[] | 编译器标志 | 常用 `llc` 标志: - `-filetype=obj`:输出目标文件 - `-mtriple=x86_64-none-elf`:目标三元组 - `-relocation-model=static`:静态重定位 - `-O2`:优化级别 ### 链接器配置 | 字段 | 类型 | 说明 | |------|------|------| | `linker.cmd` | string | 链接器命令(通常为 `ld.lld.exe`;TransPyV 宿主工程为 `clang++`) | | `linker.flags` | string[] | 链接器标志 | | `linker.static_libs` | string[] | 静态库/目标文件列表(`.a`/`.obj`) | | `linker.dynamic_libs` | string[] | 动态库列表(`.dll`/`.so`) | | `linker.output` | string | 输出文件名 | 支持 DSO(动态共享对象)构建:开启后产物为 `*_dso.ll`。 常用 `ld.lld` 标志: - `-m elf_x86_64`:ELF x86_64 格式 - `-T linker.ld`:链接脚本 - `--oformat elf64-x86-64`:输出 ELF 格式 - `--oformat binary`:输出原始二进制(用于内核) - `--strip-all`:去除所有符号信息 ### 目标平台配置 | 字段 | 类型 | 说明 | |------|------|------| | `target.triple` | string | LLVM 目标三元组 | | `target.datalayout` | string | LLVM 数据布局字符串 | 注意:**无统一默认 triple**——由各工程 `project.vpj` 自行指定(TransPyV 自身为 `x86_64-pc-windows-gnu`;ViperOS 内核为 `x86_64-none-elf`)。`target.datalayout` 同样随工程配置,内核工程常用: `e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128` ### 包含路径 | 字段 | 类型 | 说明 | |------|------|------| | `includes` | string[] | 模块搜索路径列表 | ### 编译选项 | 字段 | 类型 | 说明 | |------|------|------| | `options.slice_level` | int | 切片优化级别(0-3) | | `options.sha1_slice_level` | int | SHA1 切片存储级别(默认 1;≥1 时产物按 `{temp}/{sha1[0:2]}/` 子目录存放) | | `options.target` | string | 编译目标(目前仅支持 `llvm`) | | `options.strict_mode` | bool | 严格模式 | ## 切片优化级别 | 级别 | 名称 | 说明 | |------|------|------| | `0` | `no_optimize` | 无优化 | | `1` | `conservative` | 保守优化 | | `2` | `moderate` | 适度优化 | | `3` | `aggressive` | 激进优化(默认) | | `s` | `size` | 体积优化 | ## 项目结构示例 ### 内核项目 ``` VKernel/ ├── project.vpj # 项目配置 ├── linker.ld # 链接脚本 ├── Kernel/ # 源代码目录 │ ├── main.vp # 内核入口 │ ├── bootinfo.vp │ ├── intr/ │ │ ├── gdt.vp │ │ ├── idt.vp │ │ └── syscall.vp │ ├── drivers/ │ │ ├── serial/ │ │ ├── video/ │ │ ├── storage/ │ │ └── ... │ └── ... ├── .tpv_build/ # 构建目录(build_dir,自动生成) │ ├── temp/ # 临时文件 │ │ ├── / # SHA1 切片子目录(sha1_slice_level ≥ 1) │ │ │ ├── .vpi # 签名存根 │ │ │ ├── .stub.ll # LLVM IR 声明 │ │ │ ├── .text.ll # 含代码的 .ll │ │ │ └── .deps.txt # 依赖信息 │ │ └── _sha1_map.txt # SHA1→源文件路径映射(仅人类可读) │ └── output/ # 输出文件 │ ├── kernel.bin # 内核二进制 │ ├── *.deps.txt # 依赖信息 │ └── linker.ld # 生成的链接脚本 ``` ### 应用项目 ``` HelloWorld/ ├── project.vpj # 项目配置 ├── linker.ld # 链接脚本 ├── main.vp # 应用入口 └── .tpv_build/ # 构建目录(自动生成) ├── temp/ # 临时文件 └── output/ # 输出文件 └── helloworld.elf # ELF 可执行文件 ``` ### 库项目 ``` SerialLogger/ ├── project.vpj # 项目配置 ├── linker.ld # 链接脚本 ├── serial_logger.vp # 库源码 └── .tpv_build/ # 构建目录(自动生成) ├── temp/ # 临时文件 └── output/ # 输出文件 ``` ## 链接脚本 ViperOS 使用自定义链接脚本控制内存布局: ```ld ENTRY(_start) SECTIONS { . = 0x100000; /* 加载地址 */ .text : { *(.text.startup) *(.text*) } .rodata : { *(.rodata*) } .data : { *(.data*) } .bss : { *(.bss*) *(COMMON) } } ``` ## 编译命令 TransPyC 编译器的基本用法(注:适用于单个文件,而不适用于工程): ```bash python TransPyC.py -f InputFile -o OutputFile [options] ``` ### 命令行参数 | 参数 | 说明 | |------|------| | `-f` | 输入文件路径 | | `-o` | 输出文件路径 | | `-wh` | 头文件列表 | | `-debug` | 调试输出文件 | | `-cc` | 编译命令 | | `-cflags` | 编译标志 | | `-run` | 编译后运行 | | `-args` | 运行参数 | | `-h` | 辅助文件(C 或 Python) | 工程编译使用(`--project` 指定工程文件): ```bash python Projectrans.py --project project.vpj ``` 即可 ## 构建流程(真实骨架) 工程构建的实际流水线: - **Phase 1(声明阶段)**:扫描入口与依赖并建依赖图 → 1a 结构体注册 → 1b 生成 `.vpi` 并翻译生成 stub - **Phase 2(翻译与链接)** - **Phase A-pre-vpi / Phase A-pre**:加载 `.vpi`,预翻译准备 - **Phase A**:主循环多遍收敛翻译,`.stub.ll`/`.text.ll` 在此写盘 - **Phase B**:`llc` 并行编译 `.ll` → `.o` - **Phase B+**:缺失 includes 按需编译 - **Phase C**:链接(`linker.cmd` 决定链接器) ## 增量编译 TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦合: ### 阶段一增量 - 每个源文件按内容计算 SHA1 哈希(16 个十六进制字符,即 64 位截断) - 如果 `.vpi` 和 `.stub.ll` 已存在,则跳过生成(缓存命中) - 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口 - SHA1 → 源文件路径映射在内存 `Sha1Store` 中多遍收敛构建;`temp/_sha1_map.txt`(格式 `:`)仅人类可读 ### 阶段二增量 - 阶段二(Phase A 主循环)在内存 `Sha1Store`/`StubMergerStore` 中多遍收敛构建并复用映射,不依赖 `_sha1_map.txt` - 旧产物清理使用 `--clear-cache` - 共享符号表为内存 `StubMergerStore`,按需加载避免每个文件重复加载 ### SHA1 命名空间与增量编译的协同 SHA1 同时服务于命名空间隔离和增量编译: - **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 - **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。