修正了一些错误

This commit is contained in:
2026-07-26 20:32:26 +08:00
parent ca7c2120b8
commit 1837339f69
203 changed files with 374300 additions and 2638 deletions

View File

@@ -17,6 +17,7 @@ import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesTranslator as HandlesTranslator
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.BuildPipeline as BuildPipeline
import lib.core.StubMerger as StubMerger
import lib.Projectrans.Utils as Utils
@@ -138,7 +139,10 @@ def _ScanDirForPyFiles(mb: memhub.MemBuddy | t.CPtr,
ent.Path = full_path
ent.Sha1 = sha1_val
file_count += 1
stdio.printf("[project] %s (sha1=%s)\n", fname, sha1_val)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%s (sha1=%s)", fname, sha1_val)
VLogger.info(fb, "project")
stdlib.free(sbuf)
# full_path 不释放ent.Path 引用它
@@ -165,10 +169,16 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
Returns: 0 成功,非 0 失败
"""
if source_dir is None:
stdio.printf("[project] source_dir 为空\n")
VLogger.error("source_dir 为空", "project")
return 1
stdio.printf("[project] 多文件项目编译: %s\n", source_dir)
stdio.printf("[DBG] RunMultiFileProject enter src=%s\n", source_dir)
stdio.fflush(0)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "多文件项目编译: %s", source_dir)
VLogger.info(fb, "project")
# === 1. 递归扫描 source_dir 下的 .py 文件(包括子目录)===
entry_size: t.CSizeT = SrcFileEntry.__sizeof__()
@@ -178,7 +188,12 @@ 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)
stdio.printf("[project] 共 %d 个源文件\n", file_count)
stdio.printf("[DBG] scan done file_count=%d\n", file_count)
stdio.fflush(0)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "%d 个源文件", file_count)
VLogger.info(fb, "project")
if file_count == 0:
stdlib.free(entries)
@@ -191,34 +206,47 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
BuildPipeline.ensure_dir(temp_dir)
BuildPipeline.ensure_dir(output_dir)
# 追加 App 源文件 SHA1 到 _sha1_map.txt供日志转存和符号查找使用
# 格式: {sha1}:App/{filename}\n (与 includes 条目格式对应
# 追加 App 源文件 SHA1 到 _sha1_map.txt人类可读输出,程序内部不读取此文件
# 格式: {sha1}:{rel_path}\n (保留目录结构,如 lib/core/VLogger.py
# 同步追加到内存存储器AppendToSha1MapStore供跨模块 CDefine 查找)
td_len_am: t.CSizeT = string.strlen(temp_dir)
src_dir_len_am: t.CSizeT = string.strlen(source_dir)
map_path_am: bytes = stdlib.malloc(td_len_am + 32)
if map_path_am is not None:
viperlib.snprintf(map_path_am, td_len_am + 32, "%s/_sha1_map.txt", temp_dir)
mf: fileio.File | t.CPtr = fileio.File(map_path_am, fileio.MODE.A)
line_am: bytes = stdlib.malloc(512)
# 先遍历一次填充内存存储器(不依赖文件 I/O再写入 _sha1_map.txt
app_filled: int = 0
for i in range(file_count):
ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr))
if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None:
continue
# 计算相对路径(去除 source_dir 前缀,保留目录结构)
p_str: str = ent_am.Path
p_len: t.CSizeT = string.strlen(p_str)
rel_path_am: str = p_str
if p_len > src_dir_len_am + 1:
if string.strncmp(p_str, source_dir, src_dir_len_am) == 0:
rel_path_am = p_str + src_dir_len_am + 1
# 同步追加到内存存储器(供跨模块 CDefine 查找)
# rel_path_am 格式如 "lib/core/StubMerger.py",与 _sha1_map.txt 一致
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) == 0:
app_filled += 1
# 写入 _sha1_map.txt人类可读输出
if not mf.closed and line_am is not None:
viperlib.snprintf(line_am, 512, "%s:%s\n", ent_am.Sha1, rel_path_am)
ll_am: t.CSizeT = string.strlen(line_am)
mf.write(line_am, ll_am)
if line_am is not None:
stdlib.free(line_am)
if not mf.closed:
line_am: bytes = stdlib.malloc(512)
if line_am is not None:
for i in range(file_count):
ea_am: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent_am: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_am, t.CPtr))
if ent_am is None or ent_am.Path is None or ent_am.Sha1 is None:
continue
# 从路径提取文件名(最后一个 / 或 \\ 之后的部分)
p_str: str = ent_am.Path
p_len: t.CSizeT = string.strlen(p_str)
f_start: t.CSizeT = 0
for j in range(p_len):
if p_str[j] == '/' or p_str[j] == '\\':
f_start = j + 1
viperlib.snprintf(line_am, 512, "%s:App/%s\n", ent_am.Sha1, p_str + f_start)
ll_am: t.CSizeT = string.strlen(line_am)
mf.write(line_am, ll_am)
stdlib.free(line_am)
mf.close()
stdio.printf("[project] 已追加 %d 个 App 文件到 _sha1_map.txt\n", file_count)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "已追加 %d 个 App 文件到 _sha1_map.txt 和内存存储器", app_filled)
VLogger.info(fb, "project")
stdlib.free(map_path_am)
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
@@ -231,6 +259,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# 追加用户源文件的 (模块名, SHA1) 到全局映射
# 使跨模块方法调用能通过 from_imports + _lookup_module_sha1 找到正确的 SHA1
if pb_sha1_arr is not None and pb_mod_arr is not None:
src_dir_len_us: t.CSizeT = string.strlen(source_dir)
for i in range(file_count):
ea_us: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent_us: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_us, t.CPtr))
@@ -238,24 +267,26 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
continue
if pb_inc_count >= StubMerger.MAX_INCLUDES:
break
# 从路径提取模块名(文件名去掉 .py 后缀
# 计算相对路径并转换为点分模块名(保留完整包路径
path_str: str = ent_us.Path
path_len: t.CSizeT = string.strlen(path_str)
fname_start: t.CSizeT = 0
for j in range(path_len):
if path_str[j] == '/' or path_str[j] == '\\':
fname_start = j + 1
mod_len: t.CSizeT = path_len - fname_start
if mod_len < 4:
path_len_us: t.CSizeT = string.strlen(path_str)
rel_path_us: str = path_str
if path_len_us > src_dir_len_us + 1:
if string.strncmp(path_str, source_dir, src_dir_len_us) == 0:
rel_path_us = path_str + src_dir_len_us + 1
# 使用 _PathToModuleName 转换为点分模块名(处理 __init__.py → 包名)
mod_name_us: str = StubMerger._PathToModuleName(rel_path_us)
if mod_name_us is None:
continue
mod_len -= 3
if mod_len >= 64:
mod_len = 63
# 写入模块名
mod_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 64
for k in range(mod_len):
pb_mod_arr[mod_idx + k] = path_str[fname_start + k]
pb_mod_arr[mod_idx + mod_len] = '\0'
mn_len_us: t.CSizeT = string.strlen(mod_name_us)
if mn_len_us >= 64:
string.strncpy(pb_mod_arr + mod_idx, mod_name_us, 63)
pb_mod_arr[mod_idx + 63] = '\0'
else:
string.strcpy(pb_mod_arr + mod_idx, mod_name_us)
stdlib.free(mod_name_us)
# 写入 SHA1
sha1_idx: t.CSizeT = t.CSizeT(pb_inc_count) * 17
string.strcpy(pb_sha1_arr + sha1_idx, ent_us.Sha1)
@@ -265,36 +296,60 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# === 2. Phase A: 为每个文件生成 stub + text ===
if do_phase1 != 0:
stdio.printf("[DBG] before Phase A\n")
stdio.fflush(0)
if log is not None:
log.banner("Phase A: 生成 stub + text")
# === Phase A-pre: 预注册所有源文件的 struct/enum/union ===
# 解决循环引用问题circ_a 翻译时需要知道 circ_b.ClassB 的 struct 定义
# 仅注册 struct/enum/uniondeclare_only=1不翻译方法体
stdio.printf("[Phase A-pre] 预注册 struct/enum/union...\n")
# 多遍扫描:解决跨文件继承的字母序问题(如 HandlesAnnAssign.py 在 HandlesBase.py 之前,
# AnnAssignHandle 继承 Mixin 时 Mixin 未注册)。每遍注册新类后,下一遍子类可继承。
VLogger.info("预注册 struct/enum/union...", "PhaseA")
src_dir_len_pre: t.CSizeT = string.strlen(source_dir)
for i in range(file_count):
ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr))
if ent_pre is None or ent_pre.Path is None:
continue
pkg_pre: str = None
if string.strlen(ent_pre.Path) > src_dir_len_pre + 1:
rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1
pkg_pre = HandlesImports.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:
stdio.printf("[Phase A-pre] 警告: 预注册失败: %s\n", ent_pre.Path)
stdio.printf("[Phase A-pre] 预注册完成\n")
PHASE_A_PRE_MAX_PASSES: t.CInt = 3
for pass_i in range(PHASE_A_PRE_MAX_PASSES):
struct_count_before: int = HandlesStruct.get_struct_count()
stdio.printf("[DBG] PhaseA-pre pass=%d struct_count_before=%d\n", pass_i, struct_count_before)
stdio.fflush(0)
for i in range(file_count):
ea_pre: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent_pre: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pre, t.CPtr))
if ent_pre is None or ent_pre.Path is None:
continue
pkg_pre: str = None
if string.strlen(ent_pre.Path) > src_dir_len_pre + 1:
rel_path_pre: str = ent_pre.Path + src_dir_len_pre + 1
pkg_pre = HandlesImports.compute_package_from_relpath(mb, rel_path_pre)
stdio.printf("[DBG] PhaseA-pre pass=%d file=%s\n", pass_i, ent_pre.Path)
stdio.fflush(0)
tr_pre: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent_pre.Path, ent_pre.Sha1, pkg_pre, 1)
if tr_pre is None:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "预注册失败: %s", ent_pre.Path)
VLogger.warning(fb, "PhaseA")
struct_count_after: int = HandlesStruct.get_struct_count()
stdio.printf("[DBG] PhaseA-pre pass=%d done struct_count_after=%d\n", pass_i, struct_count_after)
stdio.fflush(0)
# 收敛检查:本遍没有新结构体注册 → 所有类已注册
if struct_count_after == struct_count_before:
break
VLogger.info("预注册完成", "PhaseA")
PHASE_A_IR_SIZE: t.CSizeT = 262144
PHASE_A_IR_SIZE: t.CSizeT = 1048576
td_len_pa: t.CSizeT = string.strlen(temp_dir)
stdio.printf("[DBG] PhaseA full-translate start\n")
stdio.fflush(0)
for i in range(file_count):
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
if ent is None or ent.Path is None:
continue
stdio.printf("[DBG] PhaseA file=%s\n", ent.Path)
stdio.fflush(0)
# 计算源文件的包名(相对 source_dir 的目录部分)
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
@@ -352,12 +407,14 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(deps_path_a)
if do_phase2 == 0:
stdio.printf("[project] Phase A 完成(仅 stub 生成)\n")
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
stdlib.free(entries)
return 0
# === 3. Phase B: 编译每个文件为 .obj ===
if do_phase2 != 0:
stdio.printf("[DBG] before Phase B\n")
stdio.fflush(0)
if log is not None:
log.banner("Phase B: 编译 .obj")
@@ -384,28 +441,51 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
if ent is None or ent.Path is None or ent.Sha1 is None:
continue
stdio.printf("[DBG] PhaseB file=%s\n", ent.Path)
stdio.fflush(0)
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
stdio.printf("[DBG] PhaseB step=alloc combined_ir\n")
stdio.fflush(0)
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
if combined_ir is None:
stdio.printf("[Phase B] combined_ir 分配失败: %s\n", ent.Path)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path)
VLogger.error(fb, "PhaseB")
continue
stdio.printf("[DBG] PhaseB step=BuildCombinedIR sha1=%s\n", ent.Sha1)
stdio.fflush(0)
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
stdio.printf("[DBG] PhaseB step=BuildCombinedIR done len=%d\n", combined_len)
stdio.fflush(0)
if combined_len == 0:
stdio.printf("[Phase B] BuildCombinedIR 失败: %s\n", ent.Path)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", ent.Path)
VLogger.error(fb, "PhaseB")
stdlib.free(combined_ir)
continue
# 编译为 .obj
stdio.printf("[DBG] PhaseB step=compile_module_to_obj\n")
stdio.fflush(0)
cret: int = BuildPipeline.compile_module_to_obj(
combined_ir, combined_len, temp_dir, output_dir, ent.Sha1,
cc_cmd, cc_flags)
stdio.printf("[DBG] PhaseB step=compile_module_to_obj done cret=%d\n", cret)
stdio.fflush(0)
stdlib.free(combined_ir)
if cret != 0:
stdio.printf("[FATAL][Phase B] llc 编译失败,终止编译: %s\n", ent.Path)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", ent.Path)
VLogger.error(fb, "PhaseB")
sys.exit(1)
compiled_count += 1
stdio.printf("[DBG] PhaseB step=obj_path construct\n")
stdio.fflush(0)
# 构造 .obj 路径,检测是否是 main 模块test_main.py 或 main.py
od_len: t.CSizeT = string.strlen(output_dir)
@@ -424,7 +504,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
if op_sliced_len < 512:
string.strcpy(main_obj_path, obj_path_sliced)
else:
stdio.printf("[Phase B] 警告: main_obj_path 缓冲区不足\n")
VLogger.warning("main_obj_path 缓冲区不足", "PhaseB")
else:
# 其他模块: 追加到 obj_paths
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
@@ -435,13 +515,20 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
obj_pos += op_sliced_len
obj_paths[obj_pos] = '\0'
else:
stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n")
VLogger.warning(".obj 路径缓冲区不足", "PhaseB")
stdlib.free(obj_path_sliced)
stdio.printf("[DBG] PhaseB step=obj_path done\n")
stdio.fflush(0)
stdio.printf("[Phase B] 编译完成: %d/%d\n", compiled_count, file_count)
stdio.printf("[DBG] PhaseB loop done compiled_count=%d\n", compiled_count)
stdio.fflush(0)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "编译完成: %d/%d", compiled_count, file_count)
VLogger.success(fb, "PhaseB")
if compiled_count == 0:
stdio.printf("[Phase B] 无成功编译的文件\n")
VLogger.error("无成功编译的文件", "PhaseB")
stdlib.free(entries)
return 1
@@ -449,198 +536,191 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# includes.binary 可能缺少某些 includes .obj如 testcheck.py
# 这些文件被用户项目导入但未被 TransPyV 自身依赖Projectrans.py 未编译它们。
# 检测并编译缺失的 includes 文件到 output_dir加入链接命令。
# 数据来源StubMerger 全局内存存储器(不读取 _sha1_map.txt 文件)
if includes_dir is not None and includes_binary_dir is not None:
stdio.printf("[DBG] PhaseB+ start\n")
stdio.fflush(0)
inc_compiled: int = 0
td_len_mi: t.CSizeT = string.strlen(temp_dir)
map_path_mi: bytes = stdlib.malloc(td_len_mi + 32)
if map_path_mi is not None:
viperlib.snprintf(map_path_mi, td_len_mi + 32, "%s/_sha1_map.txt", temp_dir)
mapf_mi: fileio.File | t.CPtr = fileio.File(map_path_mi, fileio.MODE.R)
if not mapf_mi.closed:
map_buf_mi: bytes = stdlib.malloc(65536)
if map_buf_mi is not None:
map_br_mi: t.CInt64T = mapf_mi.read_all(map_buf_mi, 65536)
mapf_mi.close()
if map_br_mi > 0:
if map_br_mi < 65536:
map_buf_mi[map_br_mi] = '\0'
else:
map_buf_mi[65535] = '\0'
map_len_mi: t.CSizeT = map_br_mi
mpos_mi: t.CSizeT = 0
while mpos_mi < map_len_mi:
ml_start_mi: t.CSizeT = mpos_mi
while mpos_mi < map_len_mi:
if map_buf_mi[mpos_mi] == '\n':
break
mpos_mi += 1
ml_len_mi: t.CSizeT = mpos_mi - ml_start_mi
mpos_mi += 1
# 从全局存储器获取 SHA1/模块名/rel_path 数组(直接访问器,避免 box 解引用问题)
store_count_mi: int = StubMerger.GetSha1StoreCount()
stdio.printf("[DBG] PhaseB+ store_count=%d\n", store_count_mi)
stdio.fflush(0)
if store_count_mi > 0:
store_sha1_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
store_mod_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreModArrPtr()
store_rel_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
stdio.printf("[DBG] PhaseB+ arrs ok sha1=%p mod=%p rel=%p\n", store_sha1_arr_mi, store_mod_arr_mi, store_rel_arr_mi)
stdio.fflush(0)
for si_mi in range(store_count_mi):
# 获取当前条目的 SHA1 和 rel_path
inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(si_mi) * 17
inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(si_mi) * StubMerger.MAX_REL_PATH_LEN
stdio.printf("[DBG] PhaseB+ iter=%d sha1=%s rel=%s\n", si_mi, inc_sha1_mi, inc_rel_mi)
stdio.fflush(0)
# 最小长度: 16(sha1)+1(:)+9(includes/)+1+1+1 = 29
if ml_len_mi < 26:
continue
if map_buf_mi[ml_start_mi + 16] != ':':
continue
rp_start_mi: t.CSizeT = ml_start_mi + 17
if string.strncmp(map_buf_mi + rp_start_mi, "includes/", 9) != 0:
continue
# 检查 .obj 是否已存在于 includes.binary
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35)
if check_pat_mi is None:
continue
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
obj_exists_mi: int = 0
if check_fd_mi is not None:
string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi)
if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE:
w32.win32file.FindClose(check_h_mi)
obj_exists_mi = 1
if obj_exists_mi != 0:
continue
# 提取 SHA1
inc_sha1_mi: str = stdlib.malloc(17)
if inc_sha1_mi is None:
continue
string.strncpy(inc_sha1_mi, map_buf_mi + ml_start_mi, 16)
inc_sha1_mi[16] = '\0'
# .obj 不存在,需要编译
# 构造源文件路径: {includes_dir}/{rel_path}
rel_path_len_mi: t.CSizeT = string.strlen(inc_rel_mi)
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
if src_fp_mi is None:
continue
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
"%s/%s", includes_dir, inc_rel_mi)
# 检查 .obj 是否已存在于 includes.binary
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
check_pat_mi: bytes = stdlib.malloc(ibd_len_mi + 35)
if check_pat_mi is None:
continue
viperlib.snprintf(check_pat_mi, ibd_len_mi + 35, "%s/%s*.obj", includes_binary_dir, inc_sha1_mi)
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
obj_exists_mi: int = 0
if check_fd_mi is not None:
string.memset(check_fd_mi, 0, w32.win32file.WIN32_FIND_DATAA.__sizeof__())
check_h_mi: w32.win32base.HANDLE = w32.win32file.FindFirstFileA(check_pat_mi, check_fd_mi)
if check_h_mi != w32.win32base.INVALID_HANDLE_VALUE:
w32.win32file.FindClose(check_h_mi)
obj_exists_mi = 1
if obj_exists_mi != 0:
continue
# 检查是否为声明文件(只有 declare 没有实质 define
# 判断方法: text.ll 中若有混淆函数 define含 @")则为实现文件
is_decl_mi: int = -1
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
if tpath_mi is not None:
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
if not tf_mi.closed:
is_decl_mi = 1
tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
if tbuf_mi is not None:
tbr_mi: t.CInt64T = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE)
if tbr_mi > 0:
if tbr_mi < StubMerger.STUB_READ_BUF_SIZE:
tbuf_mi[tbr_mi] = '\0'
else:
tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0'
# 逐行扫描: 找 define 行中含 @" 的(混淆函数名)
tpos_mi: t.CSizeT = 0
while tpos_mi < tbr_mi:
tls_mi: t.CSizeT = tpos_mi
while tpos_mi < tbr_mi:
if tbuf_mi[tpos_mi] == '\n':
break
tpos_mi += 1
tll_mi: t.CSizeT = tpos_mi - tls_mi
if tpos_mi < tbr_mi:
tpos_mi += 1
if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0:
# 临时在行尾加 \0 供 strstr 使用
saved_mi: t.CChar = tbuf_mi[tls_mi + tll_mi]
tbuf_mi[tls_mi + tll_mi] = '\0'
if string.strstr(tbuf_mi + tls_mi, "@\"") is not None:
tbuf_mi[tls_mi + tll_mi] = saved_mi
is_decl_mi = 0
break
tbuf_mi[tls_mi + tll_mi] = saved_mi
stdlib.free(tbuf_mi)
tf_mi.close()
stdlib.free(tpath_mi)
# is_decl_mi == -1: text.ll 不存在Phase1 未翻译此文件,可能不被项目导入)
# is_decl_mi == 1: 声明文件(仅 declare 无 define
# 两种情况都跳过:不编译未被 Phase1 翻译的 includes 文件
if is_decl_mi != 0:
continue
# .obj 不存在,需要编译
# 构造源文件路径: {includes_dir}/{rel_path_without_includes_prefix}
rel_path_len_mi: t.CSizeT = ml_len_mi - 26
inc_dir_len_mi: t.CSizeT = string.strlen(includes_dir)
src_fp_mi: bytes = stdlib.malloc(inc_dir_len_mi + 1 + rel_path_len_mi + 1)
if src_fp_mi is None:
continue
viperlib.snprintf(src_fp_mi, inc_dir_len_mi + 1 + rel_path_len_mi + 1,
"%s/%s", includes_dir, map_buf_mi + rp_start_mi + 9)
# 尝试 BuildCombinedIRstub/text 应已由 Phase1 生成)
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
inc_combined_len_mi: t.CSizeT = 0
if inc_combined_mi is not None:
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
# 检查是否为声明文件(只有 declare 没有实质 define
# 判断方法: text.ll 中若有混淆函数 define含 @\")则为实现文件
is_decl_mi: int = -1
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
if tpath_mi is not None:
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
if not tf_mi.closed:
is_decl_mi = 1
tbuf_mi: bytes = stdlib.malloc(StubMerger.STUB_READ_BUF_SIZE)
if tbuf_mi is not None:
tbr_mi: t.CInt64T = tf_mi.read_all(tbuf_mi, StubMerger.STUB_READ_BUF_SIZE)
if tbr_mi > 0:
if tbr_mi < StubMerger.STUB_READ_BUF_SIZE:
tbuf_mi[tbr_mi] = '\0'
else:
tbuf_mi[StubMerger.STUB_READ_BUF_SIZE - 1] = '\0'
# 逐行扫描: 找 define 行中含 @\" 的(混淆函数名)
tpos_mi: t.CSizeT = 0
while tpos_mi < tbr_mi:
tls_mi: t.CSizeT = tpos_mi
while tpos_mi < tbr_mi:
if tbuf_mi[tpos_mi] == '\n':
break
tpos_mi += 1
tll_mi: t.CSizeT = tpos_mi - tls_mi
if tpos_mi < tbr_mi:
tpos_mi += 1
if tll_mi >= 7 and string.strncmp(tbuf_mi + tls_mi, "define ", 7) == 0:
# 临时在行尾加 \0 供 strstr 使用
saved_mi: t.CChar = tbuf_mi[tls_mi + tll_mi]
tbuf_mi[tls_mi + tll_mi] = '\0'
if string.strstr(tbuf_mi + tls_mi, "@\"") is not None:
tbuf_mi[tls_mi + tll_mi] = saved_mi
is_decl_mi = 0
break
tbuf_mi[tls_mi + tll_mi] = saved_mi
stdlib.free(tbuf_mi)
tf_mi.close()
stdlib.free(tpath_mi)
if is_decl_mi == 1:
continue
# 如果 stub/text 不存在,翻译源文件并保存 stub + text然后重试
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
inc_pkg_mi: str = None
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
inc_rel_mi2: str = src_fp_mi + inc_dir_len_mi + 1
inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi2)
tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi)
if tr_mi is not None:
PBP_IR_SIZE: t.CSizeT = 1048576
# 保存 stub.ll (切片路径)
inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
if inc_stub_buf is not None:
tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB)
inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf)
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
if inc_stub_path is not None:
isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W)
if not isf.closed:
isf.write(inc_stub_buf, inc_stub_len)
isf.close()
stdlib.free(inc_stub_path)
stdlib.free(inc_stub_buf)
# 保存 text.ll (切片路径)
inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
if inc_text_buf is not None:
tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT)
inc_text_len: t.CSizeT = string.strlen(inc_text_buf)
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
if inc_text_path is not None:
itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W)
if not itf.closed:
itf.write(inc_text_buf, inc_text_len)
itf.close()
stdlib.free(inc_text_path)
stdlib.free(inc_text_buf)
# 重试 BuildCombinedIR
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
# 尝试 BuildCombinedIRstub/text 应已由 Phase1 生成)
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
inc_combined_len_mi: t.CSizeT = 0
if inc_combined_mi is not None:
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
if inc_combined_len_mi == 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "BuildCombinedIR 失败: %s", src_fp_mi)
VLogger.error(fb, "PhaseB+")
if inc_combined_mi is not None:
stdlib.free(inc_combined_mi)
continue
# 如果 stub/text 不存在,翻译源文件并保存 stub + text然后重试
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
inc_pkg_mi: str = None
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
inc_rel_mi: str = src_fp_mi + inc_dir_len_mi + 1
inc_pkg_mi = HandlesImports.compute_package_from_relpath(mb, inc_rel_mi)
tr_mi: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, src_fp_mi, inc_sha1_mi, inc_pkg_mi)
if tr_mi is not None:
PBP_IR_SIZE: t.CSizeT = 262144
# 保存 stub.ll (切片路径)
inc_stub_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
if inc_stub_buf is not None:
tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB)
inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf)
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
if inc_stub_path is not None:
isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W)
if not isf.closed:
isf.write(inc_stub_buf, inc_stub_len)
isf.close()
stdlib.free(inc_stub_path)
stdlib.free(inc_stub_buf)
# 保存 text.ll (切片路径)
inc_text_buf: bytes = stdlib.malloc(PBP_IR_SIZE)
if inc_text_buf is not None:
tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT)
inc_text_len: t.CSizeT = string.strlen(inc_text_buf)
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
if inc_text_path is not None:
itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W)
if not itf.closed:
itf.write(inc_text_buf, inc_text_len)
itf.close()
stdlib.free(inc_text_path)
stdlib.free(inc_text_buf)
# 重试 BuildCombinedIR
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
# 编译为 .obj
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi,
cc_cmd, cc_flags)
stdlib.free(inc_combined_mi)
if inc_cret_mi != 0:
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "llc 编译失败,终止编译: %s", src_fp_mi)
VLogger.error(fb, "PhaseB+")
sys.exit(1)
if inc_combined_len_mi == 0:
stdio.printf("[Phase B+] BuildCombinedIR 失败: %s\n", src_fp_mi)
if inc_combined_mi is not None:
stdlib.free(inc_combined_mi)
continue
inc_compiled += 1
# 编译为 .obj
inc_cret_mi: int = BuildPipeline.compile_module_to_obj(
inc_combined_mi, inc_combined_len_mi, temp_dir, output_dir, inc_sha1_mi,
cc_cmd, cc_flags)
stdlib.free(inc_combined_mi)
if inc_cret_mi != 0:
stdio.printf("[FATAL][Phase B+] llc 编译失败,终止编译: %s\n", src_fp_mi)
sys.exit(1)
# 添加到 obj_paths (切片路径)
od_len_mi: t.CSizeT = string.strlen(output_dir)
inc_obj_sliced: str = StubMerger._sliced_path(output_dir, od_len_mi, inc_sha1_mi, "obj")
if inc_obj_sliced is not None:
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
obj_pos += inc_obj_len
obj_paths[obj_pos] = '\0'
stdlib.free(inc_obj_sliced)
inc_compiled += 1
# 添加到 obj_paths (切片路径)
od_len_mi: t.CSizeT = string.strlen(output_dir)
inc_obj_sliced: str = StubMerger._sliced_path(output_dir, od_len_mi, inc_sha1_mi, "obj")
if inc_obj_sliced is not None:
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
if obj_pos + inc_obj_len + 2 < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
string.strcpy(obj_paths + obj_pos, inc_obj_sliced)
obj_pos += inc_obj_len
obj_paths[obj_pos] = '\0'
stdlib.free(inc_obj_sliced)
stdio.printf("[Phase B+] 编译缺失 includes: %d\n", inc_compiled)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "编译缺失 includes: %d", inc_compiled)
VLogger.info(fb, "PhaseB+")
# === 4. Phase C: 链接所有 .obj → .exe ===
stdio.printf("[DBG] PhaseC start\n")
stdio.fflush(0)
if log is not None:
log.banner("Phase C: 链接")
@@ -674,20 +754,33 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
final_obj_paths[fop_pos] = '\0'
obj_paths_len: t.CSizeT = fop_pos
stdio.printf("[DBG] PhaseC before link_objs_to_exe len=%d\n", obj_paths_len)
stdio.fflush(0)
lret: int = BuildPipeline.link_objs_to_exe(
final_obj_paths, obj_paths_len,
linker_cmd, linker_flags, exe_path,
includes_binary_dir)
stdio.printf("[DBG] PhaseC link_objs_to_exe done lret=%d\n", lret)
stdio.fflush(0)
if lret == 0:
stdio.printf("输出: %s\n", exe_path)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "输出: %s", exe_path)
VLogger.success(fb, "PhaseC")
if args.get_bool("run"):
stdio.printf("[run] 执行: %s\n", exe_path)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "执行: %s", exe_path)
VLogger.info(fb, "run")
rp: subprocess.CompletedProcess | t.CPtr = subprocess.run(exe_path, False, False)
if rp is not None:
stdio.printf("[run] 退出码: %d\n", rp.returncode)
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb is not None:
viperlib.snprintf(fb, 1024, "退出码: %d", rp.returncode)
VLogger.info(fb, "run")
else:
stdio.printf("[Phase C] 链接失败\n")
VLogger.error("链接失败", "PhaseC")
stdlib.free(entries)
return 1