From a6151350de62eff2bc00559ee6f6c19b4a5d92c1 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 3 Sep 2026 09:35:12 +0800 Subject: [PATCH] =?UTF-8?q?test(ViperBTests):=20=E6=96=B0=E5=A2=9E=20Viper?= =?UTF-8?q?ZipfileProject=EF=BC=88zipfile=20=E5=86=99->=E8=AF=BB=E5=9B=9E-?= =?UTF-8?q?>CRC=20=E6=8D=9F=E5=9D=8F=E6=A3=80=E6=B5=8B=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ViperBTests/ViperZipfileProject/.gitignore | 13 + ViperBTests/ViperZipfileProject/App/main.vp | 259 ++++++++++++++++++ ViperBTests/ViperZipfileProject/LICENSE | 21 ++ ViperBTests/ViperZipfileProject/README.md | 289 ++++++++++++++++++++ ViperBTests/ViperZipfileProject/project.vpj | 37 +++ 5 files changed, 619 insertions(+) create mode 100644 ViperBTests/ViperZipfileProject/.gitignore create mode 100644 ViperBTests/ViperZipfileProject/App/main.vp create mode 100644 ViperBTests/ViperZipfileProject/LICENSE create mode 100644 ViperBTests/ViperZipfileProject/README.md create mode 100644 ViperBTests/ViperZipfileProject/project.vpj diff --git a/ViperBTests/ViperZipfileProject/.gitignore b/ViperBTests/ViperZipfileProject/.gitignore new file mode 100644 index 0000000..6817232 --- /dev/null +++ b/ViperBTests/ViperZipfileProject/.gitignore @@ -0,0 +1,13 @@ +*.o +*.obj +*.exe +*.img +*.iso +**/__pycache__/ +.cache/ +*.pyc + +# 编译 +**/output/ +**/temp/ +**/.tpv_build/ \ No newline at end of file diff --git a/ViperBTests/ViperZipfileProject/App/main.vp b/ViperBTests/ViperZipfileProject/App/main.vp new file mode 100644 index 0000000..764e51e --- /dev/null +++ b/ViperBTests/ViperZipfileProject/App/main.vp @@ -0,0 +1,259 @@ +# main.vp — ViperZipfileProject:zipfile 模块读写测试 +# +# 覆盖: +# 1) ZipFile("w") 写入 4 个成员(deflate 文本 / deflate 大文件 / stored 伪随机 / 空文件) +# 2) ZipFile("r") 读回: 成员数/名称/大小/compress_size 检查 + 逐成员内容比对 +# (CRC32 校验由 zipfile.read 内部完成) +# 3) 损坏 stored 成员 payload 1 字节 → 再次 read 应返回 None 且错误码 ZIP_ERR_CRC +import t, c +from stdint import * +import stdio +import stdlib +import string +import zipfile +import w32.fileio as fio +import w32.win32file as wf + + +ZIP_PATH: str = "zip_roundtrip.zip" +BIG_LEN: t.CSizeT = 100000 +RND_LEN: t.CSizeT = 5000 +HELLO_TEXT: str = "Hello, Viper Zipfile!\n" + +fail_count: t.CInt = 0 + + +def chk(name: str, cond: t.CInt): + global fail_count + if cond: + stdio.printf("[PASS] %s\n", name) + else: + fail_count += 1 + stdio.printf("[FAIL] %s\n", name) + + +def StrLen(s: bytes) -> t.CSizeT: + n: t.CSizeT = 0 + while s is not None and c.Deref(s) != 0: + n += 1 + s += 1 + return n + + +def fill_pattern(buf: bytes, length: t.CSizeT, kind: t.CInt): + i: t.CSizeT = 0 + while i < length: + if kind == 1: + # 'A'..'G' 循环 — 高度可压缩 + buf[i] = 65 + (i % 7) + else: + # 伪随机 — 供 ZIP_STORED 成员 + buf[i] = (i * 37 + 11) & 0xFF + i += 1 + + +def WriteZip() -> t.CInt: + stdio.printf("\n--- 1) 写 zip(4 个成员) ---\n") + wf.DeleteFileA(ZIP_PATH) + w: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "w", zipfile.ZIP_DEFLATED) + if w.ok == 0: + stdio.printf("open(w) failed: %s\n", zipfile.error()) + return 1 + + hello: bytes = stdlib.malloc(64) + if not hello: + stdio.printf("malloc hello failed\n") + w.close() + return 1 + string.strcpy(hello, HELLO_TEXT) + hello_len: t.CSizeT = StrLen(hello) + + big: bytes = stdlib.malloc(BIG_LEN) + if not big: + stdio.printf("malloc big failed\n") + stdlib.free(hello) + w.close() + return 1 + fill_pattern(big, BIG_LEN, 1) + + rnd: bytes = stdlib.malloc(RND_LEN) + if not rnd: + stdio.printf("malloc rnd failed\n") + stdlib.free(hello) + stdlib.free(big) + w.close() + return 1 + fill_pattern(rnd, RND_LEN, 0) + + rc: t.CInt = w.write("hello.txt", hello, hello_len, zipfile.ZIP_DEFLATED) + chk("write hello.txt (deflate)", rc == zipfile.ZIP_ERR_OK) + rc = w.write("big.bin", big, BIG_LEN, zipfile.ZIP_DEFLATED) + chk("write big.bin (deflate, 100000B)", rc == zipfile.ZIP_ERR_OK) + rc = w.write("random.bin", rnd, RND_LEN, zipfile.ZIP_STORED) + chk("write random.bin (stored)", rc == zipfile.ZIP_ERR_OK) + rc = w.write("empty.txt", None, 0, zipfile.ZIP_DEFLATED) + chk("write empty.txt (deflate, 0B)", rc == zipfile.ZIP_ERR_OK) + rc = w.close() + chk("close(w)", rc == zipfile.ZIP_ERR_OK) + + stdlib.free(hello) + stdlib.free(big) + stdlib.free(rnd) + return 0 + + +def CheckReadBack(buf: bytes, expect: bytes, length: t.CSizeT) -> t.CInt: + # buf: zipfile.read 返回的解压缓冲;expect: 期望内容 + if buf is None: + return 0 + if length == 0: + return 1 + return t.CInt(string.memcmp(buf, expect, length) == 0) + + +def ReadZip() -> t.CInt: + stdio.printf("\n--- 2) 读回校验 ---\n") + r: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "r") + if r.ok == 0: + stdio.printf("open(r) failed: %s\n", zipfile.error()) + return 1 + + chk("entry count == 4", r.info_count == 4) + i: t.CSizeT = 0 + while i < r.info_count: + stdio.printf(" [%d] %s\n", t.CInt(i), r.namelist_at(i)) + i += 1 + + # ---- hello.txt:deflate 文本 ---- + info: zipfile.ZipInfo | t.CPtr = r.getinfo("hello.txt") + chk("getinfo(hello.txt)", info is not None) + hello_expect: bytes = stdlib.malloc(64) + string.strcpy(hello_expect, HELLO_TEXT) + exp_len: t.CSizeT = StrLen(hello_expect) + if info is not None: + chk("hello file_size == 22", info.file_size == exp_len) + chk("hello compress_size > 0", info.compress_size > 0) + olen: t.CSizeT = 0 + data: bytes = r.read("hello.txt", c.Addr(olen)) + chk("read(hello.txt)", data is not None) + chk("hello content match", CheckReadBack(data, hello_expect, olen) == 1) + stdlib.free(data) + stdlib.free(hello_expect) + + # ---- big.bin:deflate 大文件 ---- + info = r.getinfo("big.bin") + chk("getinfo(big.bin)", info is not None) + big_expect: bytes = stdlib.malloc(BIG_LEN) + fill_pattern(big_expect, BIG_LEN, 1) + if info is not None: + chk("big file_size == 100000", info.file_size == BIG_LEN) + chk("big compress_size < file_size", info.compress_size < info.file_size) + chk("big crc != 0", info.crc32 != 0) + olen = 0 + data = r.read("big.bin", c.Addr(olen)) + chk("read(big.bin)", data is not None) + chk("big content match", data is not None and olen == BIG_LEN + and CheckReadBack(data, big_expect, BIG_LEN) == 1) + stdlib.free(data) + stdlib.free(big_expect) + + # ---- random.bin:stored ---- + info = r.getinfo("random.bin") + chk("getinfo(random.bin)", info is not None) + rnd_expect: bytes = stdlib.malloc(RND_LEN) + fill_pattern(rnd_expect, RND_LEN, 0) + if info is not None: + chk("random file_size == 5000", info.file_size == RND_LEN) + chk("random stored: compress_size == file_size", info.compress_size == info.file_size) + olen = 0 + data = r.read("random.bin", c.Addr(olen)) + chk("read(random.bin)", data is not None) + chk("random content match", data is not None and olen == RND_LEN + and CheckReadBack(data, rnd_expect, RND_LEN) == 1) + stdlib.free(data) + stdlib.free(rnd_expect) + + # ---- empty.txt:空成员 ---- + info = r.getinfo("empty.txt") + chk("getinfo(empty.txt)", info is not None) + olen = 0 + data = r.read("empty.txt", c.Addr(olen)) + chk("read(empty.txt) ok", data is not None) + chk("empty length == 0", olen == 0) + stdlib.free(data) + + # ---- 不存在成员 ---- + olen = 0 + data = r.read("no_such.txt", c.Addr(olen)) + chk("read(missing) returns None", data is None) + chk("read(missing) code NOT_FOUND", zipfile.error_code() == zipfile.ZIP_ERR_NOT_FOUND) + + rc: t.CInt = r.close() + chk("close(r)", rc == zipfile.ZIP_ERR_OK) + return 0 + + +def CorruptStoredCheck() -> t.CInt: + stdio.printf("\n--- 3) 损坏 stored 成员后 CRC 校验 ---\n") + r: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "r") + if r.ok == 0: + stdio.printf("open(r) failed: %s\n", zipfile.error()) + return 1 + info: zipfile.ZipInfo | t.CPtr = r.getinfo("random.bin") + chk("getinfo(random.bin)", info is not None) + if info is None or info.compress_size < 2: + stdio.printf("cannot locate stored member payload\n") + r.close() + return 1 + + # 本地头无 extra 时,数据起点 = header_offset + 30 + 名字长 + start: t.CSizeT = t.CSizeT(info.header_offset) + 30 + info.name_len + flip_pos: t.CSizeT = start + info.compress_size - 1 + stdio.printf(" flip byte at offset %lld (raw)\n", flip_pos) + + f: fio.File | t.CPtr = fio.File(ZIP_PATH, fio.MODE.RP) + chk("open RP", f.closed == 0) + if f.closed == 0: + byte_buf: bytes = stdlib.malloc(1) + if not byte_buf: + r.close() + return 1 + f.seek(LONG(flip_pos), fio.SEEK_SET) + rd: LONG = f.read(byte_buf, 1) + chk("read back byte", rd == 1) + f.seek(LONG(flip_pos), fio.SEEK_SET) + byte_buf[0] = (byte_buf[0] ^ 0xFF) & 0xFF + wr: LONG = f.write(byte_buf, 1) + chk("flip byte written", wr == 1) + f.close() + stdlib.free(byte_buf) + r.close() + + z2: zipfile.ZipFile | t.CPtr = zipfile.ZipFile(ZIP_PATH, "r") + chk("reopen after corruption", z2.ok == 1) + olen: t.CSizeT = 0 + data: bytes = z2.read("random.bin", c.Addr(olen)) + chk("corrupted read returns None", data is None) + chk("error code == ZIP_ERR_CRC", zipfile.error_code() == zipfile.ZIP_ERR_CRC) + stdio.printf(" last error: %s\n", zipfile.error()) + if data is not None: + stdlib.free(data) + z2.close() + return 0 + + +@t.CExport +def main() -> int: + stdio.printf("ViperZipfileProject: zipfile 模块读写测试\n") + if WriteZip() != 0: + return 1 + if ReadZip() != 0: + return 1 + if CorruptStoredCheck() != 0: + return 1 + + wf.DeleteFileA(ZIP_PATH) + stdio.printf("\n失败数: %d\n", fail_count) + if fail_count == 0: + stdio.printf("全部通过\n") + return t.CInt(fail_count != 0) diff --git a/ViperBTests/ViperZipfileProject/LICENSE b/ViperBTests/ViperZipfileProject/LICENSE new file mode 100644 index 0000000..cee2f62 --- /dev/null +++ b/ViperBTests/ViperZipfileProject/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 TermiNexus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ViperBTests/ViperZipfileProject/README.md b/ViperBTests/ViperZipfileProject/README.md new file mode 100644 index 0000000..e1fe40f --- /dev/null +++ b/ViperBTests/ViperZipfileProject/README.md @@ -0,0 +1,289 @@ +# Viper Template Project + +[English](#english) | [中文](#中文) + +A minimal, ready-to-use template for bootstrapping a new [Viper](../wiki/01-overview.md) language project on **Windows (x86_64-pc-windows-gnu)**. + +Windows 平台(x86_64-pc-windows-gnu)下 [Viper](../wiki/01-overview.md) 语言新项目的最小可用模板。 + +--- + + + +## 中文 + +### 这是什么 + +`ViperTemplateProject` 是基于 `Viper` 语言的 **Windows 桌面应用模板**。克隆本仓库后,你可以立即得到一个能够: + +- 设置 Windows 控制台为 UTF-8 编码(避免中文乱码) +- 打印一行 `你好,世界` +- 通过 `llc + clang++`(mingw 工具链)编译为原生 `app.exe` + +的最小 Viper 项目。 + +模板对应的语言编译器是 [TransPyC](https://git.gvsds.com/GVSDS/TransPyC);关于 Viper 语言本身的概览,参见 [TransPyC 仓库 wiki](../wiki/01-overview.md)。 + +### 目录结构 + +``` +ViperTemplateProject/ +├── .gitignore # 忽略 build/、*.o、*.exe、缓存等 +├── README.md # 本文件 +├── project.vpj # 项目配置(编译器、链接器、目标三元组等) +└── App/ + └── main.py # 入口文件 +``` + +### 前提条件 + +| 工具 | 说明 | +|------|------| +| `python` ≥ 3.10 | 用于运行 TransPyC 编译器 | +| `llc` | LLVM 静态编译器,编译 `.ll` → `.o` | +| `clang++` | mingw 工具链下的链接驱动(`x86_64-w64-mingw32`) | +| `TransPyC` 仓库 | 本编译器,克隆在 `ViperTemplateProject/..` 同一目录下 | + +环境变量建议(PowerShell): + +```powershell +$env:PATH = "D:\msys64\mingw64\bin;D:\LLVM\bin;$env:PATH" +``` + +### 快速开始 + +```powershell +# 1. 确保目录布局正确 +# D:\Users\TermiNexus\Desktop\TransPyC\ +# ├── TransPyC\ # 编译器仓库 +# └── ViperTemplateProject\ # 本仓库 + +cd D:\Users\TermiNexus\Desktop\TransPyC\ViperTemplateProject + +# 2. 编译并运行 +python ..\TransPyC\Projectrans.py ` + --project .\project.vpj ` + --clean-cache=false + +# 3. 产物位于 output\app.exe +.\output\app.exe +``` + +预期输出: + +``` +你好,世界 +``` + +### 编写你的第一个程序 + +打开 `App/main.py`,替换 `print("你好,世界")` 为任意合法 Viper 表达式。例如: + +```python +import w32.win32console as w32cmd +import t, c + +pagecode: t.CDefine = 65001 + +@t.CExport +def main() -> int: + w32cmd.SetConsoleOutputCP(pagecode) + w32cmd.SetConsoleCP(pagecode) + + # 你的代码从这里开始 + a: t.CInt = 1 + b: t.CInt = 2 + print("a + b =", a + b) + + return 0 +``` + +### 修改项目配置 + +打开 `project.vpj`,按需调整: + +| 字段 | 含义 | 模板默认值 | +|------|------|-----------| +| `name` | 项目名(仅显示用) | `Standard Template Project` | +| `source_dir` | 源文件根目录 | `./App` | +| `temp_dir` | 中间产物目录(`.pyi` / `.stub.ll`) | `./temp` | +| `output_dir` | 最终产物目录 | `./output` | +| `compiler.cmd` | 汇编器 | `llc` | +| `compiler.flags` | 传给 `llc` 的参数 | `["-filetype=obj", "-relocation-model=pic"]` | +| `linker.cmd` | 链接器 | `clang++` | +| `linker.flags` | 链接器参数 | mingw 标准库 + `kernel32` | +| `linker.output` | 产物名 | `app.exe` | +| `includes` | 标准库搜索路径 | `["../includes"]` | +| `target.triple` | LLVM 目标三元组 | `x86_64-pc-windows-gnu` | +| `target.datalayout` | LLVM 数据布局 | mingw 默认 | +| `options.target` | 后端目标 | `llvm` | +| `options.strict_mode` | 严格类型检查 | `true` | +| `options.slice_level` | 切片级别 | `3` | + +### 跨平台使用 + +本模板默认针对 **Windows + mingw**。若需在其他平台使用,修改 `project.vpj` 的 `compiler.cmd` / `linker.cmd` / `target.triple`: + +- **Linux (x86_64)**:`triple = "x86_64-unknown-linux-gnu"`,`linker.cmd = "clang++"` +- **macOS (x86_64)**:`triple = "x86_64-apple-darwin*"`,`linker.cmd = "clang++"` +- **裸机 x86_64 (ViperOS)**:`triple = "x86_64-none-elf"`,`linker.cmd = "ld.lld"`,需要 `isr.s` 启动文件 + +### 常见问题 + +**Q: 报错 `cannot find includes/os` / `cannot find includes/atom` 之类?** +A: 检查 `project.vpj` 中的 `includes` 字段是否指向 `TransPyC/includes`。`../includes` 假设本仓库与 `TransPyC` 仓库同级。 + +**Q: 输出 `app.exe` 双击闪退?** +A: 在终端中运行 `.\output\app.exe` 而非双击,并确认 mingw 与 LLVM 在 `PATH` 中。 + +**Q: 想完全清理构建产物?** +A: 使用 `python ..\TransPyC\Projectrans.py --project .\project.vpj --clean-cache` 清理缓存;删除 `output/` 和 `temp/` 即可彻底重置。 + +**Q: `StandardTemplateProject` 和本仓库是什么关系?** +A: 本仓库 `ViperTemplateProject` 是 `StandardTemplateProject` 的独立仓库版本。如果你仍想保留 `StandardTemplateProject` 放在 `TransPyC` 仓库内,只需把它加入 `TransPyC/.gitignore` 的 `# 排除独立仓库的目录` 小节。 + +### 进一步阅读 + +- [Viper 语言概览](../wiki/01-overview.md) +- [类型系统](../wiki/02-type-system.md) +- [OOP 与对象模型](../wiki/06-oop.md) +- [自举路线图](../wiki/13-bootstrapping.md) + +--- + + + +## English + +### What is this + +`ViperTemplateProject` is a **Windows desktop application template** based on the [Viper](../wiki/01-overview.md) language. After cloning, you immediately have a minimal Viper project that: + +- Sets the Windows console to UTF-8 (avoids mojibake for non-ASCII output) +- Prints `你好,世界` +- Compiles to a native `app.exe` via `llc + clang++` (mingw toolchain) + +The corresponding compiler is [TransPyC](https://git.gvsds.com/GVSDS/TransPyC). For a Viper language overview, see the [TransPyC wiki](../wiki/01-overview.md). + +### Directory layout + +``` +ViperTemplateProject/ +├── .gitignore # ignores build/, *.o, *.exe, caches, etc. +├── README.md # this file +├── project.vpj # project config (compiler, linker, target triple, ...) +└── App/ + └── main.py # entry point +``` + +### Prerequisites + +| Tool | Notes | +|------|-------| +| `python` ≥ 3.10 | runs the TransPyC compiler | +| `llc` | LLVM static compiler, `.ll` → `.o` | +| `clang++` | mingw toolchain driver (`x86_64-w64-mingw32`) | +| `TransPyC` repo | the compiler, cloned as a sibling of `ViperTemplateProject` | + +Suggested `PATH` (PowerShell): + +```powershell +$env:PATH = "D:\msys64\mingw64\bin;D:\LLVM\bin;$env:PATH" +``` + +### Quick start + +```powershell +# 1. Make sure the layout is right +# D:\Users\TermiNexus\Desktop\TransPyC\ +# ├── TransPyC\ # compiler repo +# └── ViperTemplateProject\ # this repo + +cd D:\Users\TermiNexus\Desktop\TransPyC\ViperTemplateProject + +# 2. Build and run +python ..\TransPyC\Projectrans.py ` + --project .\project.vpj ` + --clean-cache=false + +# 3. Output is at output\app.exe +.\output\app.exe +``` + +Expected output: + +``` +你好,世界 +``` + +### Writing your first program + +Open `App/main.py` and replace `print("你好,世界")` with any valid Viper expression. Example: + +```python +import w32.win32console as w32cmd +import t, c + +pagecode: t.CDefine = 65001 + +@t.CExport +def main() -> int: + w32cmd.SetConsoleOutputCP(pagecode) + w32cmd.SetConsoleCP(pagecode) + + # your code goes here + a: t.CInt = 1 + b: t.CInt = 2 + print("a + b =", a + b) + + return 0 +``` + +### Editing project.vpj + +| Field | Meaning | Template default | +|-------|---------|------------------| +| `name` | display name | `Standard Template Project` | +| `source_dir` | source root | `./App` | +| `temp_dir` | intermediate artifacts (`.pyi` / `.stub.ll`) | `./temp` | +| `output_dir` | final artifacts | `./output` | +| `compiler.cmd` | assembler | `llc` | +| `compiler.flags` | flags passed to `llc` | `["-filetype=obj", "-relocation-model=pic"]` | +| `linker.cmd` | linker | `clang++` | +| `linker.flags` | linker flags | mingw stdlib + `kernel32` | +| `linker.output` | output name | `app.exe` | +| `includes` | standard library search paths | `["../includes"]` | +| `target.triple` | LLVM target triple | `x86_64-pc-windows-gnu` | +| `target.datalayout` | LLVM data layout | mingw default | +| `options.target` | backend target | `llvm` | +| `options.strict_mode` | strict type checking | `true` | +| `options.slice_level` | slice level | `3` | + +### Cross-platform use + +This template targets **Windows + mingw** by default. To use on another platform, adjust `compiler.cmd` / `linker.cmd` / `target.triple` in `project.vpj`: + +- **Linux (x86_64)**: `triple = "x86_64-unknown-linux-gnu"`, `linker.cmd = "clang++"` +- **macOS (x86_64)**: `triple = "x86_64-apple-darwin*"`, `linker.cmd = "clang++"` +- **Bare-metal x86_64 (ViperOS)**: `triple = "x86_64-none-elf"`, `linker.cmd = "ld.lld"`, requires `isr.s` startup + +### FAQ + +**Q: Error like `cannot find includes/os` or `cannot find includes/atom`?** +A: Check that the `includes` field in `project.vpj` points to the `TransPyC/includes` directory. `../includes` assumes this repo lives next to `TransPyC`. + +**Q: `app.exe` flashes and closes on double-click?** +A: Run `.\output\app.exe` from a terminal, not by double-clicking. Make sure mingw and LLVM are on `PATH`. + +**Q: How to fully clean build artifacts?** +A: `python ..\TransPyC\Projectrans.py --project .\project.vpj --clean-cache` clears the cache. To reset everything, also delete `output/` and `temp/`. + +**Q: What is the relationship with `StandardTemplateProject`?** +A: This repo `ViperTemplateProject` is the standalone-repo version of `StandardTemplateProject`. If you still want `StandardTemplateProject` to live inside the `TransPyC` repo, add it to the `# 排除独立仓库的目录` section in `TransPyC/.gitignore`. + +### Further reading + +- [Viper language overview](../wiki/01-overview.md) +- [Type system](../wiki/02-type-system.md) +- [OOP and object model](../wiki/06-oop.md) +- [Bootstrapping roadmap](../wiki/13-bootstrapping.md) diff --git a/ViperBTests/ViperZipfileProject/project.vpj b/ViperBTests/ViperZipfileProject/project.vpj new file mode 100644 index 0000000..92f3018 --- /dev/null +++ b/ViperBTests/ViperZipfileProject/project.vpj @@ -0,0 +1,37 @@ +{ + "name": "ViperZipfileProject - zipfile 模块测试", + "version": "1.0.0", + "source_dir": "./App", + "build_dir": "./.tpv_build", + "compiler": { + "cmd": "llc", + "flags": [ + "-filetype=obj", + "-relocation-model=pic" + ] + }, + "linker": { + "cmd": "clang++", + "flags": [ + "-lmsvcrt", + "-lucrt", + "-lpthread", + "-lmingwex", + "-lkernel32", + "-Wl,--allow-multiple-definition" + ], + "output": "app.exe" + }, + "includes": [ + "../../includes" + ], + "target": { + "triple": "x86_64-pc-windows-gnu", + "datalayout": "e-m:w-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 + } +} \ No newline at end of file