feat(tpv): --build-dir 命令行覆盖 project.vpj 的 build_dir

新增 --build-dir 参数:在 Config.resolve_paths 前覆盖 BuildDir,相对路径仍基于 project_dir 解析(_join_path),绝对路径(/ 或 \\ 开头)原样保留。用于隔离构建目录验证(如 --build-dir ./tpv_build2 避免陈旧缓存干扰)。
This commit is contained in:
TermiNexus committed 2026-08-25 18:07:55 +08:00
1 parent decf74b946
commit bd3705d68b
1 file changed
+27 -3
+27 -3
View File
@@ -20,6 +20,7 @@ import stdlib
import memhub
import argparse
import w32.win32console as w32cmd
import w32.win32base as w32base
import w32.fileio as fileio
import sys
import ast
@@ -57,6 +58,15 @@ def main() -> int:
w32cmd.SetConsoleOutputCP(CODE_PAGE)
w32cmd.SetConsoleCP(CODE_PAGE)
# [DET] 分配检测开关:在创建内存池前扫描命令行(sys._init_argv 依赖 mb,
# 不能提前;GetCommandLineA 直接读原始命令行,不含任何 pool 分配)。
# --detection 开启后 mb/perm_pool 均启用前后 0xCDCD 标记 + 记录表探测
# 越界写(定位"存活块被部分覆盖"的写入者,如 KwEntry cargs)。
detect_flag: int = 0
cmd_line_d: str = w32base.GetCommandLineA()
if cmd_line_d is not None and string.strstr(cmd_line_d, "--detection") is not None:
detect_flag = 1
# Initialize the mbuddy memory pool
arena: bytes = stdlib.malloc(POOL_SIZE)
if arena is None:
@@ -68,12 +78,12 @@ def main() -> int:
stdio.printf("FAIL: malloc for perm_pool arena failed\n")
return 1
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE)
mb: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(arena, POOL_SIZE, detect_flag)
if mb is None:
stdio.printf("FAIL: MemBuddy init failed\n")
return 1
perm_pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(perm_arena, PERM_POOL_SIZE)
perm_pool: memhub.MemBuddy | t.CPtr = memhub.MemBuddy(perm_arena, PERM_POOL_SIZE, detect_flag)
if perm_pool is None:
stdio.printf("FAIL: perm_pool init failed\n")
return 1
@@ -107,8 +117,14 @@ def main() -> int:
gen.__init__(mb)
GenGenerator._g_gen = gen
# P2-P5: 注入各 Handles 模块级单例(Phase1 阶段即调用其状态函数)
# P2-P5: 注入各 Handles 模块级单例(Phase1 阶段即调用其状态函数)。
# 注意:TPV 编译模块级全局带 sha1 前缀(模块隔离),必须逐个模块赋值;
# 种子 TPC 时代用裸名 @_g_gen(全局共享),遗漏三个 Handles 模块无感,
# 自举后 HT/HE/HEC 委托读各自 _g_gen=None 恒失效(is_global_name 恒 0 误报)
GenApi._g_gen = gen
HandlesTranslator._g_gen = gen
HandlesExpr._g_gen = gen
HandlesExprCall._g_gen = gen
# P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例
# 初始化 VLogger 并打印启动日志
@@ -136,6 +152,8 @@ def main() -> int:
parser.add_argument("--asan", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "ASan mode: .ll first opt -passes=asan then link -fsanitize=address")
parser.add_argument("--phase2command", None, argparse.STRING, 0, None, False, argparse.STORE, "Do not run llc/link: write Phase2 llc(opt+llc) and clang link commands to the given .bat path")
parser.add_argument("--nowarn-register", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Suppress Phase A dependency WARN")
parser.add_argument("--detection", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Enable MemBuddy allocation detection (0xCDCD markers + record-table probe for out-of-bounds writes; applies to both mb and perm_pool)")
parser.add_argument("--build-dir", None, argparse.STRING, 0, None, False, argparse.STORE, "Override project.vpj build_dir (default ./.tpv_build; relative paths resolve against the project dir)")
parser.add_argument("--version", "-v", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show version and exit")
parser.add_argument("--help", "-h", argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show help and exit")
@@ -177,6 +195,7 @@ Target: %s
output: str = args.get_str("output")
phase: str = args.get_str("phase")
cc: str = args.get_str("cc")
build_dir: str = args.get_str("build-dir")
_gb_clean: INT = args.get_bool("clean")
#if project is not None: stdio.printf(" --project: %s\n", project)
#else: stdio.printf(" --project: (未指定)\n")
@@ -281,6 +300,11 @@ Target: %s
if proj_dir is not None:
string.memcpy(proj_dir, proj_path, slash_pos)
proj_dir[slash_pos] = '\0'
# [--build-dir] 命令行覆盖 project.vpj 的 build_dir:在 resolve_paths 前
# 设置,使相对路径仍基于 project_dir 解析(如 ./tpv_build2 → Test/tpv_build2),
# 绝对路径(/ 或 \ 开头)由 _join_path 原样保留。
if build_dir is not None:
Config.BuildDir = build_dir
Config.resolve_paths(proj_dir)
Config.print_config()