移除了 VLogger fmt buffer 缓冲区,使用栈 f-string
This commit is contained in:
1 parent
54462320d2
commit
d971bae7cd
15 files changed
+357
-702
No files matched your search
@@ -83,7 +83,6 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
declare_only: 0=全量翻译(默认),1=仅注册 struct/enum/union(不翻译方法体)
|
||||
temp_dir: temp 目录路径(非 None 时在翻译前生成 .vpi 存根文件)
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if file_path is None: return None
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
if f.closed: return None
|
||||
@@ -115,8 +114,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
GenApi.dump_parse_traceback(file_path)
|
||||
err_line: int = ast.get_parse_err_line()
|
||||
err_col: int = ast.get_parse_err_col()
|
||||
viperlib.snprintf(fb, 1024, "解析失败: %s (line %d col %d)", file_path, err_line, err_col)
|
||||
VLogger.error(fb, "PARSE")
|
||||
VLogger.error(f"解析失败: {file_path} (line {err_line} col {err_col})", "PARSE")
|
||||
return None
|
||||
# 生成 .vpi 存根文件(从 AST 直接生成,在 tr.translate 之前,与 Phase1 一致)
|
||||
# .vpi 供其他模块跨模块查询函数签名和 CTypedef 定义
|
||||
@@ -184,8 +182,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
gen.ExprGenCls.extract_module_docstrings(tree, sha1_val)
|
||||
ret: int = tr.translate(tree)
|
||||
if ret != 0:
|
||||
viperlib.snprintf(fb, 1024, "文件翻译失败: %s", file_path)
|
||||
VLogger.error(fb, "Translate")
|
||||
VLogger.error(f"文件翻译失败: {file_path}", "Translate")
|
||||
return None
|
||||
return tr
|
||||
|
||||
@@ -333,7 +330,6 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if ir_path is None or cc_cmd is None or output_dir is None or module_name is None:
|
||||
return 1
|
||||
|
||||
@@ -383,8 +379,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
asan_path, ir_path)
|
||||
opt_ret: int = stdlib.system(opt_cmd)
|
||||
if opt_ret != 0:
|
||||
viperlib.snprintf(fb, 1024, "opt ASan 插桩失败 (module=%s)", module_name)
|
||||
VLogger.error(fb, "ASAN")
|
||||
VLogger.error(f"opt ASan 插桩失败 (module={module_name})", "ASAN")
|
||||
return 1
|
||||
compile_input = asan_path
|
||||
|
||||
@@ -399,8 +394,7 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
|
||||
# 避免 subprocess 管道捕获丢失输出
|
||||
sys_ret: int = stdlib.system(cmd)
|
||||
if sys_ret != 0:
|
||||
viperlib.snprintf(fb, 1024, "编译失败 (module=%s, cmd=%s)", module_name, cmd)
|
||||
VLogger.error(fb, "LLC")
|
||||
VLogger.error(f"编译失败 (module={module_name}, cmd={cmd})", "LLC")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -576,7 +570,6 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
|
||||
tasks: LlcTask 记录连续数组(stdlib.malloc),每个记录由 init_llc_task 填充。
|
||||
Returns: 0 全部成功;非 0 有失败(已打印失败模块与命令)
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if tasks is None or task_count <= 0:
|
||||
return 0
|
||||
# --phase2command 模式:不 spawn 线程,把 opt(ASan)+ llc 命令全部写入 bat
|
||||
@@ -590,8 +583,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
|
||||
_phase2_write_cmd(tsk_p.OptCmd)
|
||||
if tsk_p.LlcCmd is not None:
|
||||
_phase2_write_cmd(tsk_p.LlcCmd)
|
||||
viperlib.snprintf(fb, 1024, "phase2command 模式:%d 条 llc 命令已写入 %s", task_count, _phase2_cmd_path)
|
||||
VLogger.info(fb, "phase2cmd")
|
||||
VLogger.info(f"phase2command 模式:{task_count} 条 llc 命令已写入 {_phase2_cmd_path}", "phase2cmd")
|
||||
return 0
|
||||
if max_threads <= 0:
|
||||
max_threads = 1
|
||||
@@ -631,10 +623,7 @@ def run_llc_parallel(tasks: bytes, task_count: int, max_threads: int) -> int:
|
||||
tsk2: LlcTask | t.CPtr = (LlcTask | t.CPtr)(t.CVoid(
|
||||
t.CUInt64T(tasks) + t.CSizeT(batch_start + j) * slot_size, t.CPtr))
|
||||
if tsk2 is not None and tsk2.Result != 0:
|
||||
viperlib.snprintf(fb, 1024, "llc 编译失败: %s (cmd=%s)",
|
||||
(tsk2.ModuleSha1 if tsk2.ModuleSha1 is not None else "?"),
|
||||
(tsk2.LlcCmd if tsk2.LlcCmd is not None else "?"))
|
||||
VLogger.error(fb, "LLC")
|
||||
VLogger.error(f"llc 编译失败: {(tsk2.ModuleSha1 if tsk2.ModuleSha1 is not None else "?")} (cmd={(tsk2.LlcCmd if tsk2.LlcCmd is not None else "?")})", "LLC")
|
||||
ret = 1
|
||||
return ret
|
||||
|
||||
@@ -746,7 +735,6 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if output_dir is None or linker_cmd is None or module_name is None:
|
||||
return 1
|
||||
|
||||
@@ -764,11 +752,9 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
if includes_binary_dir is not None:
|
||||
extra_len = collect_obj_files(includes_binary_dir, extra_objs, EXTRA_BUF_SIZE)
|
||||
if extra_len > 0:
|
||||
viperlib.snprintf(fb, 1024, "附加 %d 字节的 includes.binary .obj 文件", extra_len)
|
||||
VLogger.info(fb, "link")
|
||||
VLogger.info(f"附加 {extra_len} 字节的 includes.binary .obj 文件", "link")
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024, "includes.binary 无 .obj 文件: %s", includes_binary_dir)
|
||||
VLogger.warning(fb, "link")
|
||||
VLogger.warning(f"includes.binary 无 .obj 文件: {includes_binary_dir}", "link")
|
||||
|
||||
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
|
||||
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
|
||||
@@ -807,10 +793,8 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
|
||||
VLogger.error("subprocess.run 返回 None", "link")
|
||||
return 1
|
||||
if result.returncode != 0:
|
||||
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d", result.returncode)
|
||||
VLogger.error(fb, "link")
|
||||
viperlib.snprintf(fb, 1024, "命令: %s", cmd)
|
||||
VLogger.error(fb, "link")
|
||||
VLogger.error(f"链接失败,返回码: {result.returncode}", "link")
|
||||
VLogger.error(f"命令: {cmd}", "link")
|
||||
# 显示链接器错误输出
|
||||
# 注意: subprocess 在 Windows 下将 stderr 合并到 stdout,result.stderr 总是 None
|
||||
if result.stdout is not None:
|
||||
@@ -841,7 +825,6 @@ def asm_to_obj(asm_path: str, sha1_val: str, output_dir: str,
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if asm_path is None or sha1_val is None or output_dir is None:
|
||||
return 1
|
||||
obj_path: str = build_sliced_path(output_dir, sha1_val, "obj")
|
||||
@@ -872,9 +855,7 @@ def asm_to_obj(asm_path: str, sha1_val: str, output_dir: str,
|
||||
stdio.printf("%s\n", result.stdout)
|
||||
if result.stderr is not None:
|
||||
stdio.printf("%s\n", result.stderr)
|
||||
viperlib.snprintf(fb, 1024, "llvm-mc 汇编失败,返回码: %d, 命令: %s",
|
||||
result.returncode, cmd)
|
||||
VLogger.error(fb, "asm")
|
||||
VLogger.error(f"llvm-mc 汇编失败,返回码: {result.returncode}, 命令: {cmd}", "asm")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -896,15 +877,13 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if ir_buf is None or temp_dir is None or output_dir is None or module_name is None:
|
||||
return 1
|
||||
|
||||
# Step 1: 写 .ll 文件
|
||||
ret: int = write_ir_to_file(ir_buf, ir_len, temp_dir, module_name)
|
||||
if ret != 0:
|
||||
viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", module_name)
|
||||
VLogger.error(fb, "compile")
|
||||
VLogger.error(f"写 .ll 失败: {module_name}", "compile")
|
||||
return 1
|
||||
|
||||
# Step 2: 构造切片 .ll 路径并编译 → .obj
|
||||
@@ -914,8 +893,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
|
||||
|
||||
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
|
||||
if ret != 0:
|
||||
viperlib.snprintf(fb, 1024, "llc 编译失败: %s", module_name)
|
||||
VLogger.error(fb, "compile")
|
||||
VLogger.error(f"llc 编译失败: {module_name}", "compile")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -936,7 +914,6 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
|
||||
Returns:
|
||||
0 成功,非 0 失败
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if obj_paths is None or obj_paths_len == 0 or linker_cmd is None:
|
||||
return 1
|
||||
|
||||
@@ -1045,8 +1022,7 @@ def link_objs_to_exe(obj_paths: str, obj_paths_len: t.CSizeT,
|
||||
stdio.printf("=== clang++ 链接错误输出 ===\n%s\n", result.stdout)
|
||||
if result.stderr is not None:
|
||||
stdio.printf("=== clang++ stderr ===\n%s\n", result.stderr)
|
||||
viperlib.snprintf(fb, 1024, "链接失败,返回码: %d, 命令: %s", result.returncode, cmd)
|
||||
VLogger.error(fb, "link")
|
||||
VLogger.error(f"链接失败,返回码: {result.returncode}, 命令: {cmd}", "link")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ import lib.core.Gen.GenApi as GenApi
|
||||
def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
log: VLogger.Logger | t.CPtr) -> int:
|
||||
"""Phase1: 扫描 includes 目录,按需翻译并生成 stub"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if includes_dir is None or temp_dir is None:
|
||||
VLogger.error("includes_dir 或 temp_dir 为空,无法运行 Phase1", "Phase1")
|
||||
return 1
|
||||
@@ -77,9 +76,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
t_scan0: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
|
||||
t_scan1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
fb: str = VLogger.fmtbuffer
|
||||
viperlib.snprintf(fb, 1024, "扫描 includes 总耗时: %llu ms (%d 文件, 含 SHA1 计算)", t_scan1 - t_scan0, result.Count if result is not None else 0)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"扫描 includes 总耗时: {t_scan1 - t_scan0} ms ({result.Count if result is not None else 0} 文件, 含 SHA1 计算)", "Phase1")
|
||||
if result is None:
|
||||
VLogger.error("扫描失败", "Phase1")
|
||||
return 1
|
||||
@@ -267,13 +264,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
# 1a-pre 阶段总耗时(全部 includes 文件读+parse+import 依赖扫描)
|
||||
t_pre1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
viperlib.snprintf(fb, 1024, "1a-pre 总耗时: %llu ms (%d 文件扫描 import 依赖)",
|
||||
t_pre1 - t_pre0, result.Count)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"1a-pre 总耗时: {t_pre1 - t_pre0} ms ({result.Count} 文件扫描 import 依赖)", "Phase1")
|
||||
|
||||
if p1a_failed > 0:
|
||||
viperlib.snprintf(fb, 1024, "Phase 1a-pre 有 %d 个文件扫描失败", p1a_failed)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"Phase 1a-pre 有 {p1a_failed} 个文件扫描失败", "Phase1")
|
||||
return 1
|
||||
|
||||
# ============================================================
|
||||
@@ -366,10 +360,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
tc_ptr: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(topo_count_box, t.CPtr))
|
||||
if tc_ptr is not None:
|
||||
topo_count = tc_ptr[0]
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"拓扑排序: %d 个类, %d 个文件按依赖顺序处理",
|
||||
class_count_scanned, topo_count)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"拓扑排序: {class_count_scanned} 个类, {topo_count} 个文件按依赖顺序处理", "Phase1")
|
||||
else:
|
||||
VLogger.error("拓扑排序失败(类继承依赖无法解析),终止编译", "Phase1")
|
||||
return 1
|
||||
@@ -508,11 +499,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
p1a_reg += 1
|
||||
|
||||
# 逐文件进度日志(parse/translate 两段,定位 1a 卡点)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"[%d/%d] 1a: %s (parse=%llu ms, translate=%llu ms, total=%llu ms)",
|
||||
i + 1, iter_count, file_path_r,
|
||||
t_fa1 - t_fa0, t_fa2 - t_fa1, t_fa2 - t_fa0)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"[{i+1}/{iter_count}] 1a: {file_path_r} (parse={t_fa1-t_fa0} ms, translate={t_fa2-t_fa1} ms, total={t_fa2-t_fa0} ms)", "Phase1")
|
||||
|
||||
# 释放 Translator 的 C malloc 资源
|
||||
if tr_r._global_names is not None:
|
||||
@@ -527,13 +514,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
# 1a 阶段总耗时(struct/enum/union 注册,含每文件读+parse+翻译声明)
|
||||
t_a1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
viperlib.snprintf(fb, 1024, "1a 总耗时: %llu ms (注册 struct/enum, reg=%d skp=%d)",
|
||||
t_a1 - t_a0, p1a_reg, p1a_skp)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"1a 总耗时: {t_a1-t_a0} ms (注册 struct/enum, reg={p1a_reg} skp={p1a_skp})", "Phase1")
|
||||
|
||||
if p1a_fl > 0:
|
||||
viperlib.snprintf(fb, 1024, "Phase 1a 有 %d 个文件 struct 注册失败", p1a_fl)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"Phase 1a 有 {p1a_fl} 个文件 struct 注册失败", "Phase1")
|
||||
return 1
|
||||
|
||||
# 释放拓扑排序资源(topo_order/topo_count_box 保留到 Phase 1b 结束,
|
||||
@@ -653,13 +637,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
# 1b-pre 阶段总耗时(vpi 预生成)
|
||||
t_pv1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
viperlib.snprintf(fb, 1024, "1b-pre 总耗时: %llu ms (vpi 预生成)",
|
||||
t_pv1 - t_pv0)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"1b-pre 总耗时: {t_pv1-t_pv0} ms (vpi 预生成)", "Phase1")
|
||||
|
||||
if p1bpre_failed > 0:
|
||||
viperlib.snprintf(fb, 1024, "Phase 1b-pre 有 %d 个文件 vpi 预生成失败", p1bpre_failed)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"Phase 1b-pre 有 {p1bpre_failed} 个文件 vpi 预生成失败", "Phase1")
|
||||
return 1
|
||||
|
||||
# 遍历每个文件(拓扑序优先:父类所在文件先翻译,确保跨模块 vtable
|
||||
@@ -728,13 +709,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.free(text_path)
|
||||
# text.ll 不存在,需要重新翻译
|
||||
rp: str = entry.RelPath
|
||||
viperlib.snprintf(fb, 1024, "text.ll 不存在,重新翻译: %s(sha1=%s)", rp, sha1)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"text.ll 不存在,重新翻译: {rp}(sha1={sha1})", "Phase1")
|
||||
else:
|
||||
# stub 不存在,需要翻译
|
||||
rp: str = entry.RelPath
|
||||
viperlib.snprintf(fb, 1024, "翻译: %s(sha1=%s)", rp, sha1)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"翻译: {rp}(sha1={sha1})", "Phase1")
|
||||
|
||||
stdlib.free(stub_path)
|
||||
|
||||
@@ -745,13 +724,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
file_path: str = entry.Path
|
||||
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
|
||||
if f is None:
|
||||
viperlib.snprintf(fb, 1024, "无法打开(None): %s", file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"无法打开(f=None): {file_path}", "Phase1")
|
||||
failed += 1
|
||||
continue
|
||||
if f.closed:
|
||||
viperlib.snprintf(fb, 1024, "无法打开: %s", file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"无法打开: {file_path}", "Phase1")
|
||||
failed += 1
|
||||
continue
|
||||
|
||||
@@ -764,8 +741,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
bytes_read: LONG = f.read_all(src_buf, Phase1.SRC_BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read <= 0:
|
||||
viperlib.snprintf(fb, 1024, "读取失败: %s", file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"读取失败: {file_path}", "Phase1")
|
||||
stdlib.free(src_buf)
|
||||
failed += 1
|
||||
continue
|
||||
@@ -784,8 +760,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||
if tree is None:
|
||||
viperlib.snprintf(fb, 1024, "AST 解析失败: %s", file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"AST 解析失败: {file_path}", "Phase1")
|
||||
stdlib.free(src_buf)
|
||||
failed += 1
|
||||
continue
|
||||
@@ -842,9 +817,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# (崩溃点漂移排查:把"翻译过程中随机崩"变成确定性定位)
|
||||
pre_rc: t.CInt = mb.check_alive_blocks(mark1)
|
||||
if pre_rc != 0:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(翻译前存活块, rc=%d): %s", pre_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"内存损坏(翻译前存活块, rc={pre_rc}): {file_path}", "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
ret: int = tr.translate(tree)
|
||||
@@ -853,11 +826,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 诊断:translate 正常返回(若挂起在 translate 内部,此行不会打印,
|
||||
# 用于区分"translate 内部挂起"与"后续 dump 挂起")
|
||||
if ret == 0:
|
||||
viperlib.snprintf(fb, 1024, "翻译完成(translate返回): %s", file_path)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"翻译完成(translate返回): {file_path}", "Phase1")
|
||||
if ret != 0:
|
||||
viperlib.snprintf(fb, 1024, "翻译失败: %s", file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"翻译失败: {file_path}", "Phase1") # error 终止
|
||||
stdlib.free(src_buf)
|
||||
if tr._global_names is not None:
|
||||
stdlib.free(tr._global_names)
|
||||
@@ -872,10 +843,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 时链表成环卡死"变成"定位到 translate 期间写穿发生的文件"。
|
||||
post_rc: t.CInt = mb.check_alive_blocks(mark1)
|
||||
if post_rc != 0:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(translate后存活块, rc=%d): %s", post_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
VLogger.error(f"内存损坏(translate后存活块, rc={post_rc}): {file_path}", "Phase1")
|
||||
|
||||
# dump stub IR(declarations only)
|
||||
PHASE1_IR_SIZE: t.CSizeT = 1048576
|
||||
@@ -927,11 +895,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
|
||||
# 计时点 3:dump(stub+text)完成;输出单文件三段耗时
|
||||
t_f3: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"[%d/%d] 翻译: %s (parse=%llu ms, translate=%llu ms, dump=%llu ms, total=%llu ms)",
|
||||
i + 1, loop_n_b, file_path,
|
||||
t_f1 - t_f0, t_f2 - t_f1, t_f3 - t_f2, t_f3 - t_f0)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"[{i+1}/{loop_n_b}] 翻译: {file_path} (parse={t_f1-t_f0} ms, translate={t_f2-t_f1} ms, dump={t_f3-t_f2} ms, total={t_f3-t_f0} ms)", "Phase1")
|
||||
|
||||
# save dependencies(_imported_modules) for Phase B
|
||||
deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
|
||||
@@ -968,26 +932,18 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# rc 语义(self_check):1/2=越界,3=对齐错,4=free list 成环/超步数
|
||||
chk_rc: t.CInt = mb.check_alive_blocks(mark1)
|
||||
if chk_rc != 0:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(存活块 header, rc=%d): %s", chk_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
VLogger.error(f"内存损坏(存活块 header, rc={chk_rc}): {file_path}", "Phase1")
|
||||
# A/B 实验结论(已确认):禁用 reset_to 后 stdarg 仍崩 → 越界写是根因,
|
||||
# 与回收/UAF 无关。恢复 reset_to,改用块尾 canary(check_alive_blocks 校验)
|
||||
# 定位越界写事发地到具体文件。
|
||||
mb.reset_to(mark1)
|
||||
sc_rc: t.CInt = mb.self_check()
|
||||
if sc_rc != 0:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(free list, rc=%d): %s", sc_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
VLogger.error(f"内存损坏(free list, rc={sc_rc}): {file_path}", "Phase1")
|
||||
|
||||
# 1b 阶段总耗时(全量翻译 + dump)
|
||||
t_b1: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
viperlib.snprintf(fb, 1024, "1b 总耗时: %llu ms (全量翻译, trans=%d skip=%d fail=%d)",
|
||||
t_b1 - t_b0, translated, skipped, failed)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"1b 总耗时: {t_b1-t_b0} ms (全量翻译, trans={translated} skip={skipped} fail={failed})", "Phase1")
|
||||
|
||||
# 释放 Phase 1b 使用的拓扑排序资源
|
||||
if topo_order is not None:
|
||||
@@ -995,12 +951,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
if topo_count_box is not None:
|
||||
mb.free(topo_count_box)
|
||||
|
||||
viperlib.snprintf(fb, 1024, "完成: 翻译=%d 跳过=%d 失败=%d", translated, skipped, failed)
|
||||
VLogger.info(fb, "Phase1")
|
||||
VLogger.info(f"完成: 翻译={translated} 跳过={skipped} 失败={failed}", "Phase1")
|
||||
|
||||
if failed > 0:
|
||||
viperlib.snprintf(fb, 1024, "Phase1 有 %d 个文件翻译失败", failed)
|
||||
VLogger.error(fb, "Phase1")
|
||||
VLogger.error(f"Phase1 有 {failed} 个文件翻译失败", "Phase1")
|
||||
return 1
|
||||
|
||||
# 释放可达 SHA1 集合(如果分配了)
|
||||
|
||||
@@ -358,13 +358,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
Returns: 0 成功,非 0 失败
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if source_dir is None:
|
||||
VLogger.error("source_dir 为空", "project")
|
||||
return 1
|
||||
|
||||
viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir)
|
||||
VLogger.info(fb, "project")
|
||||
VLogger.info(f"多文件项目编译: {source_dir}", "project")
|
||||
|
||||
# === 1. 递归扫描 source_dir 下的 .vp/.py 文件(包括子目录)===
|
||||
entry_size: t.CSizeT = SrcFileEntry.__sizeof__()
|
||||
@@ -374,8 +372,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
string.memset(entries, 0, MAX_SRC_FILES * entry_size)
|
||||
|
||||
file_count: int = _ScanDirForPyFiles(mb, source_dir, entries, entry_size, 0, MAX_SRC_FILES)
|
||||
viperlib.snprintf(fb, 1024, "共 %d 个源文件", file_count)
|
||||
VLogger.info(fb, "project")
|
||||
VLogger.info(f"共 {file_count} 个源文件", "project")
|
||||
|
||||
# 扫描 .s 汇编文件(独立数组,不参与 Phase A 翻译,Phase B 后 llvm-mc 汇编)
|
||||
asm_entries: SrcFileEntry | t.CPtr = stdlib.malloc(MAX_SRC_FILES * entry_size)
|
||||
@@ -385,8 +382,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
string.memset(asm_entries, 0, MAX_SRC_FILES * entry_size)
|
||||
asm_file_count: int = _ScanDirForAsmFiles(mb, source_dir, asm_entries, entry_size, 0, MAX_SRC_FILES)
|
||||
if asm_file_count > 0:
|
||||
viperlib.snprintf(fb, 1024, "汇编文件 %d 个(llvm-mc 汇编参与链接)", asm_file_count)
|
||||
VLogger.info(fb, "project")
|
||||
VLogger.info(f"汇编文件 {asm_file_count} 个(llvm-mc 汇编参与链接)", "project")
|
||||
|
||||
if file_count == 0:
|
||||
stdlib.free(entries)
|
||||
@@ -428,8 +424,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
VLogger.error("includes 扫描失败,无法填充 Sha1Store", "project")
|
||||
if inc_scan_result is not None:
|
||||
inc_filled: int = StubMergerStore.PopulateSha1MapStore(inc_scan_result)
|
||||
viperlib.snprintf(fb, 1024, "Phase2 自主填充 includes Sha1Store: %d 个", inc_filled)
|
||||
VLogger.info(fb, "project")
|
||||
VLogger.info(f"Phase2 自主填充 includes Sha1Store: {inc_filled} 个", "project")
|
||||
|
||||
# 追加 App 源文件 SHA1 到 _sha1_map.txt(人类可读输出,程序内部不读取此文件)
|
||||
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.vp)
|
||||
@@ -458,8 +453,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 同步追加到内存存储器(供跨模块 CDefine 查找)
|
||||
# rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致
|
||||
if StubMergerStore.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0:
|
||||
viperlib.snprintf(fb, 1024, "AppendToSha1MapStore 失败: %s", rel_path_am)
|
||||
VLogger.error(fb, "project")
|
||||
VLogger.error(f"AppendToSha1MapStore 失败: {rel_path_am}", "project")
|
||||
app_filled += 1
|
||||
# 写入 _sha1_map.txt(人类可读输出)
|
||||
if not mf.closed and line_am is not None:
|
||||
@@ -470,8 +464,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
stdlib.free(line_am)
|
||||
if not mf.closed:
|
||||
mf.close()
|
||||
viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled)
|
||||
VLogger.info(fb, "project")
|
||||
VLogger.info(f"已追加 {app_filled} 个 App 文件到 _sha1_map.txt 和内存存储器", "project")
|
||||
stdlib.free(map_path_am)
|
||||
|
||||
# 模块 SHA1 映射已由 PopulateSha1MapStore + AppendToSha1MapStore 统一填充到
|
||||
@@ -562,8 +555,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# OOM 清理:回收本文件 AST(vpi 已写盘;mark2 后持久数据已 stdlib 化)
|
||||
mb.reset_to(mark2)
|
||||
if vpi_failed_p2 > 0:
|
||||
viperlib.snprintf(fb, 1024, "Phase A-pre-vpi 有 %d 个文件 vpi 预生成失败", vpi_failed_p2)
|
||||
VLogger.error(fb, "PhaseA")
|
||||
VLogger.error(f"Phase A-pre-vpi 有 {vpi_failed_p2} 个文件 vpi 预生成失败", "PhaseA")
|
||||
return 1
|
||||
|
||||
|
||||
@@ -664,14 +656,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
for si_inc_f in range(store_count_inc_pre):
|
||||
if inc_fail_flags[si_inc_f] != 0:
|
||||
rel_f: str = store_rel_inc_pre + t.CSizeT(si_inc_f) * StubMerger.MAX_REL_PATH_LEN
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"includes 预注册失败: %s(文件无法翻译,可能是语法/解析/编译错误),终止编译",
|
||||
rel_f)
|
||||
VLogger.error(fb, "prePhaseA")
|
||||
sys.exit(1)
|
||||
VLogger.error(f"includes 预注册失败: {rel_f}(文件无法翻译,可能是语法/解析/编译错误),终止编译", "prePhaseA")
|
||||
stdlib.free(inc_fail_flags)
|
||||
viperlib.snprintf(fb, 1024, "includes 预注册 + 依赖填充: %d/%d", deps_filled_pre, store_count_inc_pre)
|
||||
VLogger.info(fb, "prePhaseA")
|
||||
VLogger.info(f"includes 预注册 + 依赖填充: {deps_filled_pre}/{store_count_inc_pre}", "prePhaseA")
|
||||
|
||||
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
|
||||
# 解决循环引用问题:circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
|
||||
@@ -694,8 +681,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
pkg_pre = GenApi.compute_package_from_relpath(mb, rel_path_pre)
|
||||
tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1)
|
||||
if tr_pre is None:
|
||||
viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path)
|
||||
VLogger.error(fb, "PhaseA")
|
||||
VLogger.error(f"预注册失败: {ent_pre.Path}", "PhaseA")
|
||||
# OOM 清理:回收本 App 文件预注册翻译的瞬时数据
|
||||
mb.reset_to(mark2)
|
||||
struct_count_after: int = GenApi.get_struct_count()
|
||||
@@ -803,6 +789,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if miss_dp is not None:
|
||||
miss_dp[0] = '\0'
|
||||
md_cnt: int = 0
|
||||
war: str = "" # warning 信息
|
||||
if tr_a._imported_modules is not None:
|
||||
im_dp_len: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
im_dp_pos: t.CSizeT = 0
|
||||
@@ -874,20 +861,15 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
md_cnt += 1
|
||||
stdlib.free(im_dp_buf)
|
||||
if md_cnt > 0:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"Phase A 依赖未就绪,下遍重试: %s | 依赖探测明细: %s",
|
||||
ent.Path, miss_dp)
|
||||
war = f"Phase A 依赖未就绪,下遍重试: {ent.Path} | 依赖探测明细: {miss_dp}"
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"Phase A 依赖未就绪,下遍重试: %s | 直接依赖 text.ll 均已生成"
|
||||
"(缺失可能在传递依赖/MRO/vpi 侧)", ent.Path)
|
||||
war = f"Phase A 依赖未就绪,下遍重试: {ent.Path} | 直接依赖 text.ll 均已生成(缺失可能在传递依赖/MRO/vpi 侧)"
|
||||
stdlib.free(miss_dp)
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"Phase A 依赖未就绪,下遍重试: %s", ent.Path)
|
||||
war = f"Phase A 依赖未就绪,下遍重试: {ent.Path}"
|
||||
# --nowarn-register 亦抑制此类 Phase A 依赖重试 WARN(刷屏收敛)
|
||||
if VLogger._nowarn_register == 0:
|
||||
VLogger.warning(fb, "PhaseA-DBG")
|
||||
if VLogger._nowarn_register == 0 and war:
|
||||
VLogger.warning(war, "PhaseA-DBG")
|
||||
# 回滚本文件已注册类的 MethodsEmitted:第 1 遍 _translate_oop_methods
|
||||
# 发射方法体前已置 MethodsEmitted=1(防重入),但方法体内跨模块调用
|
||||
# 依赖 text.ll 未生成触发 _deps_pending → 本遍作废;若不回滚,
|
||||
@@ -947,11 +929,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 计时点 2:stub+text dump 及写盘完成;输出逐文件进度(对齐 Phase1 1b)
|
||||
t_pa2: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"[%d/%d] PhaseA: %s (translate=%llu ms, dump=%llu ms, total=%llu ms)",
|
||||
i + 1, file_count, ent.Path,
|
||||
t_pa1 - t_pa0, t_pa2 - t_pa1, t_pa2 - t_pa0)
|
||||
VLogger.info(fb, "PhaseA")
|
||||
VLogger.info(f"[{i+1}/{file_count}] PhaseA: {ent.Path} (translate={t_pa1-t_pa0} ms, dump={t_pa2-t_pa1} ms, total={t_pa2-t_pa0} ms)", "PhaseA")
|
||||
|
||||
done_flags[i] = 1
|
||||
completed_this_pass += 1
|
||||
@@ -973,11 +951,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
ea_err: t.CUInt64T = t.CUInt64T(entries) + i_err * entry_size
|
||||
ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_err, t.CPtr))
|
||||
if ent_err is not None and ent_err.Path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册;"
|
||||
"缺失依赖明细见上方 PhaseA-DBG 警告,若被 --nowarn-register 抑制请去掉该参数重跑)",
|
||||
ent_err.Path)
|
||||
VLogger.error(fb, "PhaseA")
|
||||
VLogger.error(f"Phase A 无法完成翻译: {ent_err.Path}(请检查依赖模块是否已编译/注册;缺失依赖明细见上方 PhaseA-DBG 警告,若被 --nowarn-register 抑制请去掉该参数重跑)", "PhaseA")
|
||||
stdlib.free(done_flags)
|
||||
VLogger.error("Phase A 多遍收敛失败,终止编译", "PhaseA")
|
||||
stdlib.free(entries)
|
||||
@@ -1034,13 +1008,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
|
||||
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||
if combined_ir is None:
|
||||
viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
VLogger.error(f"combined_ir 分配失败: {ent.Path}", "PhaseB")
|
||||
continue
|
||||
combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
||||
if combined_len == 0:
|
||||
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
VLogger.error(f"BuildCombinedIR 失败: {ent.Path}", "PhaseB")
|
||||
stdlib.free(combined_ir)
|
||||
continue
|
||||
# 计时点 1:BuildCombinedIR 完成
|
||||
@@ -1050,8 +1022,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
ret_w: int = BuildPipeline.write_ir_to_file(combined_ir, combined_len, temp_dir, ent.Sha1)
|
||||
stdlib.free(combined_ir)
|
||||
if ret_w != 0:
|
||||
viperlib.snprintf(fb, 1024, "写 .ll 失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
VLogger.error(f"写 .ll 失败: {ent.Path}", "PhaseB")
|
||||
sys.exit(1)
|
||||
# 计时点 2:写 .ll 完成
|
||||
t_pb2: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
@@ -1065,8 +1036,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
t.CUInt64T(llc_tasks) + t.CSizeT(llc_task_count) * BuildPipeline.LlcTask.__sizeof__(), t.CPtr))
|
||||
if BuildPipeline.init_llc_task(tslot, llc_ir_path, output_dir, ent.Sha1,
|
||||
cc_cmd, cc_flags) != 0:
|
||||
viperlib.snprintf(fb, 1024, "llc 任务构造失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
VLogger.error(f"llc 任务构造失败: {ent.Path}", "PhaseB")
|
||||
sys.exit(1)
|
||||
# 计时点 3:llc 任务构造完成
|
||||
t_pb3: t.CUInt64T = w32.win32base.GetTickCount64()
|
||||
@@ -1074,10 +1044,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
compiled_count += 1
|
||||
# 显示已提交 llc 的文件(含三步计时:合并 stub / 写 .ll / 构造任务)
|
||||
viperlib.snprintf(fb, 1024, "[%d/%d] llc 已提交: %s (merge=%llu ms, write=%llu ms, task=%llu ms, total=%llu ms)",
|
||||
i + 1, file_count, ent.Path,
|
||||
t_pb1 - t_pb0, t_pb2 - t_pb1, t_pb3 - t_pb2, t_pb3 - t_pb0)
|
||||
VLogger.info(fb, "PhaseB")
|
||||
VLogger.info(f"[{i+1}/{file_count}] llc 已提交: {ent.Path} (merge={t_pb1-t_pb0} ms, write={t_pb2-t_pb1} ms, task={t_pb3-t_pb2} ms, total={t_pb3-t_pb0} ms)", "PhaseB")
|
||||
# 构造 .obj 路径,检测是否是 main 模块(test_main.vp 或 main.vp,不再识别 .py)
|
||||
od_len: t.CSizeT = string.strlen(output_dir)
|
||||
is_main_mod: int = 0
|
||||
@@ -1137,8 +1104,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
aret_as: int = BuildPipeline.asm_to_obj(
|
||||
ent_as.Path, ent_as.Sha1, output_dir, Config.TargetTriple)
|
||||
if aret_as != 0:
|
||||
viperlib.snprintf(fb, 1024, "llvm-mc 汇编失败,终止编译: %s", ent_as.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
VLogger.error(f"llvm-mc 汇编失败,终止编译: {ent_as.Path}", "PhaseB")
|
||||
sys.exit(1)
|
||||
obj_path_asm: str = StubMergerCollect._sliced_path(output_dir, od_len_as, ent_as.Sha1, "obj")
|
||||
if obj_path_asm is not None:
|
||||
@@ -1152,11 +1118,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
obj_paths[obj_pos] = '\0'
|
||||
stdlib.free(obj_path_asm)
|
||||
asm_compiled += 1
|
||||
viperlib.snprintf(fb, 1024, "[asm %d] 汇编完成: %s", asm_compiled, ent_as.Path)
|
||||
VLogger.info(fb, "PhaseB")
|
||||
VLogger.info(f"[asm {asm_compiled}] 汇编完成: {ent_as.Path}", "PhaseB")
|
||||
|
||||
viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count)
|
||||
VLogger.success(fb, "PhaseB")
|
||||
VLogger.success(f"编译完成: {compiled_count}/{file_count}", "PhaseB")
|
||||
|
||||
if compiled_count == 0:
|
||||
VLogger.error("无成功编译的文件", "PhaseB")
|
||||
@@ -1172,10 +1136,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
td_len_mi: t.CSizeT = string.strlen(temp_dir)
|
||||
|
||||
# 诊断日志:确认 Phase B+ 入口和 Sha1Store 状态
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"PhaseB+ 入口: store_count=%d includes_binary_dir=%s",
|
||||
StubMergerStore.GetSha1StoreCount(), includes_binary_dir)
|
||||
VLogger.info(fb, "PhaseB+")
|
||||
VLogger.info(f"PhaseB+ 入口: store_count={StubMergerStore.GetSha1StoreCount()} includes_binary_dir={includes_binary_dir}", "PhaseB+")
|
||||
|
||||
# 创建 includes_binary_dir 目录(确保 .obj 能写入和 collect_obj_files 能扫描)
|
||||
BuildPipeline.ensure_dir(includes_binary_dir)
|
||||
@@ -1193,8 +1154,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
string.memset(reachable_set, 0, REACHABLE_SET_SIZE)
|
||||
reachable_count = StubMergerBuild._BuildReachableSha1Set(
|
||||
mb, source_dir, temp_dir, reachable_set, app_deps_buf)
|
||||
viperlib.snprintf(fb, 1024, "可达 includes SHA1: %d 个", reachable_count)
|
||||
VLogger.info(fb, "PhaseB+")
|
||||
VLogger.info(f"可达 includes SHA1: {reachable_count} 个", "PhaseB+")
|
||||
# fast-fail: 可达集合构建失败(依赖未找到),永不回退,直接终止
|
||||
if reachable_count < 0:
|
||||
VLogger.error("可达集合构建失败(fast-fail),终止编译", "PhaseB+")
|
||||
@@ -1222,8 +1182,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
store_rel_arr_mi: bytes = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
store_incdir_arr_mi: bytes = StubMergerStore.GetSha1StoreIncdirArrPtr()
|
||||
# 诊断:_BuildIncludesSha1Map 复制的条目数(PhaseB+ 循环执行前提)
|
||||
viperlib.snprintf(fb, 1024, "诊断 store_count_mi=%d", store_count_mi)
|
||||
VLogger.debug(fb, "PhaseB+")
|
||||
VLogger.debug(f"诊断 store_count_mi={store_count_mi}", "PhaseB+")
|
||||
if store_count_mi > 0:
|
||||
|
||||
# 拓扑排序可达 includes:被依赖模块先完整翻译。跨模块 vtable 生成
|
||||
@@ -1239,17 +1198,13 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
reachable_set, reachable_count, topo_idx)
|
||||
|
||||
# 诊断:拓扑排序条数(0 则循环不执行)
|
||||
viperlib.snprintf(fb, 1024, "诊断 topo_count=%d reachable_count=%d",
|
||||
topo_count, reachable_count)
|
||||
VLogger.debug(fb, "PhaseB+")
|
||||
VLogger.debug(f"诊断 topo_count={topo_count} reachable_count={reachable_count}", "PhaseB+")
|
||||
|
||||
# 诊断:dump reachable_set 内容(验证 BFS 写入的 sha1 是否有效)
|
||||
ri_dbg: int = 0
|
||||
for ri_dbg in range(reachable_count):
|
||||
rsha1_dbg: str = reachable_set + t.CSizeT(ri_dbg) * 17
|
||||
viperlib.snprintf(fb, 1024, "诊断 reachable[%d]=%s",
|
||||
ri_dbg, rsha1_dbg)
|
||||
VLogger.debug(fb, "PhaseB+")
|
||||
VLogger.debug(f"诊断 reachable[{ri_dbg}]={rsha1_dbg}", "PhaseB+")
|
||||
|
||||
for si_mi in range(topo_count):
|
||||
# 当前条目(拓扑序索引,仅含可达模块)
|
||||
@@ -1291,9 +1246,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
continue
|
||||
|
||||
# 诊断:obj 不存在,进入 is_decl 判定
|
||||
viperlib.snprintf(fb, 1024, "诊断 循环 si=%d ti=%d sha1=%s obj_exists=%d",
|
||||
si_mi, ti, inc_sha1_mi, obj_exists_mi)
|
||||
VLogger.debug(fb, "PhaseB+")
|
||||
VLogger.debug(f"诊断 循环 si={si_mi} ti={ti} sha1={inc_sha1_mi} obj_exists={obj_exists_mi}", "PhaseB+")
|
||||
|
||||
# .obj 不存在,需要编译
|
||||
# 构造源文件路径: {所属 includes 根目录}/{rel_path}(多目录逐条取 IncDir,空串回退 includes_dir)
|
||||
@@ -1348,9 +1301,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
tf_mi.close()
|
||||
stdlib.free(tpath_mi)
|
||||
# 诊断:is_decl 判定结果
|
||||
viperlib.snprintf(fb, 1024, "诊断 is_decl=%d src=%s",
|
||||
is_decl_mi, src_fp_mi)
|
||||
VLogger.debug(fb, "PhaseB+")
|
||||
VLogger.debug(f"诊断 is_decl={is_decl_mi} src={src_fp_mi}", "PhaseB+")
|
||||
# is_decl_mi == -1: text.ll 不存在(Phase1 未翻译此文件)
|
||||
# is_decl_mi == 1: 声明文件(仅 declare 无 define)
|
||||
# is_decl_mi == 0: 实现文件(有 define)
|
||||
@@ -1428,10 +1379,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
diag_text_ex = 1
|
||||
df_diag_t.close()
|
||||
stdlib.free(diag_text)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"BuildCombinedIR 失败: %s (stub=%d text=%d is_decl=%d)",
|
||||
src_fp_mi, diag_stub_ex, diag_text_ex, is_decl_mi)
|
||||
VLogger.error(fb, "PhaseB+")
|
||||
VLogger.error(f"BuildCombinedIR 失败: {src_fp_mi} (stub={diag_stub_ex} text={diag_text_ex} is_decl={is_decl_mi})", "PhaseB+")
|
||||
if inc_combined_mi is not None:
|
||||
stdlib.free(inc_combined_mi)
|
||||
stdlib.free(check_pat_mi)
|
||||
@@ -1447,14 +1395,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
stdlib.free(inc_combined_mi)
|
||||
|
||||
if inc_cret_mi != 0:
|
||||
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi)
|
||||
VLogger.error(fb, "PhaseB+")
|
||||
VLogger.error(f"llc 编译失败,终止编译: {src_fp_mi}", "PhaseB+")
|
||||
sys.exit(1)
|
||||
|
||||
inc_compiled += 1
|
||||
# 显示编译完成的 includes 文件
|
||||
viperlib.snprintf(fb, 1024, "[includes %d] 编译完成: %s", inc_compiled, src_fp_mi)
|
||||
VLogger.info(fb, "PhaseB+")
|
||||
VLogger.info(f"[includes {inc_compiled}] 编译完成: {src_fp_mi}", "PhaseB+")
|
||||
|
||||
# 添加到 obj_paths (切片路径,从 includes_binary_dir 取)
|
||||
ibd_len_mi2: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
@@ -1490,8 +1436,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if store_mod_arr_mi is not None:
|
||||
stdlib.free(store_mod_arr_mi)
|
||||
|
||||
viperlib.snprintf(fb, 1024, "编译缺失 includes: %d 个", inc_compiled)
|
||||
VLogger.info(fb, "PhaseB+")
|
||||
VLogger.info(f"编译缺失 includes: {inc_compiled} 个", "PhaseB+")
|
||||
|
||||
# 释放 app_deps_buf(Phase B+ 块未执行时此处兜底释放)
|
||||
if app_deps_buf is not None:
|
||||
@@ -1593,8 +1538,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
fop_pos += op_len_p2
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
elif StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1:
|
||||
viperlib.snprintf(fb, 1024, "可达模块 .obj 缺失: %s", obj_path_pc)
|
||||
VLogger.error(fb, "PhaseC")
|
||||
VLogger.error(f"可达模块 .obj 缺失: {obj_path_pc}", "PhaseC")
|
||||
stdlib.free(obj_path_pc)
|
||||
|
||||
final_obj_paths[fop_pos] = '\0'
|
||||
@@ -1612,19 +1556,15 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
None)
|
||||
|
||||
if lret == 0:
|
||||
viperlib.snprintf(fb, 1024, "输出: %s", exe_path)
|
||||
VLogger.success(fb, "PhaseC")
|
||||
VLogger.success(f"输出: {exe_path}", "PhaseC")
|
||||
if args.get_bool("run") and BuildPipeline._phase2_cmd_path is not None:
|
||||
# phase2command 模式:exe 尚未链接(命令在 bat 中),跳过 --run
|
||||
viperlib.snprintf(fb, 1024, "phase2command 模式:跳过 --run(exe 尚未链接)")
|
||||
VLogger.info(fb, "phase2cmd")
|
||||
VLogger.info("phase2command 模式:跳过 --run(exe 尚未链接)", "phase2cmd")
|
||||
elif args.get_bool("run"):
|
||||
viperlib.snprintf(fb, 1024, "执行: %s", exe_path)
|
||||
VLogger.info(fb, "run")
|
||||
VLogger.info(f"执行: {exe_path}", "run")
|
||||
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||
if rp is not None:
|
||||
viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode)
|
||||
VLogger.info(fb, "run")
|
||||
VLogger.info(f"退出码: {rp.returncode}", "run")
|
||||
else:
|
||||
VLogger.error("链接失败", "PhaseC")
|
||||
stdlib.free(entries)
|
||||
|
||||
@@ -108,12 +108,10 @@ def _SeenInsert(tbl: bytes, cap: t.CSizeT, count: int, key: str, key_hash: t.CUI
|
||||
if tbl is None or key is None:
|
||||
return count
|
||||
kl: t.CSizeT = string.strlen(key)
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if kl >= _SEEN_NAME_MAX:
|
||||
return count
|
||||
if count >= cap:
|
||||
viperlib.snprintf(fb, 1024, "已见符号表满(容量 %d),新增符号登记被丢弃——去重失效,必须增大容量", cap)
|
||||
VLogger.error(fb, "StubMerger")
|
||||
VLogger.error(f"已见符号表满(容量 {cap}),新增符号登记被丢弃——去重失效,必须增大容量", "StubMerger")
|
||||
return count
|
||||
mask: t.CSizeT = cap - 1
|
||||
idx: t.CSizeT = t.CSizeT(key_hash) & mask
|
||||
@@ -288,14 +286,12 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
if dep_path is None:
|
||||
return out_pos
|
||||
df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R)
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if df_ls.closed:
|
||||
stdlib.free(dep_path)
|
||||
# 依赖 stub 缺失:includes 映射内的模块缺失属编译错误(fail-fast),
|
||||
# 非映射模块(如 t/c 内部库、用户文件)按设计跳过
|
||||
if StubMergerStore.LookupSha1RelPath(dep_sha1) is not None:
|
||||
viperlib.snprintf(fb, 1024, "依赖 stub 缺失: %s", dep_sha1)
|
||||
VLogger.error(fb, "StubMerger")
|
||||
VLogger.error(f"依赖 stub 缺失: {dep_sha1}", "StubMerger")
|
||||
return out_pos
|
||||
dep_br_ls: t.CInt64T = df_ls.read_all(dep_buf, StubMerger.STUB_READ_BUF_SIZE)
|
||||
df_ls.close()
|
||||
@@ -486,15 +482,13 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
|
||||
text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, dep_sha1, "text.ll")
|
||||
if text_path is None:
|
||||
return out_pos
|
||||
fb: str = VLogger.fmtbuffer
|
||||
tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
|
||||
if tf_lt.closed:
|
||||
stdlib.free(text_path)
|
||||
# 依赖 text 缺失:includes 映射内的模块缺失属编译错误(fail-fast),
|
||||
# 非映射模块(如 t/c 内部库、用户文件)按设计跳过
|
||||
if StubMergerStore.LookupSha1RelPath(dep_sha1) is not None:
|
||||
viperlib.snprintf(fb, 1024, "依赖 text 缺失: %s", dep_sha1)
|
||||
VLogger.error(fb, "StubMerger")
|
||||
VLogger.error(f"依赖 text 缺失: {dep_sha1}", "StubMerger")
|
||||
return out_pos
|
||||
text_br: t.CInt64T = tf_lt.read_all(dep_buf, StubMerger.STUB_READ_BUF_SIZE)
|
||||
tf_lt.close()
|
||||
@@ -757,9 +751,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
return -1
|
||||
fb: str = VLogger.fmtbuffer
|
||||
viperlib.snprintf(fb, 1024, "SHA1 映射: %d 个", map_count)
|
||||
VLogger.debug(fb, "Reachable")
|
||||
VLogger.debug(f"SHA1 映射: {map_count} 个", "Reachable")
|
||||
|
||||
# 工作列表(空格分隔的模块名)
|
||||
worklist: bytes = stdlib.malloc(StubMerger.REACH_WORKLIST_BUF)
|
||||
@@ -868,9 +860,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
worklist[wl_len - 1] = '\0'
|
||||
wl_len -= 1
|
||||
|
||||
fb: str = VLogger.fmtbuffer
|
||||
viperlib.snprintf(fb, 1024, "源文件直接依赖: '%s'", worklist)
|
||||
VLogger.debug(fb, "Reachable")
|
||||
VLogger.debug(f"源文件直接依赖: '{worklist}'", "Reachable")
|
||||
|
||||
# 2.5. 预加入基础模块(builtins)
|
||||
#
|
||||
@@ -891,8 +881,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
wl_len += 1
|
||||
worklist[wl_len] = '\0'
|
||||
|
||||
viperlib.snprintf(fb, 1024, "预加入容器模块后: '%s'", worklist)
|
||||
VLogger.debug(fb, "Reachable")
|
||||
VLogger.debug(f"预加入容器模块后: '{worklist}'", "Reachable")
|
||||
|
||||
# 3. 工作列表算法:递归收集可达 SHA1
|
||||
processed: bytes = stdlib.malloc(StubMerger.REACH_WORKLIST_BUF)
|
||||
@@ -1024,8 +1013,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
stdlib.free(app_mod_path)
|
||||
if is_app_src == 0:
|
||||
# fast-fail: includes 文件依赖未在内存中找到,Phase 1a-pre 未正确填充
|
||||
viperlib.snprintf(fb, 1024, "依赖未找到 fast-fail: 模块 %s(sha1=%s) 的依赖未在内存中注册", mod_buf, found_sha1)
|
||||
VLogger.error(fb, "Reachable")
|
||||
VLogger.error(f"依赖未找到 fast-fail: 模块 {mod_buf}(sha1={found_sha1}) 的依赖未在内存中注册", "Reachable")
|
||||
stdlib.free(sha1_arr)
|
||||
stdlib.free(mod_arr)
|
||||
stdlib.free(worklist)
|
||||
@@ -1038,8 +1026,7 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
|
||||
stdlib.free(worklist)
|
||||
stdlib.free(processed)
|
||||
|
||||
viperlib.snprintf(fb, 1024, "可达 SHA1: %d 个", reachable_count)
|
||||
VLogger.debug(fb, "Reachable")
|
||||
VLogger.debug(f"可达 SHA1: {reachable_count} 个", "Reachable")
|
||||
return reachable_count
|
||||
# ============================================================
|
||||
# BuildCombinedIR - 组合本地 stub + 依赖 stubs + 本地 text → 完整 IR
|
||||
@@ -1276,7 +1263,6 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
# 2d. 验证 deps.txt 中所有依赖模块的 stub 文件都存在(fail-fast)
|
||||
# 避免到 llc 才报 undefined value 错误。
|
||||
# 仅验证在 includes 映射中找到的模块(t/c 等内部库无 SHA1 映射,自动跳过)。
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if deps_loaded != 0 and inc_count > 0:
|
||||
dep_total: t.CSizeT = string.strlen(deps_buf)
|
||||
dp: t.CSizeT = 0
|
||||
@@ -1317,8 +1303,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
if chk_path is not None:
|
||||
chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R)
|
||||
if chk_f.closed:
|
||||
viperlib.snprintf(fb, 1024, "依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译", mod_nm, found_s, chk_path)
|
||||
VLogger.error(fb, "BuildCombinedIR")
|
||||
VLogger.error(f"依赖模块 '{mod_nm}' (sha1={found_s}) 的 stub 文件不存在: {chk_path},立即终止编译", "BuildCombinedIR")
|
||||
chk_f.close()
|
||||
stdlib.free(chk_path)
|
||||
stdlib.free(mod_nm)
|
||||
@@ -1330,8 +1315,7 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
|
||||
tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
|
||||
if tf.closed:
|
||||
# 本地 text.ll 缺失:合并 IR 无法生成定义块,fail-fast 终止
|
||||
viperlib.snprintf(fb, 1024, "本地 text.ll 缺失: %s", text_path)
|
||||
VLogger.error(fb, "StubMerger")
|
||||
VLogger.error(f"本地 text.ll 缺失: {text_path}", "StubMerger")
|
||||
stdlib.free(text_path)
|
||||
else:
|
||||
text_content: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
|
||||
|
||||
@@ -1436,8 +1436,6 @@ class AssignGenMixin:
|
||||
def translate_assign(self, trans: HT.Translator | t.CPtr,
|
||||
node: ast.AST | t.CPtr) -> int:
|
||||
"""翻译 Assign 语句,返回新增变量数(0 或 1)"""
|
||||
|
||||
fb: str = VLogger.fmtbuffer
|
||||
|
||||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||||
if asgn is None:
|
||||
@@ -1490,23 +1488,15 @@ class AssignGenMixin:
|
||||
tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value)
|
||||
target_nm = tn_nm.id
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d '%s.%s' 属性访问失败",
|
||||
rel_path, val_line, target_nm, attr_nm)
|
||||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} '{target_nm}.{attr_nm}' 属性访问失败", "ASGN")
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败",
|
||||
sha1, val_line, target_nm, attr_nm)
|
||||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} '{target_nm}.{attr_nm}' 属性访问失败", "ASGN")
|
||||
elif val_kind == ast.ASTKind.Name:
|
||||
nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value)
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d 变量 '%s' 未找到",
|
||||
rel_path, val_line, nm_nv.id)
|
||||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} 变量 '{nm_nv.id}' 未找到", "ASGN")
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到",
|
||||
sha1, val_line, nm_nv.id)
|
||||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} 变量 '{nm_nv.id}' 未找到", "ASGN")
|
||||
elif val_kind == ast.ASTKind.Call:
|
||||
cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value)
|
||||
func_nm: str = "?"
|
||||
@@ -1515,23 +1505,14 @@ class AssignGenMixin:
|
||||
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func)
|
||||
func_nm = fn_nm.id
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None",
|
||||
rel_path, val_line, func_nm)
|
||||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} 调用 '{func_nm}(...)' 返回 None", "ASGN")
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None",
|
||||
sha1, val_line, func_nm)
|
||||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} 调用 '{func_nm}(...)' 返回 None", "ASGN")
|
||||
else:
|
||||
if rel_path is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: %s:%d [kind=%d]",
|
||||
rel_path, val_line, val_kind)
|
||||
VLogger.error(f"赋值右侧为 None: {rel_path}:{val_line} [kind={val_kind}]")
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"赋值右侧为 None: sha1=%s:%d [kind=%d]",
|
||||
sha1, val_line, val_kind)
|
||||
VLogger.error(fb, "ASGN")
|
||||
VLogger.error(f"赋值右侧为 None: sha1={sha1}:{val_line} [kind={val_kind}]")
|
||||
else:
|
||||
VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
|
||||
return 0
|
||||
@@ -1890,8 +1871,7 @@ class AssignGenMixin:
|
||||
mod_gv: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||||
trans.SymTab, nm.id)
|
||||
if mod_gv is not None:
|
||||
viperlib.snprintf(fb, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id)
|
||||
self.Gen.TypeGenErr.fatal_error(target, fb, "SyntaxError")
|
||||
self.Gen.TypeGenErr.fatal_error(target, f"变量 '{nm.id}' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", "SyntaxError")
|
||||
|
||||
# 普通局部变量
|
||||
alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen.get_or_create_sym(
|
||||
|
||||
@@ -647,36 +647,6 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
# 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value
|
||||
if found_func is None:
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||||
# [根治] declare 创建后按形参类型 coerce 实参(与上方 found_func 路径
|
||||
# 的 L588-611 同逻辑,缺失导致字面量 0=i32 传 i64 形参(t.CSizeT)未提升:
|
||||
# llc 按 i32 布局栈参(movl 4 字节写)→ i64 形参高 4 字节残留垃圾 →
|
||||
# callee 读 can=[垃圾][count] 崩溃,SlotsBugTest/StringIterTest 根因,
|
||||
# 反汇编 movl 实锤)。coerce 使 IR call 实参与 declare 形参类型一致。
|
||||
dc_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||||
if dc_func is not None and head is not None:
|
||||
dc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dc_func)
|
||||
dc_node: llvmlite.Value | t.CPtr = head
|
||||
dc_new_head: llvmlite.Value | t.CPtr = head
|
||||
dc_prev: llvmlite.Value | t.CPtr = None
|
||||
while dc_node is not None:
|
||||
dc_next: llvmlite.Value | t.CPtr = dc_node.Next
|
||||
dc_cur: llvmlite.Value | t.CPtr = dc_node
|
||||
if dc_param is not None:
|
||||
dc_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dc_param)
|
||||
if dc_pty is not None:
|
||||
dc_c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||||
builder, dc_node, dc_pty, None)
|
||||
if dc_c is not None:
|
||||
dc_cur = dc_c
|
||||
dc_param = llvmlite.param_get_next(dc_param)
|
||||
dc_cur.Next = None
|
||||
if dc_prev is None:
|
||||
dc_new_head = dc_cur
|
||||
else:
|
||||
dc_prev.Next = dc_cur
|
||||
dc_prev = dc_cur
|
||||
dc_node = dc_next
|
||||
head = dc_new_head
|
||||
|
||||
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
|
||||
# ============================================================
|
||||
@@ -710,12 +680,6 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
mc_entry = self.Gen.StructGen.find_struct_by_type(mc_struct_ty)
|
||||
if mc_entry is None:
|
||||
mc_entry = self.Gen.StructGen.find_struct(class_name)
|
||||
# [MMDBG] 诊断:mc_entry 解析(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
if mc_entry is not None:
|
||||
stdio.printf("[MMDBG] mc_entry.Name=%s\n", mc_entry.Name)
|
||||
else:
|
||||
stdio.printf("[MMDBG] mc_entry=None\n")
|
||||
|
||||
# 构造方法查找名: ClassName.method_name
|
||||
lookup_name: str = pool.alloc(128)
|
||||
@@ -725,12 +689,6 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
|
||||
# 查找函数(支持 SHA1 后缀匹配)
|
||||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||||
# [MMDBG] 诊断:found_func 查找(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
if found_func is not None:
|
||||
stdio.printf("[MMDBG] found_func=%s\n", llvmlite.function_get_name(found_func))
|
||||
else:
|
||||
stdio.printf("[MMDBG] found_func=None lookup=%s\n", lookup_name)
|
||||
|
||||
# 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get),
|
||||
# "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成,
|
||||
@@ -1589,20 +1547,9 @@ class CallGenCall(CallGenBase.CallGenBase):
|
||||
is_variadic_3441: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||||
pool, builder, mod, call_name, head, total_count, cargs, 1, trans)
|
||||
# try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测
|
||||
# [MMDBG] 诊断:调用发射前状态(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
stdio.printf("[MMDBG] pre-call call_name=%s ret_ty_ptr=%llu head=%llu count=%d\n",
|
||||
call_name, t.CUInt64T(call_ret_ty), t.CUInt64T(head), total_count)
|
||||
res_final: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||||
return self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||||
builder, pool, mod, trans, found_func, call_name, head, total_count,
|
||||
call_ret_ty, is_variadic_3441)
|
||||
# [MMDBG] 诊断:调用发射结果(用后移除)
|
||||
if string.strcmp(method_name, "Sub") == 0:
|
||||
if res_final is not None:
|
||||
stdio.printf("[MMDBG] _emit_eh_guarded_call ok\n")
|
||||
else:
|
||||
stdio.printf("[MMDBG] _emit_eh_guarded_call None\n")
|
||||
return res_final
|
||||
# ============================================================
|
||||
# _translate_super_call — super().method(args) → 静态调用父类方法
|
||||
#
|
||||
|
||||
@@ -127,12 +127,6 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
|
||||
普通结构体:alloca → zero + defaults → store 参数 → load
|
||||
"""
|
||||
# [DET] callee 入口 can 核对(无条件首条打印):与槽位悬空处 can 对比——
|
||||
# 入口即垃圾 = ABI 栈参数错位(caller 存/callee 读错位 4 字节);
|
||||
# 入口正常但槽位悬空处垃圾 = 函数内部 can 被改写(栈槽复用)。
|
||||
# 无条件打印仅在进入结构体构造时执行一次(每 ctor 一条,量可控)。
|
||||
stdio.printf("[DET] ctor入口: can=%llu cargs=%llu\n",
|
||||
t.CUInt64T(can), t.CUInt64T(cargs))
|
||||
# [DET] 读取侧存活校验(detection 模式启用):cargs(cl.args)必须指向
|
||||
# 存活块——不在记录表(或已 free)= use-after-free 读取(SlotsBugTest
|
||||
# KwEntry cargs 悬空根因定位)。is_alive 内部处理 detection==0 时不拦截,
|
||||
@@ -428,8 +422,6 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
cargs: 参数 AST 列表
|
||||
can: 参数数量
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
|
||||
if pool is None or builder is None or class_name is None:
|
||||
return None
|
||||
|
||||
@@ -440,8 +432,10 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if renum_entry is None:
|
||||
renum_entry = self.Gen.StructGen.find_struct(class_name)
|
||||
if renum_entry is None:
|
||||
viperlib.snprintf(fb, 1024, "REnum construct: type %s not registered", class_name)
|
||||
VLogger.error(fb, "RENUM")
|
||||
fb_re: str = VLogger.fmt_buf()
|
||||
if fb_re is not None:
|
||||
viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name)
|
||||
VLogger.error(fb_re, "RENUM")
|
||||
return None
|
||||
|
||||
renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty
|
||||
@@ -715,7 +709,7 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
if kw is None or kw.arg is None or kw.value is None:
|
||||
continue
|
||||
fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class(
|
||||
class_name, kw.arg, kw_sha1, kw, trans._from_imports)
|
||||
class_name, kw.arg, kw_sha1)
|
||||
if fe is None:
|
||||
# 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
|
||||
@@ -813,8 +813,6 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
cl: ast.Call | t.CPtr,
|
||||
trans: HT.Translator | t.CPtr = None) -> None:
|
||||
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
|
||||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||||
if cargs is None:
|
||||
return
|
||||
@@ -843,8 +841,7 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if arg_val is None or arg_val.Ty is None:
|
||||
# fail-fast:print 参数翻译失败必须终止编译,绝不在格式串写
|
||||
# 误导为数据问题而非编译器 bug。
|
||||
viperlib.snprintf(fb, 1024, "print 参数翻译失败(表达式返回 None): [arg=%d]", ai)
|
||||
VLogger.error(fb, "PRINT")
|
||||
VLogger.error(f"print 参数翻译失败(表达式返回 None): [arg={ai}]", "PRINT")
|
||||
self.Gen.TypeGenErr.fatal_error(arg, "print 参数翻译失败(表达式返回 None)", "TypeError")
|
||||
return
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
can: t.CSizeT = 0
|
||||
if cargs is not None:
|
||||
can = len(cargs)
|
||||
|
||||
# super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回
|
||||
# None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理"
|
||||
# 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名
|
||||
@@ -226,30 +227,8 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 用 find_struct_by_module 规避跨模块同名 find_struct 找错
|
||||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
gen_ctor_entry: GenTypes.StructEntry | t.CPtr = None
|
||||
# 模块限定构造 Module.Class(...) 优先:按模块名解析 SHA1 精确命中类。
|
||||
# 必须在裸名可见性分支之前——跨模块同名类(VKernel gfx 与 App gfx 都
|
||||
# 定义 Scene3D)存在时,裸名 find_struct 返回先注册的错误 entry
|
||||
# (0ae → ctor 生成 @0ae.Scene3D.__before_init__ → 链接 undefined
|
||||
# symbol,Scene3D 根因)。模块解析成功即锁定,跳过下方裸名回退。
|
||||
mod_qual_done: int = 0
|
||||
if trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_qc0: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
mod_path0: str = None
|
||||
if at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc0.value)
|
||||
if mod_nm0.id is not None:
|
||||
mod_path0 = mod_nm0.id
|
||||
elif at_qc0.value is not None and at_qc0.value.kind() == ast.ASTKind.Attribute:
|
||||
mod_path0 = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc0.value)
|
||||
if mod_path0 is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mod_path0) != 0:
|
||||
mod_sha1_0: str = self._lookup_module_sha1(mod_path0)
|
||||
if mod_sha1_0 is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(
|
||||
func_name, mod_sha1_0)
|
||||
mod_qual_done = 1
|
||||
vis: int = self.Gen.StructGen.is_struct_visible(func_name)
|
||||
if mod_qual_done == 0 and vis != 0:
|
||||
if vis != 0:
|
||||
if trans is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1)
|
||||
if gen_ctor_entry is None:
|
||||
@@ -260,20 +239,10 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name:
|
||||
mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value)
|
||||
imp_ok: int = self.Gen.ImportsGen.is_module_imported_or_known(trans._imported_modules, mod_nm_qc.id)
|
||||
imp_ok: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_nm_qc.id)
|
||||
if imp_ok != 0:
|
||||
# 模块限定构造 Module.Class(...):按模块名解析 SHA1 精确命中类。
|
||||
# 不能用 trans.ModuleSha1(那是当前文件 sha1,类在 gfx 模块)——
|
||||
# find_struct_by_module 落空后裸名回退 find_struct 会命中跨模块
|
||||
# 同名类中先注册的 entry(VKernel gfx 与 App gfx 都定义 Scene3D,
|
||||
# 0ae 先注册 → ctor 生成 @0ae.Scene3D.__before_init__ → 链接
|
||||
# undefined symbol,Scene3D 根因)。
|
||||
mod_sha1_qc2: str = None
|
||||
if mod_nm_qc.id is not None:
|
||||
mod_sha1_qc2 = self._lookup_module_sha1(mod_nm_qc.id)
|
||||
if mod_sha1_qc2 is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(
|
||||
func_name, mod_sha1_qc2)
|
||||
if trans is not None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1)
|
||||
if gen_ctor_entry is None:
|
||||
gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||||
if gen_ctor_entry is not None:
|
||||
@@ -337,7 +306,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
ctor_is_oop = gen_ctor_entry.IsOOP
|
||||
if ctor_is_oop != 0:
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, t.CSizeT(0), trans)
|
||||
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
|
||||
# @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存
|
||||
# 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解
|
||||
# (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误
|
||||
@@ -347,7 +316,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
ctor_is_novt = gen_ctor_entry.IsNoVTable
|
||||
if ctor_is_novt != 0:
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, t.CSizeT(0), trans)
|
||||
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
|
||||
# 普通结构体:检查是否有默认值(用 entry 直接访问)
|
||||
gen_has_defaults: int = 0
|
||||
if gen_ctor_entry is not None:
|
||||
@@ -362,7 +331,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if gen_has_defaults == 1:
|
||||
# 有默认值:走构造函数路径应用默认值
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, t.CSizeT(0), trans)
|
||||
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
|
||||
# 无默认值:返回 zeroinitializer
|
||||
ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
|
||||
return ret
|
||||
@@ -371,6 +340,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor_kw(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, can,
|
||||
keywords, kw_count, trans)
|
||||
# 仅位置参数:按字段顺序构建
|
||||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||||
pool, builder, mod, struct_ty, func_name, cargs, can, trans)
|
||||
|
||||
@@ -622,19 +592,9 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
xm_mod_path = self.Gen.ExprGenAttr._attr_module_path_str(
|
||||
pool, xm_at.value)
|
||||
if xm_mod_path is not None:
|
||||
if self.Gen.ImportsGen.is_module_imported_or_known(
|
||||
if self.Gen.ImportsGen.is_module_imported(
|
||||
trans._imported_modules, xm_mod_path) != 0:
|
||||
mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path)
|
||||
if mod_sha1_chk is None and trans._from_imports is not None:
|
||||
# import X as Y(如 import fat32_diskio as diskio):
|
||||
# 精确查不到别名,必须按别名还原后再查(精确→后缀→
|
||||
# LookupModNameByAlias 三级)。否则本校验被跳过 →
|
||||
# find_func_in_module 后缀匹配误命中本模块同名函数
|
||||
# (diskio.read 命中 fat32 自身 read)→ call 到错误
|
||||
# 符号 + 参数错位 + define 被 4 参调用污染(VKernel
|
||||
# llc "instruction expected to be numbered" 根因)。
|
||||
mod_sha1_chk = self.Gen.StructGen._resolve_module_sha1(
|
||||
xm_mod_path, trans._from_imports)
|
||||
if mod_sha1_chk is not None:
|
||||
ff_nm2: str = llvmlite.function_get_name(found_func)
|
||||
if ff_nm2 is not None:
|
||||
@@ -680,19 +640,12 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
if bi_sha1 is not None:
|
||||
bi_ret: llvmlite.LLVMType | t.CPtr = None
|
||||
bi_p1: llvmlite.LLVMType | t.CPtr = None
|
||||
bi_p2: llvmlite.LLVMType | t.CPtr = None
|
||||
if string.strcmp(func_name, "ord") == 0:
|
||||
bi_ret = llvmlite.Int32(pool)
|
||||
bi_p1 = llvmlite.Int8(pool)
|
||||
elif string.strcmp(func_name, "chr") == 0:
|
||||
bi_ret = llvmlite.Int8(pool)
|
||||
bi_p1 = llvmlite.Int32(pool)
|
||||
elif string.strcmp(func_name, "min") == 0 or string.strcmp(func_name, "max") == 0:
|
||||
# min/max 数值比较(builtins.vp 定义 double 参数/返回,
|
||||
# int/float 实参经 coerce 提升;两参数)
|
||||
bi_ret = llvmlite.Double(pool)
|
||||
bi_p1 = llvmlite.Double(pool)
|
||||
bi_p2 = llvmlite.Double(pool)
|
||||
if bi_ret is not None:
|
||||
bi_sym: str = func_name
|
||||
if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0:
|
||||
@@ -705,8 +658,6 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
pool, mod, bi_sym, bi_ret)
|
||||
if bi_decl is not None:
|
||||
llvmlite.add_param(pool, bi_decl, bi_p1, "v")
|
||||
if bi_p2 is not None:
|
||||
llvmlite.add_param(pool, bi_decl, bi_p2, "w")
|
||||
found_func = bi_decl
|
||||
# 使用访问器绕过 stub 类型限制
|
||||
found_ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
@@ -727,20 +678,12 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 →
|
||||
# free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。
|
||||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
# 跨模块返回类型解析的来源模块 SHA1:仅在下方 cl.func 是
|
||||
# Attribute(模块.函数) 分支赋值。必须显式初始化 None——此前声明在
|
||||
# if 块内、elif mod_ret_sha1 is not None 在外层读取,裸名调用
|
||||
# (cl.func 是 Name,如 LLVMModuleCore 方法内裸名 create_global_int)
|
||||
# 时该 alloca 从未 store,读到栈残留垃圾(0x1)→
|
||||
# _LookupMethodRetTyFromTextLL 的 strlen(0x1) 零页崩溃
|
||||
# (llvmlite/__init__.vp CreateGlobalInt 翻译时 0xC0000005 根因)。
|
||||
mod_ret_sha1: str = None
|
||||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||||
at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||||
if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name:
|
||||
mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value)
|
||||
if mod_ret_nm.id is not None:
|
||||
mod_ret_sha1 = self._lookup_module_sha1(mod_ret_nm.id)
|
||||
mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id)
|
||||
if mod_ret_sha1 is not None:
|
||||
# 函数内懒 import:VpiReader imports HandlesExprCall,
|
||||
# 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致)
|
||||
@@ -754,57 +697,18 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
llvmlite.Ptr(pool, llvmlite.Int8(pool)))
|
||||
if vpi_ret_ty is not None:
|
||||
call_ret_ty = vpi_ret_ty
|
||||
elif mod_ret_sha1 is not None:
|
||||
# 跨模块裸名 CExport 函数(如 mm.malloc → @malloc):found_func=None
|
||||
# 且 vpi 返回注解缓存未命中时,仍从依赖模块 text.ll/vpi 精确解析
|
||||
# 返回类型(对齐 mangled 路径),避免静默默认 i32 截断指针/i64
|
||||
# (uhci.vp mm.malloc 根因:call i32 @malloc 截断 0xbb69000 → null)。
|
||||
# 依赖模块尚未编译(text.ll/vpi 均未生成)→ 标记 _deps_pending=1
|
||||
# 下遍重试,本遍保持默认类型(Phase A 多遍收敛)。
|
||||
cross_ret: llvmlite.LLVMType | t.CPtr = None
|
||||
if trans is not None and trans._declare_only == 0:
|
||||
cross_ret = self._LookupMethodRetTyFromTextLL(
|
||||
pool, mod_ret_sha1, None, func_name, 1)
|
||||
if cross_ret is None:
|
||||
cross_ret = self._lookup_method_ret_ty_via_vpi(
|
||||
pool, mod_ret_sha1, None, func_name)
|
||||
if cross_ret is not None:
|
||||
call_ret_ty = cross_ret
|
||||
else:
|
||||
if trans is not None and trans._declare_only == 0:
|
||||
if self._dep_text_ll_exists(pool, mod_ret_sha1) == 0:
|
||||
trans._deps_pending = 1
|
||||
call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name)
|
||||
else:
|
||||
call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name)
|
||||
|
||||
# 如果模块中找不到函数,仅裸名调用(Name)才回退查局部变量(函数指针/
|
||||
# 闭包调用);模块属性调用(VLogger.fmtbuffer)的目标是模块符号,绝不
|
||||
# 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmtbuffer
|
||||
# 曾劫持 VLogger.fmtbuffer → 误走函数指针调用报 t.Callable 缺失),
|
||||
# 闭包调用);模块属性调用(VLogger.fmt_buf())的目标是模块符号,绝不
|
||||
# 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmt_buf
|
||||
# 曾劫持 VLogger.fmt_buf → 误走函数指针调用报 t.Callable 缺失),
|
||||
# 仅 from-import 的裸名 yyy 与局部重名才可能冲突(该场景 func 是 Name)。
|
||||
if found_func is None:
|
||||
fp_alloca: llvmlite.Value | t.CPtr = None
|
||||
if cl.func is None or cl.func.kind() == ast.ASTKind.Name:
|
||||
# 闭包内调用捕获的闭包变量(如 _cmd_cd 调 _build_path):
|
||||
# 从 env 读闭包对象指针,不能 lookup_var 跨函数命中父函数
|
||||
# 闭包 alloca(SSA 错乱 → llc "instruction expected to be
|
||||
# numbered",Terminal _cmd_cd 根因)。
|
||||
if trans is not None and HT.is_nonlocal_name(trans, func_name) != 0:
|
||||
fp_alloca = self.Gen.StmtGenDecl.load_nonlocal_var(trans, func_name)
|
||||
if fp_alloca is not None:
|
||||
# translate_closure_call 期望 i8** 存储(load 一次得闭包
|
||||
# 对象指针);load_nonlocal_var 已返回对象指针 → 临时
|
||||
# alloca 暂存
|
||||
i8_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||||
i8_ptr_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_nl)
|
||||
tmp_alloca_nl: llvmlite.Value | t.CPtr = llvmlite.build_alloca(
|
||||
builder, i8_ptr_ty_nl)
|
||||
if tmp_alloca_nl is not None:
|
||||
llvmlite.build_store(builder, fp_alloca, tmp_alloca_nl)
|
||||
fp_alloca = tmp_alloca_nl
|
||||
else:
|
||||
fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name)
|
||||
fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name)
|
||||
if fp_alloca is not None:
|
||||
# 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用
|
||||
if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0:
|
||||
@@ -1046,24 +950,6 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
found_name: str = llvmlite.function_get_name(found_func)
|
||||
if found_name is not None:
|
||||
call_name = found_name
|
||||
# CExport 裸名兜底:跨模块 stub declare 可能带 SHA1 前缀
|
||||
# (@"1fdad1c76fb116bc.malloc"),但定义端 CExport 函数
|
||||
# (mm.vp malloc/free/malloc_direct,返回注解含 t.CExport)
|
||||
# 用裸名 @malloc → 链接 undefined symbol: 1fdad1c76fb116bc.malloc。
|
||||
# found_func 非 None 时下方 is_cexport_func 裸名分支不执行
|
||||
# (该分支仅 found_func None 的模块限定路径),这里对带前缀
|
||||
# 的 declare 提取 sha1 再查 CExport 注册表,命中则改用裸名。
|
||||
if found_func.IsDeclared != 0:
|
||||
dot_pos_cx: str = string.strchr(found_name, 46)
|
||||
if dot_pos_cx is not None:
|
||||
cx_pre_len: t.CSizeT = string.strlen(found_name) - string.strlen(dot_pos_cx)
|
||||
if cx_pre_len == 16:
|
||||
cx_sha1_buf: str = pool.alloc(17)
|
||||
if cx_sha1_buf is not None:
|
||||
string.memcpy(cx_sha1_buf, found_name, 16)
|
||||
cx_sha1_buf[16] = '\0'
|
||||
if self.Gen.CallGenBase.is_cexport_func(cx_sha1_buf, func_name) != 0:
|
||||
call_name = func_name
|
||||
else:
|
||||
# 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用
|
||||
# 如 string.strchr(...) → @{sha1_of_string}.strchr
|
||||
@@ -1093,7 +979,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。
|
||||
is_xmod_imported: int = 1
|
||||
if trans is not None and trans._imported_modules is not None:
|
||||
is_xmod_imported = self.Gen.ImportsGen.is_module_imported_or_known(
|
||||
is_xmod_imported = self.Gen.ImportsGen.is_module_imported(
|
||||
trans._imported_modules, xmod_path)
|
||||
if is_xmod_imported == 0:
|
||||
err_ni: str = pool.alloc(256)
|
||||
@@ -1327,11 +1213,13 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 保持白名单类型继续,Phase A 多遍循环下遍重译——
|
||||
# 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。
|
||||
if self._dep_text_ll_exists(pool, cf_sha1) != 0:
|
||||
viperlib.snprintf(
|
||||
VLogger.fmtbuffer, 1024,
|
||||
"跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中),"
|
||||
"默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name)
|
||||
VLogger.error(VLogger.fmtbuffer, "HandlesExprCall")
|
||||
cf_err: str = VLogger.fmt_buf()
|
||||
if cf_err is not None:
|
||||
viperlib.snprintf(
|
||||
cf_err, 1024,
|
||||
"跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中),"
|
||||
"默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name)
|
||||
VLogger.error(cf_err, "HandlesExprCall")
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node,
|
||||
f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}",
|
||||
@@ -1339,12 +1227,14 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
else:
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
cf_dbg: str = VLogger.fmt_buf()
|
||||
if cf_dbg is not None:
|
||||
viperlib.snprintf(
|
||||
VLogger.fmtbuffer, 1024,
|
||||
cf_dbg, 1024,
|
||||
"跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序),"
|
||||
"标记重试,本遍保持默认类型", call_name)
|
||||
if VLogger._nowarn_register == 0:
|
||||
VLogger.warning(VLogger.fmtbuffer, "HandlesExprCall")
|
||||
if VLogger.nowarn_register() == 0:
|
||||
VLogger.warning(cf_dbg, "HandlesExprCall")
|
||||
stdlib.free(cf_sha1)
|
||||
stdlib.free(cf_bare)
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
@@ -1352,7 +1242,7 @@ class CallGenMixin(CallGenBase.CallGenBase):
|
||||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||||
# (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用)
|
||||
is_variadic_call: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||||
pool, builder, mod, call_name, head, can, cargs, t.CSizeT(0), trans)
|
||||
pool, builder, mod, call_name, head, can, cargs, 0, trans)
|
||||
# try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常
|
||||
return self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||||
builder, pool, mod, trans, found_func, call_name, head, can,
|
||||
|
||||
@@ -141,7 +141,6 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if cd is None or cd.name is None or trans is None:
|
||||
return 0
|
||||
|
||||
fb: str = VLogger.fmtbuffer
|
||||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||||
class_name: str = cd.name
|
||||
|
||||
@@ -152,8 +151,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
|
||||
VLogger.warning(fb, "ENUM")
|
||||
VLogger.warning(f"{class_name} has no body", "ENUM")
|
||||
return 0
|
||||
|
||||
cn: t.CSizeT = len(children)
|
||||
@@ -251,8 +249,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
member_count += 1
|
||||
|
||||
if member_count == 0:
|
||||
viperlib.snprintf(fb, 1024, "%s has no members", class_name)
|
||||
VLogger.warning(fb, "ENUM")
|
||||
VLogger.warning(f"{class_name} has no members", "ENUM")
|
||||
return 0
|
||||
|
||||
# 确定基准类型:所有成员类型中 Bits 最大的
|
||||
@@ -273,8 +270,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
entry: GenTypes.EnumEntry | t.CPtr = self.Gen.StmtGenDecl.register_enum(
|
||||
pool, class_name, base_ty)
|
||||
if entry is None:
|
||||
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
|
||||
VLogger.error(fb, "ENUM")
|
||||
VLogger.error("failed to register {class_name}", "ENUM")
|
||||
return 0
|
||||
|
||||
# 添加成员
|
||||
@@ -292,9 +288,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if mname is not None and mty2 is not None:
|
||||
self.Gen.StmtGenDecl.add_enum_member(pool, entry, mname, mval, mty2)
|
||||
|
||||
viperlib.snprintf(fb, 1024, "registered %s with %d members, base_bits=%d",
|
||||
class_name, member_count, max_bits)
|
||||
VLogger.info(fb, "ENUM")
|
||||
VLogger.info(f"registered {class_name} with {member_count} members, base_bits={max_bits}", "ENUM")
|
||||
return 0
|
||||
|
||||
def _get_type_size(self, ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||||
@@ -383,7 +377,6 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
def _translate_union_def(self, trans: HT.Translator | t.CPtr,
|
||||
cd: ast.ClassDef | t.CPtr) -> int:
|
||||
"""翻译联合体定义,返回 0"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if cd is None or cd.name is None or trans is None:
|
||||
return 0
|
||||
|
||||
@@ -405,8 +398,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
|
||||
VLogger.warning(fb, "UNION")
|
||||
VLogger.warning("{class_name} has no body", "UNION")
|
||||
return 0
|
||||
|
||||
cn: t.CSizeT = len(children)
|
||||
@@ -468,8 +460,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
field_count += 1
|
||||
|
||||
if field_count == 0:
|
||||
viperlib.snprintf(fb, 1024, "%s has no fields", class_name)
|
||||
VLogger.warning(fb, "UNION")
|
||||
VLogger.warning(f"{class_name} has no fields", "UNION")
|
||||
return 0
|
||||
|
||||
if max_size < 1:
|
||||
@@ -497,8 +488,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
union_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, pnode, 1, union_type_name)
|
||||
if union_ty is None:
|
||||
viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name)
|
||||
VLogger.error(fb, "UNION")
|
||||
VLogger.error(f"failed to create type for {class_name}", "UNION")
|
||||
return 0
|
||||
|
||||
# Phase 1b 新注册的 union struct_ty 深拷贝到 stdlib(跨文件 reset 存活)
|
||||
@@ -519,8 +509,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct(
|
||||
pool, class_name, union_ty, trans.ModuleSha1)
|
||||
if entry is None:
|
||||
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
|
||||
VLogger.error(fb, "UNION")
|
||||
VLogger.error(f"failed to register {class_name}", "UNION")
|
||||
return 0
|
||||
|
||||
# 标记为当前文件可见(命名空间隔离)
|
||||
@@ -543,9 +532,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
if fname is not None and fty2 is not None:
|
||||
self.Gen.StructGen.add_field(pool, entry, fname, fty2, None, None)
|
||||
|
||||
viperlib.snprintf(fb, 1024, "registered %s with %d fields, max_size=%d",
|
||||
class_name, field_count, max_size)
|
||||
VLogger.info(fb, "UNION")
|
||||
VLogger.info(f"registered {class_name} with {field_count} fields, max_size={max_size}", "UNION")
|
||||
return 0
|
||||
def _get_annotation_field_size(self, annotation: ast.AST | t.CPtr) -> int:
|
||||
"""计算注解类型的字节大小,用于 REnum 布局计算"""
|
||||
@@ -608,7 +595,6 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
def _translate_renum_def(self, trans: HT.Translator | t.CPtr,
|
||||
cd: ast.ClassDef | t.CPtr) -> int:
|
||||
"""翻译 REnum 类定义,返回 0"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if cd is None or cd.name is None or trans is None:
|
||||
return 0
|
||||
|
||||
@@ -628,8 +614,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
|
||||
children: list[ast.AST | t.CPtr] | t.CPtr = cd.children
|
||||
if children is None:
|
||||
viperlib.snprintf(fb, 1024, "%s has no body", class_name)
|
||||
VLogger.warning(fb, "RENUM")
|
||||
VLogger.warning(f"{class_name} has no body", "RENUM")
|
||||
return 0
|
||||
|
||||
cn: t.CSizeT = len(children)
|
||||
@@ -701,8 +686,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
variant_count += 1
|
||||
|
||||
if variant_count == 0:
|
||||
viperlib.snprintf(fb, 1024, "%s has no variants", class_name)
|
||||
VLogger.warning(fb, "RENUM")
|
||||
VLogger.warning(f"{class_name} has no variants", "RENUM")
|
||||
return 0
|
||||
|
||||
# 计算每个位置的最大字段大小
|
||||
@@ -755,8 +739,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
first_node = tail_node
|
||||
|
||||
if first_node is None:
|
||||
viperlib.snprintf(fb, 1024, "failed to build field list for %s", class_name)
|
||||
VLogger.error(fb, "RENUM")
|
||||
VLogger.error(f"failed to build field list for {class_name}", "RENUM")
|
||||
return 0
|
||||
|
||||
# 构造命名结构体类型名: "sha1.ClassName" 或 "ClassName"
|
||||
@@ -770,8 +753,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
renum_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(
|
||||
pool, first_node, total_positions, renum_type_name)
|
||||
if renum_ty is None:
|
||||
viperlib.snprintf(fb, 1024, "failed to create type for %s", class_name)
|
||||
VLogger.error(fb, "RENUM")
|
||||
VLogger.error(f"failed to create type for {class_name}", "RENUM")
|
||||
return 0
|
||||
|
||||
# Phase 1b 新注册的 REnum struct_ty 深拷贝到 stdlib(跨文件 reset 存活,
|
||||
@@ -790,8 +772,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.register_struct(
|
||||
pool, class_name, renum_ty, trans.ModuleSha1)
|
||||
if entry is None:
|
||||
viperlib.snprintf(fb, 1024, "failed to register %s", class_name)
|
||||
VLogger.error(fb, "RENUM")
|
||||
VLogger.error(f"failed to register {class_name}", "RENUM")
|
||||
return 0
|
||||
|
||||
# 修复 class_name 指针不匹配:
|
||||
@@ -820,17 +801,13 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
self._register_renum_variants(pool, class_name, cd, variant_count)
|
||||
|
||||
# 注册变体字段名别名已在变体遍历时直接完成(避免 CSizeT→str 转换问题)
|
||||
|
||||
viperlib.snprintf(fb, 1024, "registered %s with %d variants, %d positions",
|
||||
class_name, variant_count, total_positions)
|
||||
VLogger.info(fb, "RENUM")
|
||||
VLogger.info(f"registered {class_name} with {variant_count} variants, {total_positions} positions", "RENUM")
|
||||
return 0
|
||||
def _register_renum_variants(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
class_name: str,
|
||||
cd: ast.ClassDef | t.CPtr,
|
||||
variant_count: int):
|
||||
"""注册 REnum 类的变体名和 tag 值到全局变体表"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if pool is None or class_name is None or cd is None:
|
||||
return
|
||||
if variant_count == 0:
|
||||
@@ -858,26 +835,10 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
string.memset(self.RenumVariantTags, 0, 8 * RENUM_CLASS_MAX * RENUM_VARIANT_PER_CLASS)
|
||||
self.RenumClassCount = 0
|
||||
|
||||
# ============ 临时诊断(0xb0 崩溃定位,定位后移除) ============
|
||||
# lazy init 后 RenumClassNames 必非空;此时若 RCV 异常(null/小值)
|
||||
# 说明字段被越界覆盖或 __init__ 未生效,fail-fast 暴露崩溃现场。
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"[RENUM-DIAG] self=%llu RN=%llu RCV=%llu RVN=%llu RVT=%llu RCount=%d class=%s",
|
||||
t.CUInt64T(self), t.CUInt64T(self.RenumClassNames),
|
||||
t.CUInt64T(self.RenumClassVariantCounts),
|
||||
t.CUInt64T(self.RenumVariantNames),
|
||||
t.CUInt64T(self.RenumVariantTags),
|
||||
self.RenumClassCount, class_name)
|
||||
VLogger.info(fb, "RENUM")
|
||||
rcv_chk: t.CUInt64T = t.CUInt64T(self.RenumClassVariantCounts)
|
||||
if rcv_chk == 0 or rcv_chk < 4096:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"[RENUM-FAIL] RCV=%llu 异常(lazy init 后应为 perm_pool 地址),RenumClassCount=%d class=%s",
|
||||
t.CUInt64T(self.RenumClassVariantCounts),
|
||||
self.RenumClassCount, class_name)
|
||||
VLogger.error(fb, "RENUM")
|
||||
stdlib.exit(1)
|
||||
# ============ 临时诊断结束 ============
|
||||
#rcv_chk: t.CUInt64T = t.CUInt64T(self.RenumClassVariantCounts)
|
||||
#if rcv_chk == 0 or rcv_chk < 4096:
|
||||
# VLogger.error(f"[RENUM-FAIL] RCV={rcv_chk} 异常(lazy init 后应为 perm_pool 地址),RenumClassCount={self.RenumClassCount} class={class_name}", "RENUM")
|
||||
# stdlib.exit(1)
|
||||
|
||||
# 检查是否已注册(避免重复注册)
|
||||
for i in range(self.RenumClassCount):
|
||||
@@ -908,9 +869,7 @@ class ClassGenEnum(ClassGenBase.ClassGenBase):
|
||||
break
|
||||
if tag >= RENUM_VARIANT_PER_CLASS:
|
||||
# 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name)
|
||||
VLogger.error(fb, "RENUM")
|
||||
VLogger.error(f"REnum 变体数超过上限 {RENUM_VARIANT_PER_CLASS}: {class_name}", "RENUM")
|
||||
break
|
||||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||||
if stmt is None:
|
||||
|
||||
@@ -488,9 +488,7 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
# 创建新的 LLVM 函数(使用 SHA1 混淆名)
|
||||
func = llvmlite.create_function(pool, mod, mangled_name, ret_ty)
|
||||
if func is None:
|
||||
fb: str = VLogger.fmtbuffer
|
||||
viperlib.snprintf(fb, 1024, "create_function %s failed", fd.name)
|
||||
VLogger.error(fb, "FUNC")
|
||||
VLogger.error(f"create_function {fd.name} failed", "FUNC")
|
||||
return 0
|
||||
|
||||
# 提取 @c.Attribute 装饰器属性并设置到函数
|
||||
|
||||
@@ -760,7 +760,6 @@ class StructGenMixin:
|
||||
from_imports: from-import 映射("local:module" 格式),供模块限定名
|
||||
的 import 别名(import X as Y → Y.Class)解析为模块 sha1
|
||||
"""
|
||||
fb: str = VLogger.fmtbuffer
|
||||
if class_name is None or field_name is None:
|
||||
return None
|
||||
|
||||
@@ -825,28 +824,16 @@ class StructGenMixin:
|
||||
stdlib.free(mod_buf_q)
|
||||
return fe_q
|
||||
# 类命中但字段未找到:可读化报错(traceback 格式)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 已按模块归属解析"
|
||||
"(ModuleSha1=%s, FieldCount=%d)但字段 '%s' 未找到",
|
||||
class_name, mod_sha1_q, mod_entry_q.FieldCount, field_name)
|
||||
self.Gen.TypeGenErr.fatal_error(node, fb, "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 已按模块归属解析(ModuleSha1={mod_sha1_q}, FieldCount={mod_entry_q.FieldCount})但字段 '{field_name}' 未找到", "AttributeError")
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
# 模块可解析但类未注册:fail-fast(暴露 vpi 注入/注册缺陷,
|
||||
# 不再裸名跨库抓其他模块同名类)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 未找到(模块 '%s' 可解析"
|
||||
" sha1=%s,但无同名注册类;请检查 vpi stub 注入或编译顺序)",
|
||||
class_name, mod_buf_q, mod_sha1_q)
|
||||
self.Gen.TypeGenErr.fatal_error(node, fb, "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 未找到(模块 '{mod_buf_q}' 可解析 sha1={mod_sha1_q},但无同名注册类;请检查 vpi stub 注入或编译顺序)", "AttributeError")
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
# 模块名未登记:fail-fast(不再裸名跨库回退)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 的模块 '%s' 无法解析"
|
||||
"(sha1 映射表未登记,请检查 import 与编译顺序)",
|
||||
class_name, mod_buf_q)
|
||||
self.Gen.TypeGenErr.fatal_error(node, fb, "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 的模块 '{mod_buf_q}' 无法解析(sha1 映射表未登记,请检查 import 与编译顺序)", "AttributeError")
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
stdlib.free(mod_buf_q)
|
||||
@@ -855,10 +842,7 @@ class StructGenMixin:
|
||||
entry = self.find_struct(class_name)
|
||||
if entry is None:
|
||||
# 诊断:目标类未注册(仿 Python traceback 格式,立即终止编译)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)",
|
||||
class_name, self.StructCount)
|
||||
self.Gen.TypeGenErr.fatal_error(node, fb, "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, f"lookup_field_by_class: 类 '{class_name}' 未注册 (struct_count={self.StructCount})", "AttributeError")
|
||||
return None
|
||||
# 先查找字段(诊断/error 之前返回,否则 error 立即退出导致查找永远失败)
|
||||
for fi in range(entry.FieldCount):
|
||||
@@ -909,16 +893,12 @@ class StructGenMixin:
|
||||
string.strcat(fb_flds_lst, ", ")
|
||||
if string.strlen(fb_flds_lst) + string.strlen(fe.Name) < 1024:
|
||||
string.strcat(fb_flds_lst, fe.Name)
|
||||
fb: str = VLogger.fmtbuffer
|
||||
err: str
|
||||
if rn_is_renum_l != 0:
|
||||
# 报错友好化:REnum 类直接说明是"变体字段别名查找失败",并附
|
||||
# entry.Name 与别名槽位结果,一眼可辨"别名未注册"(槽位=-1)
|
||||
# 还是"class_name 指针未统一"(已注册但传错指针查不到)
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 是 REnum 类(FieldCount=%d),"
|
||||
"变体字段 '%s' 别名查找失败(entry.Name='%s',别名槽位=%d,"
|
||||
"请检查该变体字段是否已注册别名,或 class_name 指针是否统一)",
|
||||
class_name, entry.FieldCount, field_name, rn_cls_l, rn_alias_l)
|
||||
err = f"lookup_field_by_class: 类 '{class_name}' 是 REnum 类(FieldCount={entry.FieldCount}),变体字段 '{field_name}' 别名查找失败(entry.Name='{rn_cls_l}',别名槽位={rn_alias_l},请检查该变体字段是否已注册别名,或 class_name 指针是否统一)"
|
||||
else:
|
||||
# 可读化:附 entry.Name/ModuleSha1(跨模块同名定位)+ 注册字段
|
||||
# 列表 + 期望 sha1(调用方)→ 一眼分辨"跨模块同名类误匹配"
|
||||
@@ -932,16 +912,13 @@ class StructGenMixin:
|
||||
fld_lst_txt: str = "(无)"
|
||||
if fb_flds_lst is not None and string.strlen(fb_flds_lst) > 0:
|
||||
fld_lst_txt = fb_flds_lst
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d, "
|
||||
"entry.Name='%s', ModuleSha1=%s, 调用方期望 sha1=%s) "
|
||||
"但字段 '%s' 未找到;注册字段: [%s]。可能原因: 跨模块同名类"
|
||||
"被误匹配 / vpi stub 注入字段不全 / 类定义与访问处不一致",
|
||||
class_name, entry.FieldCount, entry.Name, sha1_txt,
|
||||
want_sha1_txt, field_name, fld_lst_txt)
|
||||
err = f"lookup_field_by_class: 类 '{class_name}' 已注册 (FieldCount={entry.FieldCount}, "\
|
||||
f"entry.Name='{entry.Name}', ModuleSha1={sha1_txt}, 调用方期望 sha1={want_sha1_txt}) "\
|
||||
f"但字段 '{field_name}' 未找到;注册字段: [{fld_lst_txt}]。可能原因: 跨模块同名类"\
|
||||
f"被误匹配 / vpi stub 注入字段不全 / 类定义与访问处不一致"
|
||||
# 仿 Python traceback 格式输出(Traceback 帧 + 文件:行号 + 错误类型),
|
||||
# 立即终止编译(与 VLogger.error 同语义,格式对齐 fatal_error)
|
||||
self.Gen.TypeGenErr.fatal_error(node, fb, "AttributeError")
|
||||
self.Gen.TypeGenErr.fatal_error(node, err, "AttributeError")
|
||||
if fb_flds_lst is not None:
|
||||
stdlib.free(fb_flds_lst)
|
||||
# 诊断:找到结构体但字段未找到
|
||||
|
||||
@@ -210,8 +210,6 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
# 子目录递归失败计数(不静默忽略,汇总处 fail-fast 终止)
|
||||
subdir_failed: int = 0
|
||||
|
||||
fb: str = VLogger.fmtbuffer
|
||||
|
||||
# 构造搜索模式: root_dir/*
|
||||
root_len: t.CSizeT = string.strlen(root_dir)
|
||||
pattern: bytes = stdlib.malloc(root_len + 4)
|
||||
@@ -296,11 +294,9 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
sha1: str = compute_file_sha1(pool, full_path)
|
||||
if sha1 is not None:
|
||||
add_file_entry(result, pool, full_path, rel_path, sha1, inc_dir)
|
||||
viperlib.snprintf(fb, 1024, "扫描: %s -> %s", rel_path, sha1)
|
||||
VLogger.debug(fb, "scan")
|
||||
VLogger.debug(f"扫描: {rel_path} -> {sha1}", "scan")
|
||||
else:
|
||||
viperlib.snprintf(fb, 1024, "SHA1 计算失败: %s", full_path)
|
||||
VLogger.warning(fb, "scan")
|
||||
VLogger.warning(f"SHA1 计算失败: {full_path}", "scan")
|
||||
|
||||
# 继续搜索下一个文件
|
||||
if win32file.FindNextFileA(handle, find_data) == 0:
|
||||
@@ -308,8 +304,7 @@ def scan_directory_recursive(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
win32file.FindClose(handle)
|
||||
if subdir_failed > 0:
|
||||
viperlib.snprintf(fb, 1024, "子目录扫描失败 %d 个", subdir_failed)
|
||||
VLogger.error(fb, "scan")
|
||||
VLogger.error(f"子目录扫描失败 {subdir_failed} 个", "scan")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
@@ -194,19 +194,15 @@ _mbuddy: memhub.MemBuddy | t.CPtr
|
||||
logger: Logger | t.CPtr
|
||||
log: Logger | t.CPtr
|
||||
|
||||
# 全局格式化缓冲区(用于带变量的日志消息,1024 字节)
|
||||
fmtbuffer: str
|
||||
|
||||
def init_logger():
|
||||
"""初始化全局 logger 实例。"""
|
||||
global logger, log, fmtbuffer
|
||||
global logger, log
|
||||
raw: t.CVoid | t.CPtr = _mbuddy.alloc(Logger.__sizeof__())
|
||||
# if raw is None: return None 存疑,如何去管理内存?
|
||||
logger = raw
|
||||
logger.__before_init__()
|
||||
logger.__init__(LogLevel.INFO)
|
||||
log = logger
|
||||
fmtbuffer = _mbuddy.alloc(1024)
|
||||
# if fmtbuffer is None: return None
|
||||
|
||||
|
||||
|
||||
+185
-117
@@ -42,12 +42,12 @@ CODE_PAGE: t.CDefine = 65001
|
||||
# Source code buffer size (1MB)
|
||||
SRC_BUF_SIZE: t.CDefine = 1048576
|
||||
# Version (dev/beta/rc)
|
||||
V_VIPER_VERSION: t.CDefine = "1.0.3-dev.31 2026-07-27 Non-LTS"
|
||||
V_TPV_VERSION: t.CDefine = "0.0.3-dev.428"
|
||||
V_RUNTIME_VERSION: t.CDefine = "0.2.3+19-Non-LTS"
|
||||
V_TPC_COMMIT: t.CDefine = "e376b949c9"
|
||||
V_TPV_COMMIT: t.CDefine = "ab0f37e1a8"
|
||||
V_RUNTIME_COMMIT: t.CDefine = "f087aa88e2"
|
||||
V_VIPER_VERSION: t.CDefine = "1.0.3-dev.30 2026-07-27 Non-LTS"
|
||||
V_TPV_VERSION: t.CDefine = "0.0.3-dev.230"
|
||||
V_RUNTIME_VERSION: t.CDefine = "0.2.2+4-Non-LTS"
|
||||
V_TPC_COMMIT: t.CDefine = "1dc23ffdde"
|
||||
V_TPV_COMMIT: t.CDefine = "f4fee79d4d"
|
||||
V_RUNTIME_COMMIT: t.CDefine = "4ce6095359"
|
||||
V_TARGET: t.CDefine = "x86_64-w64-windows-gnu"
|
||||
V_LLVM: t.CDefine = "22.1.8"
|
||||
|
||||
@@ -88,7 +88,7 @@ def main() -> int:
|
||||
stdio.printf("FAIL: perm_pool init failed\n")
|
||||
return 1
|
||||
|
||||
CompilerFactory.factory = CompilerFactory.CompilerFactory(mb, perm_pool)
|
||||
CompilerFactory.set_factory(CompilerFactory.CompilerFactory(mb, perm_pool))
|
||||
|
||||
# 设置全局 mbuddy 指针(sys 和 argparse 都需要)
|
||||
sys._mbuddy = mb
|
||||
@@ -128,12 +128,9 @@ def main() -> int:
|
||||
# P6: 注入语句/赋值/变量/导入/翻译驱动模块的单例
|
||||
|
||||
# 初始化 VLogger 并打印启动日志
|
||||
VLogger.init_logger()
|
||||
log: VLogger.Logger | t.CPtr = VLogger.logger
|
||||
log: VLogger.Logger | t.CPtr = VLogger.get_logger()
|
||||
if log is None:
|
||||
log.error("TransPyV Failed to parse parameters")
|
||||
fmtbuf: str = VLogger.fmtbuffer
|
||||
fb: str = VLogger.fmtbuffer
|
||||
|
||||
# 初始化命令行参数(Windows: GetCommandLineA, POSIX: /proc/self/cmdline)
|
||||
sys._init_argv()
|
||||
@@ -156,15 +153,14 @@ def main() -> int:
|
||||
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("--show-args", None, argparse.BOOL, 0, None, False, argparse.STORE_TRUE, "Show all parsed arguments")
|
||||
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")
|
||||
|
||||
# 解析命令行参数
|
||||
args: argparse.ParsedArgs | t.CPtr = parser.parse_args(sys._argc, sys._argv)
|
||||
if args is None:
|
||||
log.error("参数解析失败", "argparse")
|
||||
if log is not None:
|
||||
log.error("参数解析失败", "argparse")
|
||||
return 1
|
||||
|
||||
if args.get_bool("help"):
|
||||
@@ -188,40 +184,39 @@ Target: %s
|
||||
return 0
|
||||
|
||||
# 打印解析结果
|
||||
# log.banner("TransPyV 参数解析结果")
|
||||
#if log is not None:
|
||||
# log.banner("TransPyV 参数解析结果")
|
||||
|
||||
# 字符串参数
|
||||
project: str = args.get_str("project")
|
||||
src: str = args.get_str("src")
|
||||
temp: str = args.get_str("temp")
|
||||
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: bool = args.get_bool("clean")
|
||||
show_args: bool = args.get_bool("show-args")
|
||||
if show_args:
|
||||
if project is not None: stdio.printf(" --project: %s\n", project)
|
||||
else: stdio.printf(" --project: (未指定)\n")
|
||||
if src is not None: stdio.printf(" --src: %s\n", src)
|
||||
else: stdio.printf(" --src: (未指定)\n")
|
||||
if temp is not None: stdio.printf(" --temp: %s\n", temp)
|
||||
else: stdio.printf(" --temp: (未指定)\n")
|
||||
if output is not None: stdio.printf(" --output: %s\n", output)
|
||||
else: stdio.printf(" --output: (未指定)\n")
|
||||
if phase is not None: stdio.printf(" --phase: %s\n", phase)
|
||||
else: stdio.printf(" --phase: (未指定,默认 all)\n")
|
||||
if cc is not None: stdio.printf(" --cc: %s\n", cc)
|
||||
else: stdio.printf(" --cc: (未指定)\n")
|
||||
if _gb_clean: stdio.printf(" --clean: True\n")
|
||||
else: stdio.printf(" --clean: False\n")
|
||||
if args.get_bool("run"): stdio.printf(" --run: True\n")
|
||||
else: stdio.printf(" --run: False\n")
|
||||
if args.get_bool("rebuild-includes"): stdio.printf(" --rebuild-includes: True\n")
|
||||
else: stdio.printf(" --rebuild-includes: False\n")
|
||||
if args.get_bool("clear-cache"): stdio.printf(" --clear-cache: True\n")
|
||||
else: stdio.printf(" --clear-cache: False\n")
|
||||
stdio.printf("参数解析完成。\n\n")
|
||||
project: str = args.get_str("project")
|
||||
src: str = args.get_str("src")
|
||||
temp: str = args.get_str("temp")
|
||||
output: str = args.get_str("output")
|
||||
phase: str = args.get_str("phase")
|
||||
cc: str = args.get_str("cc")
|
||||
_gb_clean: INT = args.get_bool("clean")
|
||||
#if project is not None: stdio.printf(" --project: %s\n", project)
|
||||
#else: stdio.printf(" --project: (未指定)\n")
|
||||
#if src is not None: stdio.printf(" --src: %s\n", src)
|
||||
#else: stdio.printf(" --src: (未指定)\n")
|
||||
#if temp is not None: stdio.printf(" --temp: %s\n", temp)
|
||||
#else: stdio.printf(" --temp: (未指定)\n")
|
||||
#if output is not None: stdio.printf(" --output: %s\n", output)
|
||||
#else: stdio.printf(" --output: (未指定)\n")
|
||||
#if phase is not None: stdio.printf(" --phase: %s\n", phase)
|
||||
#else: stdio.printf(" --phase: (未指定,默认 all)\n")
|
||||
#if cc is not None: stdio.printf(" --cc: %s\n", cc)
|
||||
#else: stdio.printf(" --cc: (未指定)\n")
|
||||
#if _gb_clean: stdio.printf(" --clean: True\n")
|
||||
#else: stdio.printf(" --clean: False\n")
|
||||
#if args.get_bool("run"): stdio.printf(" --run: True\n")
|
||||
#else: stdio.printf(" --run: False\n")
|
||||
#if args.get_bool("rebuild-includes"): stdio.printf(" --rebuild-includes: True\n")
|
||||
#else: stdio.printf(" --rebuild-includes: False\n")
|
||||
#if args.get_bool("clear-cache"): stdio.printf(" --clear-cache: True\n")
|
||||
#else: stdio.printf(" --clear-cache: False\n")
|
||||
|
||||
#stdio.printf("\n参数解析完成。\n")
|
||||
|
||||
# ASan 模式
|
||||
# includes 缓存用独立目录 .binary_asan 隔离 asan 插桩 obj,避免与非 asan obj 混链
|
||||
@@ -229,13 +224,17 @@ Target: %s
|
||||
if args.get_bool("asan"):
|
||||
BuildPipeline._asan_mode = True
|
||||
Config._inc_bin_suffix = ".binary_asan"
|
||||
log.info("ASan 模式已启用(opt -passes=asan + libclang_rt)", "asan")
|
||||
if log is not None:
|
||||
log.info("ASan 模式已启用(opt -passes=asan + libclang_rt)", "asan")
|
||||
# ASan 模式清理 asan includes 缓存(强制重建 asan 插桩 obj)
|
||||
mf_inc_bin_asan: str = Config.get_includes_binary_dir()
|
||||
if mf_inc_bin_asan is not None:
|
||||
n_asan: int = Utils.CleanDir(mf_inc_bin_asan)
|
||||
viperlib.snprintf(fb, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan)
|
||||
log.info(f"ASan 模式清理 includes 缓存: {n_asan} 个文件(将重建 asan obj)", "asan")
|
||||
if log is not None:
|
||||
fb_asan: str = VLogger.fmt_buf()
|
||||
if fb_asan is not None:
|
||||
viperlib.snprintf(fb_asan, 1024, "ASan 模式清理 includes 缓存: %d 个文件(将重建 asan obj)", n_asan)
|
||||
log.info(fb_asan, "asan")
|
||||
else:
|
||||
BuildPipeline._asan_mode = False
|
||||
Config._inc_bin_suffix = ".binary"
|
||||
@@ -246,25 +245,34 @@ Target: %s
|
||||
p2c: str = args.get_str("phase2command")
|
||||
if p2c is not None:
|
||||
BuildPipeline._phase2_cmd_path = p2c
|
||||
viperlib.snprintf(fmtbuf, 1024, "--phase2command: 不执行 llc/链接,命令写入 %s", p2c)
|
||||
log.info(fmtbuf, "phase2cmd")
|
||||
if log is not None:
|
||||
fb_p2c: str = VLogger.fmt_buf()
|
||||
if fb_p2c is not None:
|
||||
viperlib.snprintf(fb_p2c, 1024, "--phase2command: 不执行 llc/链接,命令写入 %s", p2c)
|
||||
log.info(fb_p2c, "phase2cmd")
|
||||
|
||||
# --nowarn-register:抑制"外部函数返回类型未登记"类 WARN 输出
|
||||
if args.get_bool("nowarn-register"):
|
||||
VLogger._nowarn_register = 1
|
||||
log.info("--nowarn-register 已启用:抑制注册类 WARN 输出", "vlogger")
|
||||
VLogger.set_nowarn_register(1)
|
||||
if log is not None:
|
||||
log.info("--nowarn-register 已启用:抑制注册类 WARN 输出", "vlogger")
|
||||
|
||||
# 加载 project.vpj 配置
|
||||
proj_loaded: int = 0
|
||||
proj_path: str = project
|
||||
if proj_path is not None:
|
||||
log.banner("工程配置")
|
||||
if log is not None:
|
||||
log.banner("工程配置")
|
||||
cfg_ret: int = Config.Load_project_config(proj_path)
|
||||
if cfg_ret == 0:
|
||||
proj_loaded = 1
|
||||
else:
|
||||
viperlib.snprintf(fmtbuf, 256, "无法加载 project.vpj: %s", proj_path)
|
||||
log.warning(fmtbuf, "config")
|
||||
if log is not None:
|
||||
warn_buf: str = stdlib.malloc(256)
|
||||
if warn_buf is not None:
|
||||
viperlib.snprintf(warn_buf, 256, "无法加载 project.vpj: %s", proj_path)
|
||||
log.warning(warn_buf, "config")
|
||||
stdlib.free(warn_buf)
|
||||
else:
|
||||
# 尝试默认路径 project.vpj(当前目录和上级目录)
|
||||
proj_path = "project.vpj"
|
||||
@@ -290,50 +298,63 @@ 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()
|
||||
|
||||
# === --clean: 清理 temp、output 和 includes.binary 目录 ===
|
||||
if _gb_clean:
|
||||
log.info("清理临时目录...", "clean")
|
||||
if log is not None:
|
||||
log.info("清理临时目录...", "clean")
|
||||
if Config.TempDir is not None:
|
||||
n: int = Utils.CleanDir(Config.TempDir)
|
||||
viperlib.snprintf(fmtbuf, 1024, "%s: 删除 %d 个文件", Config.TempDir, n)
|
||||
log.info(fmtbuf, "clean")
|
||||
if log is not None:
|
||||
fb: str = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024, "%s: 删除 %d 个文件", Config.TempDir, n)
|
||||
log.info(fb, "clean")
|
||||
if Config.OutputDir is not None:
|
||||
n2: int = Utils.CleanDir(Config.OutputDir)
|
||||
viperlib.snprintf(fmtbuf, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2)
|
||||
log.info(fmtbuf, "clean")
|
||||
if log is not None:
|
||||
fb2: str = VLogger.fmt_buf()
|
||||
if fb2 is not None:
|
||||
viperlib.snprintf(fb2, 1024, "%s: 删除 %d 个文件", Config.OutputDir, n2)
|
||||
log.info(fb2, "clean")
|
||||
# 清理 includes.binary 目录(旧 .obj 文件会导致跳过重新编译)
|
||||
mf_inc_bin_clean: str = Config.get_includes_binary_dir()
|
||||
if mf_inc_bin_clean is not None:
|
||||
n3: int = Utils.CleanDir(mf_inc_bin_clean)
|
||||
viperlib.snprintf(fmtbuf, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3)
|
||||
log.info(fmtbuf, "clean")
|
||||
if log is not None:
|
||||
fb3: str = VLogger.fmt_buf()
|
||||
if fb3 is not None:
|
||||
viperlib.snprintf(fb3, 1024, "%s: 删除 %d 个文件", mf_inc_bin_clean, n3)
|
||||
log.info(fb3, "clean")
|
||||
|
||||
# === --rebuild-includes: 删除 includes.binary 预编译缓存 ===
|
||||
# 强制下次编译时重新编译所有 includes(不清 temp/output)
|
||||
if args.get_bool("rebuild-includes"):
|
||||
log.info("重建 includes 缓存...", "rebuild-includes")
|
||||
if log is not None:
|
||||
log.info("重建 includes 缓存...", "rebuild-includes")
|
||||
mf_inc_bin_rb: str = Config.get_includes_binary_dir()
|
||||
if mf_inc_bin_rb is not None:
|
||||
n_rb: int = Utils.CleanDir(mf_inc_bin_rb)
|
||||
viperlib.snprintf(fmtbuf, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb)
|
||||
log.info(fmtbuf, "rebuild-includes")
|
||||
if log is not None:
|
||||
fb_rb: str = VLogger.fmt_buf()
|
||||
if fb_rb is not None:
|
||||
viperlib.snprintf(fb_rb, 1024, "%s: 删除 %d 个文件(includes 将重新编译)", mf_inc_bin_rb, n_rb)
|
||||
log.info(fb_rb, "rebuild-includes")
|
||||
|
||||
# === --clear-cache: 清除 temp 目录缓存(.vpi/.stub.ll/.text.ll) ===
|
||||
# 强制下次 Phase1 重新生成 stub(不清 output/includes.binary)
|
||||
if args.get_bool("clear-cache"):
|
||||
log.info("清除 temp 缓存...", "clear-cache")
|
||||
if log is not None:
|
||||
log.info("清除 temp 缓存...", "clear-cache")
|
||||
if Config.TempDir is not None:
|
||||
n_cc: int = Utils.CleanDir(Config.TempDir)
|
||||
viperlib.snprintf(fmtbuf, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc)
|
||||
log.info(fmtbuf, "clear-cache")
|
||||
if log is not None:
|
||||
fb_cc: str = VLogger.fmt_buf()
|
||||
if fb_cc is not None:
|
||||
viperlib.snprintf(fb_cc, 1024, "%s: 删除 %d 个文件(.vpi/.stub.ll 缓存)", Config.TempDir, n_cc)
|
||||
log.info(fb_cc, "clear-cache")
|
||||
|
||||
# === --phase 参数控制 ===
|
||||
# phase=1: 仅 stub 分离(生成 .stub.ll/.text.ll),不编译
|
||||
@@ -349,8 +370,11 @@ Target: %s
|
||||
do_phase1 = 1
|
||||
if string.strcmp(phase_mode, "2") == 0 or string.strcmp(phase_mode, "all") == 0:
|
||||
do_phase2 = 1
|
||||
viperlib.snprintf(fmtbuf, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2)
|
||||
log.info(fmtbuf, "phase")
|
||||
if log is not None:
|
||||
fb3: str = VLogger.fmt_buf()
|
||||
if fb3 is not None:
|
||||
viperlib.snprintf(fb3, 1024, "模式: %s (phase1=%d phase2=%d)", phase_mode, do_phase1, do_phase2)
|
||||
log.info(fb3, "phase")
|
||||
|
||||
# === Phase1: 扫描 includes(按需翻译)===
|
||||
# 对 includes 目录中每个 .vp/.py 文件,若 stub 不存在则翻译并分离 stub
|
||||
@@ -363,7 +387,8 @@ Target: %s
|
||||
return 1
|
||||
# 如果仅 Phase1(不执行 Phase2),直接退出
|
||||
if do_phase2 == 0:
|
||||
log.info("Phase1 完成,退出", "phase")
|
||||
if log is not None:
|
||||
log.info("Phase1 完成,退出", "phase")
|
||||
return 0
|
||||
|
||||
# AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树
|
||||
@@ -374,20 +399,21 @@ Target: %s
|
||||
# 未初始化的 Config 字段可能为垃圾指针 → is not None 检查通过 →
|
||||
# 用非法路径 → 崩溃且 ASan 堆栈来不及输出)
|
||||
if proj_loaded == 0 and src_path is None:
|
||||
log.error("未找到 project.vpj(当前目录/上级目录)且未指定 --src,无法构建", "config")
|
||||
if log is not None:
|
||||
log.error("未找到 project.vpj(当前目录/上级目录)且未指定 --src,无法构建", "config")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
|
||||
# === 多文件项目模式 ===
|
||||
# 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .vp/.py 文件编译
|
||||
if src_path is None and project is not None and Config.SourceDir is not None:
|
||||
mf_temp: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
mf_output: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||
mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic"
|
||||
mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||
mf_temp: str = Config.TempDir if Config.TempDir is not None else "."
|
||||
mf_output: str = Config.OutputDir if Config.OutputDir is not None else "."
|
||||
mf_cc: str = Config.CompilerCmd if Config.CompilerCmd is not None else "llc"
|
||||
mf_cc_flags: str = Config.CompilerFlags if Config.CompilerFlags is not None else "-filetype=obj -relocation-model=pic"
|
||||
mf_linker: str = Config.LinkerCmd if Config.LinkerCmd is not None else "clang++"
|
||||
mf_linker_flags: str = Config.LinkerFlags if Config.LinkerFlags is not None else "-lmsvcrt -lucrt -lpthread -lmingwex -lkernel32 -lgcc -Wl,--allow-multiple-definition"
|
||||
mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe"
|
||||
mf_linker_out: str = Config.LinkerOutput if Config.LinkerOutput is not None else "app.exe"
|
||||
mf_includes_bin: str = Config.get_includes_binary_dir()
|
||||
|
||||
mf_ret: int = Phase2.RunMultiFileProject(
|
||||
@@ -395,34 +421,49 @@ Target: %s
|
||||
mf_cc, mf_cc_flags, mf_linker, mf_linker_flags, mf_linker_out,
|
||||
mf_includes_bin, Config.IncludesDirs, do_phase1, do_phase2, log, args)
|
||||
argparse.release(args)
|
||||
log.success("TransPyV 完成")
|
||||
if log is not None:
|
||||
log.success("TransPyV 完成")
|
||||
return mf_ret
|
||||
|
||||
# === 单文件模式:--src 指定时使用指定文件;--project 但无 SourceDir 时回退 ===
|
||||
if src_path is None and project is not None:
|
||||
if Config.SourceDir is not None:
|
||||
# 构造入口路径: SourceDir/main.vp(不再做 vp -> py 后缀识别回退)
|
||||
# 构造入口路径: 优先 SourceDir/main.vp,回退 SourceDir/main.py
|
||||
sd_len: t.CSizeT = string.strlen(Config.SourceDir)
|
||||
path_buf: bytes = stdlib.malloc(sd_len + 16)
|
||||
if path_buf is not None:
|
||||
# 优先尝试 main.vp
|
||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.vp", Config.SourceDir)
|
||||
ef: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||||
if ef.closed:
|
||||
# .vp 不存在,回退 main.py
|
||||
viperlib.snprintf(path_buf, sd_len + 16, "%s/main.py", Config.SourceDir)
|
||||
else:
|
||||
ef.close()
|
||||
src_path = path_buf
|
||||
viperlib.snprintf(fmtbuf, 1024, "入口文件: %s", src_path)
|
||||
log.info(fmtbuf, "project")
|
||||
|
||||
if log is not None:
|
||||
fb4: str = VLogger.fmt_buf()
|
||||
if fb4 is not None:
|
||||
viperlib.snprintf(fb4, 1024, "入口文件: %s", src_path)
|
||||
log.info(fb4, "project")
|
||||
if src_path is not None:
|
||||
log.banner("AST 解析")
|
||||
if log is not None:
|
||||
log.banner("AST 解析")
|
||||
# 打开文件
|
||||
f: fileio.File | t.CPtr = fileio.File(src_path, fileio.MODE.R)
|
||||
if f.closed:
|
||||
viperlib.snprintf(fmtbuf, 1024, "无法打开文件: %s", src_path)
|
||||
log.error(fmtbuf, "fileio")
|
||||
if log is not None:
|
||||
fb5: str = VLogger.fmt_buf()
|
||||
if fb5 is not None:
|
||||
viperlib.snprintf(fb5, 1024, "无法打开文件: %s", src_path)
|
||||
log.error(fb5, "fileio")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 分配源代码缓冲区
|
||||
src_buf: bytes = stdlib.malloc(SRC_BUF_SIZE)
|
||||
if src_buf is None:
|
||||
log.error("malloc for src_buf failed", "memhub")
|
||||
if log is not None:
|
||||
log.error("malloc for src_buf failed", "memhub")
|
||||
f.close()
|
||||
argparse.release(args)
|
||||
return 1
|
||||
@@ -430,8 +471,11 @@ Target: %s
|
||||
bytes_read: LONG = f.read_all(src_buf, SRC_BUF_SIZE)
|
||||
f.close()
|
||||
if bytes_read < 0:
|
||||
viperlib.snprintf(fmtbuf, 1024, "读取文件失败 (错误码: %d)", bytes_read)
|
||||
log.error(fmtbuf, "fileio")
|
||||
if log is not None:
|
||||
fb6: str = VLogger.fmt_buf()
|
||||
if fb6 is not None:
|
||||
viperlib.snprintf(fb6, 1024, "读取文件失败 (错误码: %d)", bytes_read)
|
||||
log.error(fb6, "fileio")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
# 添加 null 终止符,确保 strlen 和 SHA1 计算正确
|
||||
@@ -439,9 +483,12 @@ Target: %s
|
||||
src_buf[bytes_read] = 0
|
||||
else:
|
||||
src_buf[SRC_BUF_SIZE - 1] = 0
|
||||
if log is not None:
|
||||
log.info("文件读取完成", "fileio")
|
||||
viperlib.snprintf(fmtbuf, 1024, "读取 %d 字节", bytes_read)
|
||||
log.info(fmtbuf, "fileio")
|
||||
fb7: str = VLogger.fmt_buf()
|
||||
if fb7 is not None:
|
||||
viperlib.snprintf(fb7, 1024, "读取 %d 字节", bytes_read)
|
||||
log.info(fb7, "fileio")
|
||||
# 解析 AST(拆分为词法+语法两阶段,便于调试)
|
||||
ast._init_tables(mb)
|
||||
lx: ast.Lexer | t.CPtr = ast.new_lexer(mb)
|
||||
@@ -449,12 +496,14 @@ Target: %s
|
||||
tokens: ast.Token | t.CPtr = ast.tokenize(lx)
|
||||
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
|
||||
if tree is None:
|
||||
log.error("AST 解析失败", "ast")
|
||||
if log is not None:
|
||||
log.error("AST 解析失败", "ast")
|
||||
argparse.release(args)
|
||||
return 1
|
||||
|
||||
# === 翻译 AST → LLVM IR ===
|
||||
log.banner("LLVM IR 翻译")
|
||||
if log is not None:
|
||||
log.banner("LLVM IR 翻译")
|
||||
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
|
||||
result: int = tr.translate(tree)
|
||||
if result == 0:
|
||||
@@ -464,7 +513,8 @@ Target: %s
|
||||
tr.dump_ir(ir_buf, IR_BUF_SIZE, llvmlite.OUTPUT_FULL)
|
||||
|
||||
# === 编译管线: .ll → .obj → .exe ===
|
||||
log.banner("编译管线")
|
||||
if log is not None:
|
||||
log.banner("编译管线")
|
||||
|
||||
# module_name 用源代码内容的 SHA1(前 16 字符),与 Projectrans.py 一致
|
||||
# output_name 从文件名推导(如 test.vp -> test.exe),保持可读性
|
||||
@@ -532,7 +582,8 @@ Target: %s
|
||||
|
||||
# === Phase1 stub 分离:使用 OUTPUT_STUB/TEXT 模式分别生成 stub.ll 和 text.ll ===
|
||||
if do_phase1 != 0 and temp_dir is not None and module_name is not None:
|
||||
log.banner("stub 分离")
|
||||
if log is not None:
|
||||
log.banner("stub 分离")
|
||||
SF_IR_SIZE: t.CSizeT = 262144
|
||||
td_len_sf: t.CSizeT = string.strlen(temp_dir)
|
||||
# 保存 stub.ll
|
||||
@@ -564,7 +615,8 @@ Target: %s
|
||||
|
||||
# phase=1 模式:仅生成 stub,不执行编译
|
||||
if do_phase2 == 0:
|
||||
log.success("Phase1 完成(仅 stub 分离,跳过编译)")
|
||||
if log is not None:
|
||||
log.success("Phase1 完成(仅 stub 分离,跳过编译)")
|
||||
argparse.release(args)
|
||||
return 0
|
||||
|
||||
@@ -572,7 +624,8 @@ Target: %s
|
||||
final_ir: bytes = ir_buf
|
||||
final_ir_len: t.CSizeT = ir_len
|
||||
if temp_dir is not None and module_name is not None:
|
||||
log.banner("IR 组合")
|
||||
if log is not None:
|
||||
log.banner("IR 组合")
|
||||
SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB
|
||||
combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE)
|
||||
if combined_buf is not None:
|
||||
@@ -590,32 +643,47 @@ Target: %s
|
||||
includes_binary_dir
|
||||
)
|
||||
if br is not None and br.Success == 1:
|
||||
log.success("编译管线完成")
|
||||
viperlib.snprintf(fmtbuf, 1024, "输出: %s/%s", output_dir, linker_output)
|
||||
log.info(fmtbuf)
|
||||
if log is not None:
|
||||
log.success("编译管线完成")
|
||||
fb8: str = VLogger.fmt_buf()
|
||||
if fb8 is not None:
|
||||
viperlib.snprintf(fb8, 1024, "输出: %s/%s", output_dir, linker_output)
|
||||
log.info(fb8)
|
||||
# --run 模式:执行生成的可执行文件
|
||||
# phase2command 模式:exe 尚未链接(命令在 bat 中),跳过 --run
|
||||
if args.get_bool("run") and BuildPipeline._phase2_cmd_path is None:
|
||||
exe_path: bytes = stdlib.malloc(string.strlen(output_dir) + string.strlen(linker_output) + 2)
|
||||
if exe_path is not None:
|
||||
viperlib.snprintf(exe_path, 256, "%s/%s", output_dir, linker_output)
|
||||
viperlib.snprintf(fmtbuf, 1024, "执行: %s", exe_path)
|
||||
log.info(fmtbuf)
|
||||
if log is not None:
|
||||
fb9: str = VLogger.fmt_buf()
|
||||
if fb9 is not None:
|
||||
viperlib.snprintf(fb9, 1024, "执行: %s", exe_path)
|
||||
log.info(fb9, "run")
|
||||
r: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
|
||||
if r is not None:
|
||||
viperlib.snprintf(fmtbuf, 1024, "退出码: %d", r.returncode)
|
||||
log.info(fmtbuf)
|
||||
if log is not None:
|
||||
fb10: str = VLogger.fmt_buf()
|
||||
if fb10 is not None:
|
||||
viperlib.snprintf(fb10, 1024, "退出码: %d", r.returncode)
|
||||
log.info(fb10, "run")
|
||||
else:
|
||||
log.error("编译管线失败", "pipeline")
|
||||
if br is not None and br.ErrorMsg is not None:
|
||||
viperlib.snprintf(fmtbuf, 1024, "编译管线失败: %s", br.ErrorMsg)
|
||||
log.error(fmtbuf, "FATAL")
|
||||
if log is not None:
|
||||
log.error("编译管线失败", "pipeline")
|
||||
if br is not None and br.ErrorMsg is not None:
|
||||
fb11: str = VLogger.fmt_buf()
|
||||
if fb11 is not None:
|
||||
viperlib.snprintf(fb11, 1024, "编译管线失败: %s", br.ErrorMsg)
|
||||
log.error(fb11, "FATAL")
|
||||
sys.exit(1)
|
||||
else:
|
||||
log.error("malloc for IR buffer failed", "memhub")
|
||||
if log is not None:
|
||||
log.error("malloc for IR buffer failed", "memhub")
|
||||
else:
|
||||
log.error("翻译失败", "translator")
|
||||
if log is not None:
|
||||
log.error("翻译失败", "translator")
|
||||
|
||||
argparse.release(args)
|
||||
log.success("TransPyV 完成")
|
||||
if log is not None:
|
||||
log.success("TransPyV 完成")
|
||||
return 0
|
||||
Reference in new issue
Block a user