# 12 - 项目配置与构建 Viper 项目使用 `project.json` 配置文件管理编译和链接参数。 ## project.json 结构 ```json { "name": "Kernel", "version": "1.0.0", "source_dir": "./Kernel", "temp_dir": "./temp", "output_dir": "./output", "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, "target": "llvm", "strict_mode": true } } ``` ## 配置项说明 ### 基本信息字段 | 字段 | 类型 | 说明 | |------|------|------| | `name` | string | 项目名称 | | `version` | string | 项目版本 | | `source_dir` | string | 源代码目录(相对于 project.json 所在目录) | | `temp_dir` | string | 临时文件目录(存放 .pyi 存根等) | | `output_dir` | string | 输出文件目录 | ### 编译器配置 | 字段 | 类型 | 说明 | |------|------|------| | `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`) | | `linker.flags` | string[] | 链接器标志 | | `linker.output` | string | 输出文件名 | 常用 `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: `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` ### 包含路径 | 字段 | 类型 | 说明 | |------|------|------| | `includes` | string[] | 模块搜索路径列表 | ### 编译选项 | 字段 | 类型 | 说明 | |------|------|------| | `options.slice_level` | int | 切片优化级别(0-3) | | `options.target` | string | 编译目标(目前仅支持 `llvm`) | | `options.strict_mode` | bool | 严格模式 | ## 切片优化级别 | 级别 | 名称 | 说明 | |------|------|------| | `0` | `no_optimize` | 无优化 | | `1` | `conservative` | 保守优化 | | `2` | `moderate` | 适度优化 | | `3` | `aggressive` | 激进优化(默认) | | `s` | `size` | 体积优化 | ## 项目结构示例 ### 内核项目 ``` VKernel/ ├── project.json # 项目配置 ├── linker.ld # 链接脚本 ├── Kernel/ # 源代码目录 │ ├── main.py # 内核入口 │ ├── bootinfo.py │ ├── intr/ │ │ ├── gdt.py │ │ ├── idt.py │ │ └── syscall.py │ ├── drivers/ │ │ ├── serial/ │ │ ├── video/ │ │ ├── storage/ │ │ └── ... │ └── ... ├── temp/ # 临时文件(自动生成) │ ├── .pyi # 签名存根(阶段一生成) │ ├── .stub.ll # LLVM IR 声明(阶段一生成) │ └── _sha1_map.txt # SHA1→源文件路径映射 └── output/ # 输出文件(自动生成) ├── kernel.bin # 内核二进制 ├── *.deps.json # 依赖信息 └── linker.ld # 生成的链接脚本 ``` ### 应用项目 ``` HelloWorld/ ├── project.json # 项目配置 ├── linker.ld # 链接脚本 ├── main.py # 应用入口 ├── temp/ # 临时文件 └── output/ # 输出文件 └── helloworld.elf # ELF 可执行文件 ``` ### 库项目 ``` SerialLogger/ ├── project.json # 项目配置 ├── linker.ld # 链接脚本 ├── serial_logger.py # 库源码 ├── 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) | 工程编译使用: ```bash python Projectrans.py xxx.json ``` 即可 ## 增量编译 TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦合: ### 阶段一增量 - 每个源文件按内容计算 SHA1 哈希(16位) - 如果 `.pyi` 和 `.stub.ll` 已存在,则跳过生成(缓存命中) - 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口 - `temp/_sha1_map.txt` 记录 SHA1 → 源文件路径的映射,格式为 `:` ### 阶段二增量 - 阶段二加载 `temp/_sha1_map.txt` 重建 SHA1 映射 - 过滤掉不在当前 SHA1 映射中的旧 `.pyi` 和 `.stub.ll` 文件 - 共享符号表一次性构建,避免每个文件重复加载 ### SHA1 命名空间与增量编译的协同 SHA1 同时服务于命名空间隔离和增量编译: - **命名空间**:非 `t.CExport` 函数和结构体使用 SHA1 前缀,消除符号冲突 - **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成 详见 [01-overview.md 中 SHA1 命名空间机制](01-overview.md#sha1-命名空间机制)。