修正了种子编译器的错误

This commit is contained in:
2026-07-22 21:55:36 +08:00
parent 135aa05485
commit ca7c2120b8
1185 changed files with 12056 additions and 2673 deletions

View File

@@ -14,6 +14,7 @@ import lib.core.Handles.HandlesTranslator as HandlesTranslator
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesImports as HandlesImports
import lib.Projectrans.Config as Config
# ============================================================
# BuildPipeline - 编译管线
@@ -48,10 +49,12 @@ SRC_BUF_SIZE: t.CDefine = 1048576
# ============================================================
def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
sha1_val: str,
current_package: str = None) -> HandlesTranslator.Translator | t.CPtr:
current_package: str = None,
declare_only: int = 0) -> HandlesTranslator.Translator | t.CPtr:
"""翻译文件,返回 Translator 对象(调用者负责 dump_irNone 失败
current_package: 当前文件所属包名用于解析相对导入None 表示顶级模块
declare_only: 0=全量翻译默认1=仅注册 struct/enum/union不翻译方法体
"""
if file_path is None:
return None
@@ -81,6 +84,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
tr.__init__()
tr.ModuleSha1 = sha1_val
tr.CurrentPackage = current_package
tr._declare_only = declare_only
# 设置当前文件名(供报错使用)
HandlesType.set_current_file(file_path)
# 模块切换:清空 CDefine 常量表,确保每个模块的 CDefine 常量正确隔离
@@ -134,19 +138,74 @@ def ensure_dir(path: str) -> int:
# 遇到分隔符时临时截断,创建每一层目录
# CreateDirectoryA 在目录已存在时返回 0失败忽略即可
for i in range(path_len):
ch: int = c.Deref(buf + i)
if ch == ord('/') or ch == ord('\\'):
i: int = 0
plen: int = path_len
while i < plen:
ch: int = buf[i]
if ch == 47 or ch == 92: # '/' = 47, '\\' = 92
saved: int = ch
buf[i] = '\0'
w32.win32file.CreateDirectoryA(buf, None)
buf[i] = saved
i += 1
# 创建最终目录
w32.win32file.CreateDirectoryA(buf, None)
return 0
# ============================================================
# build_sliced_path - 构建切片路径并确保目录存在
#
# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录:
# level=0 → {base_dir}/{sha1}.{ext}
# level=1 → {base_dir}/b7/{sha1}.{ext}
# level=2 → {base_dir}/b7/90/{sha1}.{ext}
#
# 自动调用 ensure_dir 创建子目录。
#
# Args:
# base_dir: 基础目录(如 temp_dir
# sha1: SHA1 字符串
# ext: 文件扩展名(如 "stub.ll"
#
# Returns:
# 完整文件路径mbuddy 分配None 失败
# ============================================================
def build_sliced_path(base_dir: str, sha1: str, ext: str) -> str:
"""构建切片路径并确保目录存在"""
if base_dir is None or sha1 is None or ext is None:
return None
subdir: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel)
base_len: t.CSizeT = string.strlen(base_dir)
sha1_len: t.CSizeT = string.strlen(sha1)
ext_len: t.CSizeT = string.strlen(ext)
if subdir is not None:
sub_len: t.CSizeT = string.strlen(subdir)
# ensure_dir({base_dir}/{subdir})
dir_path: str = _mbuddy.alloc(base_len + sub_len + 2)
if dir_path is not None:
viperlib.snprintf(dir_path, base_len + sub_len + 2, "%s/%s", base_dir, subdir)
ensure_dir(dir_path)
# 文件路径: {base_dir}/{subdir}/{sha1}.{ext}
path_len: t.CSizeT = base_len + sub_len + sha1_len + ext_len + 4
path: str = _mbuddy.alloc(path_len)
if path is None:
return None
viperlib.snprintf(path, path_len, "%s/%s/%s.%s", base_dir, subdir, sha1, ext)
return path
else:
# 无切片: {base_dir}/{sha1}.{ext}
path_len = base_len + sha1_len + ext_len + 3
path = _mbuddy.alloc(path_len)
if path is None:
return None
viperlib.snprintf(path, path_len, "%s/%s.%s", base_dir, sha1, ext)
return path
def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_name: str) -> int:
"""将 IR 缓冲区写入 .ll 文件
@@ -154,22 +213,18 @@ def write_ir_to_file(ir_buf: bytes, ir_len: t.CSizeT, output_dir: str, module_na
ir_buf: IR 文本缓冲区
ir_len: IR 文本长度
output_dir: 输出目录temp 或 output
module_name: 模块名("main"
module_name: 模块名(SHA1
Returns:
0 成功,非 0 失败
"""
if ir_buf is None or output_dir is None:
if ir_buf is None or output_dir is None or module_name is None:
return 1
# 构造文件路径: output_dir/module_name.ll
dir_len: t.CSizeT = string.strlen(output_dir)
name_len: t.CSizeT = string.strlen(module_name)
path_len: t.CSizeT = dir_len + 1 + name_len + 4 # dir/module.ll\0
path: bytes = _mbuddy.alloc(path_len)
# 构造切片路径: output_dir/{sha1前缀}/{module_name}.ll
path: str = build_sliced_path(output_dir, module_name, "ll")
if path is None:
return 1
viperlib.snprintf(path, path_len, "%s/%s.ll", output_dir, module_name)
# 打开文件写入
f: fileio.File | t.CPtr = fileio.File(path, fileio.MODE.W)
@@ -189,22 +244,27 @@ def compile_ll_to_obj(ir_path: str, output_dir: str, module_name: str, cc_cmd: s
Args:
ir_path: .ll 文件路径
output_dir: 输出目录
module_name: 模块名(用于生成 .obj 文件名)
module_name: 模块名(SHA1用于生成 .obj 文件名)
cc_cmd: 编译器命令(如 "llc"
cc_flags: 编译器参数(如 "-filetype=obj -relocation-model=pic"
Returns:
0 成功,非 0 失败
"""
if ir_path is None or cc_cmd is None:
if ir_path is None or cc_cmd is None or output_dir is None or module_name is None:
return 1
# 构造命令: llc -filetype=obj -o output_dir/module_name.obj ir_path
cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(output_dir) + string.strlen(module_name) + string.strlen(ir_path) + 64
# 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj
obj_path: str = build_sliced_path(output_dir, module_name, "obj")
if obj_path is None:
return 1
# 构造命令: llc -filetype=obj -o {obj_path} ir_path
cmd_len: t.CSizeT = string.strlen(cc_cmd) + string.strlen(cc_flags) + string.strlen(obj_path) + string.strlen(ir_path) + 64
cmd: bytes = _mbuddy.alloc(cmd_len)
if cmd is None:
return 1
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s.obj %s", cc_cmd, cc_flags, output_dir, module_name, ir_path)
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s %s", cc_cmd, cc_flags, obj_path, ir_path)
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
if result is None:
@@ -284,7 +344,7 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
Args:
output_dir: 输出目录(包含 .obj 文件)
module_name: 模块名
module_name: 模块名SHA1
linker_cmd: 链接器命令(如 "clang++"
linker_flags: 链接器参数
linker_output: 输出文件名(如 "test.exe"
@@ -293,7 +353,12 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
Returns:
0 成功,非 0 失败
"""
if output_dir is None or linker_cmd is None:
if output_dir is None or linker_cmd is None or module_name is None:
return 1
# 构造切片 .obj 路径: output_dir/{sha1前缀}/{module_name}.obj
obj_path: str = build_sliced_path(output_dir, module_name, "obj")
if obj_path is None:
return 1
# 收集 includes.binary 的 .obj 文件路径
@@ -309,19 +374,19 @@ def link_obj_to_exe(output_dir: str, module_name: str, linker_cmd: str, linker_f
else:
stdio.printf("[link] 警告: includes.binary 无 .obj 文件: %s\n", includes_binary_dir)
# 构造命令: clang++ main.obj extra_objs -o output linker_flags
# 构造命令: clang++ {obj_path} extra_objs -o {output_dir}/{linker_output} linker_flags
# 注意: .obj 文件必须在 -l 库标志之前,否则链接器无法解析符号依赖
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(output_dir) + string.strlen(module_name) + string.strlen(linker_flags) + string.strlen(linker_output) + extra_len + 128
cmd_len: t.CSizeT = string.strlen(linker_cmd) + string.strlen(obj_path) + string.strlen(linker_flags) + string.strlen(output_dir) + string.strlen(linker_output) + extra_len + 128
cmd: bytes = _mbuddy.alloc(cmd_len)
if cmd is None:
return 1
if extra_len > 0:
viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj %s -o %s/%s %s",
linker_cmd, output_dir, module_name, extra_objs,
viperlib.snprintf(cmd, cmd_len, "%s %s %s -o %s/%s %s",
linker_cmd, obj_path, extra_objs,
output_dir, linker_output, linker_flags)
else:
viperlib.snprintf(cmd, cmd_len, "%s %s/%s.obj -o %s/%s %s",
linker_cmd, output_dir, module_name, output_dir, linker_output,
viperlib.snprintf(cmd, cmd_len, "%s %s -o %s/%s %s",
linker_cmd, obj_path, output_dir, linker_output,
linker_flags)
result: subprocess.CompletedProcess | t.CPtr = subprocess.run(cmd, True, True)
@@ -357,7 +422,7 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
Returns:
0 成功,非 0 失败
"""
if ir_buf is None or temp_dir is None or output_dir is None:
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 文件
@@ -366,13 +431,10 @@ def compile_module_to_obj(ir_buf: bytes, ir_len: t.CSizeT,
stdio.printf("[compile] 写 .ll 失败: %s\n", module_name)
return 1
# Step 2: 构造 .ll 路径并编译 → .obj
name_len: t.CSizeT = string.strlen(module_name)
dir_len: t.CSizeT = string.strlen(temp_dir)
ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5)
# Step 2: 构造切片 .ll 路径并编译 → .obj
ir_path: str = build_sliced_path(temp_dir, module_name, "ll")
if ir_path is None:
return 1
viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name)
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
if ret != 0:
@@ -474,15 +536,12 @@ def run_pipeline(ir_buf: bytes, ir_len: t.CSizeT,
return result
# Step 2: llc 编译 .ll → .obj
# 构造 .ll 文件路径
name_len: t.CSizeT = string.strlen(module_name)
dir_len: t.CSizeT = string.strlen(temp_dir)
ir_path: bytes = _mbuddy.alloc(dir_len + name_len + 5)
# 构造切片 .ll 文件路径
ir_path: str = build_sliced_path(temp_dir, module_name, "ll")
if ir_path is None:
result.Success = 0
result.ErrorMsg = "内存分配失败"
return result
viperlib.snprintf(ir_path, dir_len + name_len + 5, "%s/%s.ll", temp_dir, module_name)
ret = compile_ll_to_obj(ir_path, output_dir, module_name, cc_cmd, cc_flags)
if ret != 0:

View File

@@ -199,10 +199,16 @@ def _is_marker_base(base_name: str) -> int:
# ============================================================
# _get_base_name — 从 base AST 节点提取基类名
#
# 支持 Name(id), Attribute(attr), Subscript
# 支持 Name(id), Attribute(attr), Subscript(value, slice)
# 对于 Subscript如 GSListNode[Value]),需要 pool 拼接特化名 "GSListNode[Value]"
# ============================================================
def _get_base_name(base_node: ast.AST | t.CPtr) -> str:
"""从 base AST 节点提取基类名,返回 None=失败"""
def _get_base_name(base_node: ast.AST | t.CPtr,
pool: memhub.MemBuddy | t.CPtr = None) -> str:
"""从 base AST 节点提取基类名,返回 None=失败
对于 Subscript 节点,需要 pool 分配内存拼接特化名;
pool=None 时降级返回基类名(不含类型实参)
"""
if base_node is None:
return None
k: int = base_node.kind()
@@ -214,6 +220,40 @@ def _get_base_name(base_node: ast.AST | t.CPtr) -> str:
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(base_node)
return at.attr
# Subscript(value, slice) 形式 — 如 GSListNode[Value]
if k == ast.ASTKind.Subscript:
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node)
if sub is None or sub.value is None or sub.slice is None:
return None
# 提取基类名(如 "GSListNode"
base_nm: str = _get_base_name(sub.value, pool)
if base_nm is None:
return None
# 提取类型实参名(如 "Value"
slice_k: int = sub.slice.kind()
arg_nm: str = None
if slice_k == ast.ASTKind.Name:
sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice)
arg_nm = sl_nm.id
# 如果无法提取类型实参,返回基类名(降级)
if arg_nm is None:
return base_nm
# 无 pool 时返回基类名(降级,无法拼接特化名)
if pool is None:
return base_nm
# 拼接特化名 "GSListNode[Value]"
base_len: t.CSizeT = string.strlen(base_nm)
arg_len: t.CSizeT = string.strlen(arg_nm)
total_len: t.CSizeT = base_len + arg_len + 3 # "[" + arg + "]" + NUL
mangled: str = pool.alloc(total_len)
if mangled is None:
return base_nm # 降级
mangled[0] = '\0'
string.strcat(mangled, base_nm)
string.strcat(mangled, "[")
string.strcat(mangled, arg_nm)
string.strcat(mangled, "]")
return mangled
return None
@@ -221,11 +261,17 @@ def _get_base_name(base_node: ast.AST | t.CPtr) -> str:
# _get_parent_class — 获取 ClassDef 的真实父类名(非标记基类)
#
# 遍历 bases返回第一个非标记基类的名字None=无真实父类
# 支持 Name, Attribute, Subscript 三种 base 节点
# 对于 Subscript如 GSListNode[Value]),需要 trans.Pool 拼接特化名
# ============================================================
def _get_parent_class(cd: ast.ClassDef | t.CPtr) -> str:
def _get_parent_class(cd: ast.ClassDef | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> str:
"""获取 ClassDef 的真实父类名,返回 None=无真实父类"""
if cd is None or cd.bases is None:
return None
pool: memhub.MemBuddy | t.CPtr = None
if trans is not None:
pool = trans.Pool
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
@@ -234,12 +280,66 @@ def _get_parent_class(cd: ast.ClassDef | t.CPtr) -> str:
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
bname: str = _get_base_name(base_node)
bname: str = _get_base_name(base_node, pool)
if bname is not None and _is_marker_base(bname) == 0:
return bname
return None
# ============================================================
# _trigger_base_specialization — 触发 base 中 Subscript 的泛型特化
#
# 对于 class Value(GSListNode[Value])GSListNode[Value] 是 Subscript 节点。
# 在 translate_class_def 处理 Value 之前,需要先特化 GSListNode[Value]
# 否则 find_struct_by_module("GSListNode[Value]") 返回 None父类字段不被继承。
#
# 遍历 cd.bases如果 base 是 Subscript提取 class_name 和 type_args
# 调用 _specialize_generic_class 触发特化。
# ============================================================
def _trigger_base_specialization(trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr):
"""触发 base 中 Subscript 的泛型特化(如 GSListNode[Value]"""
if trans is None or cd is None or cd.bases is None:
return
pool: memhub.MemBuddy | t.CPtr = trans.Pool
bases: list[ast.AST | t.CPtr] | t.CPtr = cd.bases
bn: t.CSizeT = bases.__len__()
if bn == 0:
return
for bi in range(bn):
base_node: ast.AST | t.CPtr = bases.get(bi)
if base_node is None:
continue
bk: int = base_node.kind()
if bk != ast.ASTKind.Subscript:
continue
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(base_node)
if sub is None or sub.value is None or sub.slice is None:
continue
# 提取泛型类名(如 "GSListNode"
gen_class_name: str = _get_base_name(sub.value, pool)
if gen_class_name is None:
continue
# 跳过标记基类
if _is_marker_base(gen_class_name) == 1:
continue
# 提取类型实参名(如 "Value"
slice_k: int = sub.slice.kind()
arg_nm: str = None
if slice_k == ast.ASTKind.Name:
sl_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.slice)
arg_nm = sl_nm.id
if arg_nm is None:
continue
# 构建 type_args 列表
type_args: list[str] | t.CPtr = list[str](pool, 1)
if type_args is None:
continue
type_args.append(arg_nm)
# 触发特化_specialize_generic_class 有缓存,重复调用安全)
_specialize_generic_class(trans, gen_class_name, type_args)
# ============================================================
# _has_any_func_cvtable — 检查类中是否有任何函数标记了 @t.CVTable
#
@@ -304,7 +404,7 @@ def _should_method_be_virtual(cd: ast.ClassDef | t.CPtr,
return 1
# 4. 检查继承关系
parent_name: str = _get_parent_class(cd)
parent_name: str = _get_parent_class(cd, trans)
if parent_name is not None:
# 用 SHA1 感知查找父类,规避跨模块同名找错
is_nvt: int = 0
@@ -349,7 +449,7 @@ def _detect_vtable_status(cd: ast.ClassDef | t.CPtr,
return _has_any_func_cvtable(cd)
# 检查是否有真实父类(继承自动启用 CVTable
parent_name: str = _get_parent_class(cd)
parent_name: str = _get_parent_class(cd, trans)
if parent_name is not None:
# 用 SHA1 感知查找父类,规避跨模块同名找错
is_nvt: int = 0
@@ -1111,9 +1211,27 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr = trans.Pool
# ============================================================
# 诊断输出:追踪 GSListNode 特化调用路径
# ============================================================
if string.strcmp(class_name, "GSListNode") == 0:
stdio.printf("[SPEC] === _specialize_generic_class ===\n")
stdio.printf("[SPEC] class=%s module=%s\n", class_name, trans.ModuleSha1)
if type_args is not None:
ta_n: t.CSizeT = type_args.__len__()
ta_i: t.CSizeT
for ta_i in range(ta_n):
ta: str = type_args.get(ta_i)
if ta is not None:
stdio.printf("[SPEC] type_arg[%d]=%s\n", ta_i, ta)
stdio.fflush(0)
# 1. 查找泛型模板
template_cd: ast.ClassDef | t.CPtr = _find_generic_template(class_name)
if template_cd is None:
if string.strcmp(class_name, "GSListNode") == 0:
stdio.printf("[SPEC] template NOT FOUND, return None\n")
stdio.fflush(0)
return None
# 2. 生成特化名
@@ -1148,11 +1266,18 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr,
string.strcat(spec_key, ">")
cached: str = _find_cached_spec(spec_key)
if cached is not None:
if string.strcmp(class_name, "GSListNode") == 0:
stdio.printf("[SPEC] CACHE HIT, return cached=%s\n", cached)
stdio.fflush(0)
return cached
# 4. 检查是否已注册Phase B 重复特化)
existing: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if existing is not None:
if string.strcmp(class_name, "GSListNode") == 0:
stdio.printf("[SPEC] EXISTING registered, return spec_name=%s field_count=%d\n",
spec_name, existing.FieldCount)
stdio.fflush(0)
_cache_spec(pool, spec_key, spec_name)
return spec_name
@@ -1179,6 +1304,27 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr,
trans.GenericTypeArgs = None
HandlesType.clear_generic_context()
# 诊断输出:检查特化结果
if string.strcmp(class_name, "GSListNode") == 0:
result_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if result_entry is not None:
stdio.printf("[SPEC] DONE spec_name=%s field_count=%d\n",
spec_name, result_entry.FieldCount)
# 打印每个字段的类型信息
ri: int
for ri in range(result_entry.FieldCount):
rfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
result_entry, ri)
if rfe is not None:
rfn: str = HandlesStruct.get_field_name_ptr(rfe)
rft: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_field_type_ptr(rfe)
stdio.printf("[SPEC] field[%d] name=%s type=%d\n",
ri, rfn if rfn is not None else "(null)",
t.CSizeT(rft) if rft is not None else 0)
else:
stdio.printf("[SPEC] DONE but result NOT FOUND in struct table!\n")
stdio.fflush(0)
return spec_name
@@ -1224,11 +1370,18 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
# SHA1 已在 register_struct 时设置,无需再补
return 0
# ============================================================
# 触发 base 中 Subscript 的泛型特化(如 GSListNode[Value]
# 必须在 _detect_vtable_status 和父类字段继承之前调用,
# 否则 find_struct_by_module("GSListNode[Value]") 返回 None
# ============================================================
_trigger_base_specialization(trans, cd)
# ============================================================
# VTable 检测:判断是否启用虚表
# ============================================================
has_vtable: int = _detect_vtable_status(cd, trans)
parent_name: str = _get_parent_class(cd)
parent_name: str = _get_parent_class(cd, trans)
is_novtable_deco: int = 0
if cd.decorator_list is not None:
if _has_decorator(cd.decorator_list, "NoVTable") == 1:
@@ -1473,11 +1626,9 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
if fname is not None and fty2 is not None:
HandlesStruct.add_field(pool, entry, fname, fty2, fdef, fannot)
stdio.printf("[CLASS] registered %s with %d fields (vtable=%d)\n",
class_name, field_count, has_vtable)
# Phase 1a 声明模式:只注册 struct不翻译方法体
# Phase 1a 声明模式:只注册 struct + 设置 OOP 标志,不翻译方法体
if trans._declare_only == 1:
_translate_oop_methods(trans, cd, struct_ty, class_name, 1)
return 0
# ============================================================
@@ -1844,8 +1995,6 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
vt_self_entry.VTableMethods = method_names_buf
vt_self_entry.VTableMethodCount = method_count
stdio.printf("[VTABLE] generated vtable for %s with %d methods\n",
class_name, method_count)
return 0
@@ -1870,8 +2019,12 @@ def _generate_vtable(trans: HT.Translator | t.CPtr,
def _translate_oop_methods(trans: HT.Translator | t.CPtr,
cd: ast.ClassDef | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str) -> int:
"""扫描 class body 中的方法并翻译,生成 __before_init__"""
class_name: str,
mark_only: int = 0) -> int:
"""扫描 class body 中的方法并翻译,生成 __before_init__
mark_only: 0=全量翻译默认1=只设置 IsOOP/HasNew/HasInit 标志(不翻译方法体)
"""
if trans is None or cd is None or struct_ty is None or class_name is None:
return 0
@@ -1922,6 +2075,10 @@ def _translate_oop_methods(trans: HT.Translator | t.CPtr,
if has_new != 0:
oop_entry.HasNew = 1
# mark_only 模式:只设置标志,不翻译方法体
if mark_only != 0:
return 0
# 第二遍:翻译每个方法
for ci in range(cn):
stmt: ast.AST | t.CPtr = children.get(ci)

View File

@@ -207,6 +207,10 @@ def coerce_to_type(builder: llvmlite.IRBuilder | t.CPtr,
# float → int
if val_fbits != 0 and target_bits != 0:
return llvmlite.build_fp2si(builder, val, target_ty)
# 整数 → 指针: inttoptr
# 适用于: 跨模块方法返回 i64默认推断目标变量是指针类型
if val_bits != 0 and is_ptr_type(target_ty) != 0:
return llvmlite.build_inttoptr(builder, val, target_ty)
# 指针 → 非指针值: build_load 解引用
# 适用于: 指针 → 整数 (如 i8* → i8), 指针 → 结构体值
# 当构造器返回 Ptr(Struct) 但目标变量是 Struct 值类型时,需要 load

View File

@@ -17,7 +17,6 @@ import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesClassDef as HandlesClassDef
# ============================================================
# 全局模块 SHA1 映射module_name → SHA1
#
@@ -30,7 +29,6 @@ _g_sha1_arr: bytes = None
_g_mod_arr: bytes = None
_g_sha1_count: int = 0
def set_module_sha1_map(sha1_arr: bytes, mod_arr: bytes, count: int) -> int:
"""设置全局模块 SHA1 映射"""
global _g_sha1_arr
@@ -41,7 +39,6 @@ def set_module_sha1_map(sha1_arr: bytes, mod_arr: bytes, count: int) -> int:
_g_sha1_count = count
return 0
def _lookup_module_sha1(mod_name: str) -> str:
"""查找模块名对应的 SHA1找不到返回 None"""
if mod_name is None:
@@ -57,7 +54,6 @@ def _lookup_module_sha1(mod_name: str) -> str:
return _g_sha1_arr + sidx
return None
def _lookup_module_sha1_suffix(mod_suffix: str) -> str:
"""后缀匹配查找模块 SHA1如 mod_suffix="__types" 匹配 "llvmlite.__types"
@@ -93,7 +89,6 @@ def _lookup_module_sha1_suffix(mod_suffix: str) -> str:
return _g_sha1_arr + sidx2
return None
# ============================================================
# 全局 CExport 函数表module_sha1 + func_name
#
@@ -108,7 +103,6 @@ _g_cexport_func_arr: bytes = None
_g_cexport_count: int = 0
_CEXPORT_MAX: t.CDefine = 256
def register_cexport_func(sha1: str, func_name: str) -> int:
"""注册 CExport 函数到全局表sha1+func_name 二元组)"""
global _g_cexport_sha1_arr
@@ -132,7 +126,6 @@ def register_cexport_func(sha1: str, func_name: str) -> int:
return 1
return 0
def is_cexport_func(sha1: str, func_name: str) -> int:
"""检查 (sha1, func_name) 是否是 CExport 函数"""
if sha1 is None or func_name is None:
@@ -147,7 +140,6 @@ def is_cexport_func(sha1: str, func_name: str) -> int:
return 1
return 0
# ============================================================
# _lookup_mod_sha1 - 从 from_imports 查找类所属模块的 SHA1
#
@@ -185,14 +177,12 @@ def _lookup_mod_sha1(pool: memhub.MemBuddy | t.CPtr,
sha1 = _lookup_module_sha1_suffix(base_mod)
return sha1
# ============================================================
# HandlesExprCall - 函数调用表达式处理Mixin 继承模式)
#
# 工具函数和 FuncEntry 保留为模块级ExprCallHandle 提供 trans 接口
# ============================================================
# ============================================================
# 在模块函数链表中按名称查找函数
# ============================================================
@@ -239,7 +229,6 @@ def find_func_in_module(mod: llvmlite.LLVMModule | t.CPtr,
cur = llvmlite.function_get_next(cur)
return None
# ============================================================
# _infer_external_func_ret_ty - 根据函数名推断外部函数返回类型
#
@@ -341,7 +330,6 @@ def _infer_external_func_ret_ty(pool: memhub.MemBuddy | t.CPtr,
# 默认 i32
return llvmlite.Int32(pool)
# ============================================================
# _get_external_func_param_ty - 获取外部函数第 idx 个参数的期望类型
#
@@ -390,7 +378,6 @@ def _get_external_func_param_ty(pool: memhub.MemBuddy | t.CPtr,
return None
# ============================================================
# _emit_llvm_memcpy_intrinsic — 将 memcpy 调用映射到 @llvm.memcpy 内联函数
#
@@ -498,7 +485,6 @@ def _emit_llvm_memcpy_intrinsic(pool: memhub.MemBuddy | t.CPtr,
# 返回 dst匹配 C memcpy 语义: 返回 dest 指针)
return dst_coerced
# ============================================================
# c.Deref(ptr) — 解引用指针load i8字符遍历用例
#
@@ -525,7 +511,6 @@ def translate_c_deref(pool: memhub.MemBuddy | t.CPtr,
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
return llvmlite.build_load(builder, i8_ty, ptr_val)
# ============================================================
# c.DerefAs(ptr, val) — 解引用写入,*ptr = val
#
@@ -559,7 +544,6 @@ def translate_c_derefas(pool: memhub.MemBuddy | t.CPtr,
llvmlite.build_store(builder, val, casted_ptr)
return val
# ============================================================
# c.Addr(var) — 取变量地址,返回 alloca 指针(不 load
#
@@ -587,7 +571,6 @@ def translate_c_addr(pool: memhub.MemBuddy | t.CPtr,
return HandlesVar.lookup_var(trans.SymTab, nm.id)
# ============================================================
# c.Load(a, b) — 指针间复制: *a = *b
#
@@ -641,7 +624,6 @@ def translate_c_load(pool: memhub.MemBuddy | t.CPtr,
llvmlite.build_store(builder, loaded, dst_cast)
return loaded
# ============================================================
# c.Asm — 内联汇编支持
#
@@ -657,7 +639,6 @@ ASM_CONST_BUF_SIZE: t.CDefine = 512
ASM_ARGS_BUF_SIZE: t.CDefine = 512
ASM_LINE_BUF_SIZE: t.CDefine = 4096
# ============================================================
# AsmOperand - 内联汇编操作数条目
# ============================================================
@@ -668,7 +649,6 @@ class AsmOperand:
Constraint: str # 约束字符串 (如 "r", "=r")
IsOutput: int # 1=输出, 0=输入
# ============================================================
# _asm_append_cstr — 将 C 字符串 src 追加到 dst 末尾
# ============================================================
@@ -688,7 +668,6 @@ def _asm_append_cstr(dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
i += 1
dst[dlen + i] = '\0'
# ============================================================
# _asm_escape_for_ir — 将汇编文本转义为 LLVM IR 字符串内容
#
@@ -732,7 +711,6 @@ def _asm_escape_for_ir(pool: memhub.MemBuddy | t.CPtr,
buf[pos] = '\0'
return buf
# ============================================================
# _resolve_register — 将 ASM_DESCR 属性名映射到约束字符串
# ============================================================
@@ -820,7 +798,6 @@ def _resolve_register(attr_name: str) -> str:
return ""
# ============================================================
# _resolve_asm_descr — 递归解析约束表达式
#
@@ -882,7 +859,6 @@ def _resolve_asm_descr(pool: memhub.MemBuddy | t.CPtr,
return ""
# ============================================================
# _asm_get_operand — 获取操作数数组中第 idx 个元素的指针
# ============================================================
@@ -893,7 +869,6 @@ def _asm_get_operand(base: AsmOperand | t.CPtr,
entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size
return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# ============================================================
# _asm_is_c_call — 检查 Call 节点是否是 c.XXX 调用
#
@@ -913,7 +888,6 @@ def _asm_is_c_call(node: ast.Call | t.CPtr) -> str:
return None
return at.attr
# ============================================================
# _asm_add_operand — 添加操作数到数组
#
@@ -933,7 +907,6 @@ def _asm_add_operand(operands: AsmOperand | t.CPtr,
op.IsOutput = is_output
return count + 1
# ============================================================
# translate_c_asm — 翻译 c.Asm 内联汇编
#
@@ -1397,7 +1370,6 @@ def translate_c_asm(pool: memhub.MemBuddy | t.CPtr,
return None
# ============================================================
# c.LLVMIR — 内联 LLVM IR 支持
#
@@ -1419,7 +1391,6 @@ def translate_c_asm(pool: memhub.MemBuddy | t.CPtr,
LLVMIR_MAX_OPS: t.CDefine = 16
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
# ============================================================
# _llvmir_get_op — 获取第 i 个 AsmOperand 槽位
# ============================================================
@@ -1429,7 +1400,6 @@ def _llvmir_get_op(buf: AsmOperand | t.CPtr, i: int) -> AsmOperand | t.CPtr:
entry_addr: t.CUInt64T = t.CUInt64T(buf) + i * entry_size
return (AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# ============================================================
# _llvmir_find_op_marker — 在字符串中查找 %__OP 并返回编号
#
@@ -1441,7 +1411,6 @@ def _llvmir_find_op_marker(s: t.CChar | t.CPtr) -> t.CPtr:
return None
return string.strstr(s, "%__OP")
# ============================================================
# _llvmir_parse_op_num — 从 %__OPN__ 中解析编号 N
#
@@ -1466,7 +1435,6 @@ def _llvmir_parse_op_num(marker: t.CChar | t.CPtr) -> int:
ch = num_start[i]
return num
# ============================================================
# _llvmir_match_icmp_pred — 将预测字符串转为 ICMP 常量
# ============================================================
@@ -1496,7 +1464,6 @@ def _llvmir_match_icmp_pred(pred: str) -> int:
return 9
return 0
# ============================================================
# _llvmir_match_fcmp_pred — 将预测字符串转为 FCMP 常量
# ============================================================
@@ -1534,7 +1501,6 @@ def _llvmir_match_fcmp_pred(pred: str) -> int:
return 13
return 0
# ============================================================
# _llvmir_extract_two_ops — 从模板中提取两个操作数编号
#
@@ -1567,7 +1533,6 @@ def _llvmir_extract_two_ops(template: t.CChar | t.CPtr,
out_nums[1] = _llvmir_parse_op_num(m2)
return 1
# ============================================================
# _llvmir_resolve_op — 根据编号解析操作数值
# ============================================================
@@ -1590,7 +1555,6 @@ def _llvmir_resolve_op(op_num: int,
op2: AsmOperand | t.CPtr = _llvmir_get_op(output_targets, idx)
return op2.Value
# ============================================================
# _llvmir_store_outputs — 将结果存储到输出变量
# ============================================================
@@ -1608,7 +1572,6 @@ def _llvmir_store_outputs(pool: memhub.MemBuddy | t.CPtr,
llvmlite.build_store(builder, result, op.Value)
return result
# ============================================================
# translate_c_llvmir — 翻译 c.LLVMIR 内联 LLVM IR
# ============================================================
@@ -1953,7 +1916,6 @@ def translate_c_llvmir(pool: memhub.MemBuddy | t.CPtr,
stdio.printf("[LLVMIR] unsupported instruction: %s\n", instr_kw)
return None
# ============================================================
# _apply_struct_defaults — 应用结构体字段的默认值
#
@@ -1989,7 +1951,6 @@ def _apply_struct_defaults(pool: memhub.MemBuddy | t.CPtr,
default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty)
llvmlite.build_store(builder, default_val, field_ptr)
# ============================================================
# _translate_struct_ctor — 结构体构造函数 Point(10, 20)
#
@@ -2147,7 +2108,6 @@ def _translate_struct_ctor(pool: memhub.MemBuddy | t.CPtr,
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
# ============================================================
# _do_virtual_call — 通过虚表间接调用虚方法
#
@@ -2308,7 +2268,6 @@ def _do_virtual_call(pool: memhub.MemBuddy | t.CPtr,
# 12. 间接调用
return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty)
# ============================================================
# _call_method_on_ptr — 在结构体指针上调用方法
#
@@ -2384,6 +2343,11 @@ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr,
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
else:
# found_func 为 None跨模块调用 stub 未注入):根据方法名推断返回类型
# __new__ 返回 Ptr(struct_ty),其他方法默认 void
if string.strcmp(method_name, "__new__") == 0 and cmop_struct_ty is not None:
call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty)
# 构建参数链表: self_ptr → extra_args...
llvmlite.value_set_next(self_ptr, None)
@@ -2446,7 +2410,6 @@ def _call_method_on_ptr(pool: memhub.MemBuddy | t.CPtr,
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# ============================================================
# _infer_method_ret_ty - 根据方法名推断返回类型
#
@@ -2482,10 +2445,15 @@ def _infer_method_ret_ty(pool: memhub.MemBuddy | t.CPtr,
# 返回 void 的方法
if string.strcmp(method_name, "__before_init__") == 0:
return llvmlite.Void(pool)
if string.strcmp(method_name, "__init__") == 0:
return llvmlite.Void(pool)
if string.strcmp(method_name, "__exit__") == 0:
return llvmlite.Void(pool)
# 默认 i32free, reset, __init__, __exit__, _fl_push 等
return llvmlite.Int32(pool)
# 默认 i64整数既可安全截断为 i32trunc也可转换为指针inttoptr
# 避免使用指针类型i8*)导致 coerce_to_type 生成 load解引用造成崩溃
# x86-64 ABI 中 i32 返回值在 rax 低 32 位i64 读取后 trunc 取低 32 位是安全的
return llvmlite.Int64(pool)
# ============================================================
# _translate_method_call - 翻译方法调用 obj.method(args)
@@ -2633,7 +2601,6 @@ def _translate_method_call(pool: memhub.MemBuddy | t.CPtr,
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# ============================================================
# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名
#
@@ -2656,7 +2623,6 @@ def _kwarg_name_matches(kw_arg: str,
return 0
return 1
# ============================================================
# _translate_struct_ctor_kw — 结构体构造函数(关键字参数)
#
@@ -2747,7 +2713,6 @@ def _translate_struct_ctor_kw(pool: memhub.MemBuddy | t.CPtr,
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
# ============================================================
# _translate_call_with_kwargs — 带关键字参数的函数调用
#
@@ -2850,7 +2815,6 @@ def _translate_call_with_kwargs(pool: memhub.MemBuddy | t.CPtr,
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1)
return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0)
# ============================================================
# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换
#
@@ -2892,14 +2856,12 @@ def _translate_t_type_cast(pool: memhub.MemBuddy | t.CPtr,
# 指针 → 指针: bitcast
return llvmlite.build_bitcast(builder, val, target_ty)
# ============================================================
# 泛型实例化辅助:从 Subscript slice 提取类型实参名
# ============================================================
# _get_type_name_from_annotation 已移至 HandlesType.py支持 BinOp/Attribute
# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用
def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr,
slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr:
"""从 Subscript.slice 提取类型实参名列表
@@ -2929,7 +2891,6 @@ def _extract_type_args_from_slice(pool: memhub.MemBuddy | t.CPtr,
result.append(tn)
return result
# ============================================================
# 翻译函数调用 Call(func, args) — 模块级版本
# ============================================================
@@ -3678,7 +3639,6 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
return _emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2)
return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, 0)
# ============================================================
# 翻译闭包调用 — 通过闭包指针间接调用
#
@@ -3738,7 +3698,6 @@ def translate_closure_call(pool: memhub.MemBuddy | t.CPtr,
env_ptr.Next = None
return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty)
# ============================================================
# 翻译 printf 调用 — 模块级版本
# ============================================================
@@ -3802,7 +3761,6 @@ def translate_printf_call(pool: memhub.MemBuddy | t.CPtr,
# 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器)
llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1)
# ============================================================
# FuncEntry 结构体(用于函数表)
# ============================================================
@@ -3812,7 +3770,6 @@ class FuncEntry:
Name: str
Func: llvmlite.Function | t.CPtr
# ============================================================
# 初始化函数表
# ============================================================
@@ -3825,7 +3782,6 @@ def init_func_table(pool: memhub.MemBuddy | t.CPtr,
string.memset(funcs_ptr, 0, size)
return funcs_ptr
# ============================================================
# 查找函数
# ============================================================
@@ -3844,7 +3800,6 @@ def find_func_in_table(funcs: FuncEntry | t.CPtr,
return entry.Func
return None
# ============================================================
# 添加函数到函数表
# ============================================================
@@ -3867,7 +3822,6 @@ def add_func_to_table(funcs: FuncEntry | t.CPtr,
_register_global_func(name, func)
return 0
# ============================================================
# 全局函数注册表(跨模块函数查找)
#
@@ -3879,7 +3833,6 @@ GLOBAL_FUNC_MAX: t.CDefine = 8192
_global_funcs: FuncEntry | t.CPtr = None
_global_func_count: int = 0
def _init_global_func_table() -> int:
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
global _global_funcs
@@ -3894,7 +3847,6 @@ def _init_global_func_table() -> int:
_global_func_count = 0
return 1
def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int:
"""注册函数到全局表(已存在则跳过),返回 0 成功
@@ -3919,14 +3871,12 @@ def _register_global_func(name: str, func: llvmlite.Function | t.CPtr) -> int:
_global_func_count += 1
return 0
def find_func_global(name: str) -> llvmlite.Function | t.CPtr:
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
if name is None or _global_funcs is None:
return None
return find_func_in_table(_global_funcs, _global_func_count, name)
# ============================================================
# ExprCallHandle - 函数调用处理器Mixin 继承模式)
#
@@ -3958,7 +3908,6 @@ class ExprCallHandle(HandlesBase.Mixin):
self.Trans.Pool, self.Trans._cur_builder, self.Trans.Module,
cl, self.Trans)
# ============================================================
# NewExprCallHandle - 工厂函数
# ============================================================

View File

@@ -425,7 +425,6 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
param_types_str: str = HandlesType.build_param_types_str(pool, fd.args)
ret_ty = HandlesType.infer_return_type(
pool, fd.children, param_types_str)
# 检测是否为外部声明函数t.CExtern 或 t.State
# 语义t.CExtern 忽略 body 体,仅生成 declare由链接器解析符号
# t.State = t.CExtern + t.CExport既是声明又是导出
@@ -458,10 +457,15 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
if is_extern_decl != 0:
# 外部声明函数:生成 declare仅声明不定义
# 先检查是否已由 forward_declare_functions 创建,避免重复 declare
existing_extern: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(mod, mangled_name)
if existing_extern is not None:
# 已存在前向声明,复用之,不再重复创建
return 0
func: llvmlite.Function | t.CPtr = llvmlite.create_declare(
pool, mod, mangled_name, ret_ty)
if func is None:
stdio.printf("[FUNC] create_declare %s failed\n", fd.name)
return 0
# 注册到函数表
@@ -553,7 +557,6 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
if pname is not None:
viperlib.snprintf(pname, 32, "%%%s", arg.arg)
llvmlite.add_param(pool, func, param_ty, pname)
# 创建 entry 块
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, "entry")
if entry_blk is None:
@@ -603,7 +606,6 @@ def translate_function_def(trans: HT.Translator | t.CPtr,
param_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(
pool, param_ty2, pname2)
llvmlite.build_store(func_builder, param_val, alloca)
# 保存模块级作用域状态(仅非变量表相关)
old_func: llvmlite.Function | t.CPtr = trans._cur_func
old_builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder

View File

@@ -104,8 +104,6 @@ def translate_children(trans: HT.Translator | t.CPtr,
# ClassDef 在模块级直接处理(不需要 builder
# _declare_only=2import扫描模式时跳过只处理 import 依赖
if trans._declare_only != 2:
cd_node: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
cd_name: str = "?" if cd_node is None or cd_node.name is None else cd_node.name
HandlesClassDef.translate_class_def(trans, child)
elif trans._declare_only == 0 and trans._cur_builder is not None:
# 有 builder → 委托 HandlesBody 分派

View File

@@ -333,15 +333,12 @@ def scan_includes(pool: memhub.MemBuddy | t.CPtr,
if pool is None or includes_dir is None:
return None
stdio.printf("[Phase1] 扫描 includes 目录: %s\n", includes_dir)
result: ScanResult | t.CPtr = create_scan_result(pool)
if result is None:
return None
scan_directory_recursive(pool, includes_dir, None, result)
stdio.printf("[Phase1] 扫描完成: %d 个 .py 文件\n", result.Count)
return result

View File

@@ -18,7 +18,9 @@ import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.IncludesScanner as IncludesScanner
import lib.core.StubMerger as StubMerger
import lib.core.BuildPipeline as BuildPipeline
import lib.Projectrans.Config as Config
import lib.StubGen.Converter as StubConverter
# 全局 mbuddy 指针
_mbuddy: memhub.MemManager | t.CPtr
@@ -26,6 +28,10 @@ _mbuddy: memhub.MemManager | t.CPtr
# 源代码缓冲区大小1MB
SRC_BUF_SIZE: t.CDefine = 1048576
# pyi 缓冲区大小256KB
PYI_BUF_SIZE: t.CSizeT = 262144
# ============================================================
# RunPhase1 - Phase1: 扫描 includes 目录,按需翻译并生成 stub
#
@@ -48,6 +54,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdio.printf("[Phase1] includes_dir 或 temp_dir 为空,跳过\n")
return 1
# 确保 temp 目录存在build_dir/temp 可能尚未创建)
BuildPipeline.ensure_dir(temp_dir)
if log is not None:
log.banner("Phase1: 扫描 includes按需翻译")
@@ -57,8 +66,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdio.printf("[Phase1] 扫描失败\n")
return 1
stdio.printf("[Phase1] 共 %d 个文件\n", result.Count)
# 读取 _sha1_map.txt 获取需要的 includes SHA1 集合
# 优先使用 Projectrans.py 生成的 _sha1_map.txt含依赖分析只包含需要的 includes
# 若不存在,则从扫描结果生成(包含所有 includes可能导致结构体表溢出
@@ -75,8 +82,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
if set_count < 0:
stdio.printf("[Phase1] 无法加载 _sha1_map.txt跳过 Phase1\n")
return 1
stdio.printf("[Phase1] includes SHA1 集合: %d\n", set_count)
# 构建模块 SHA1 映射(供跨模块函数调用名混淆使用)
td_len_p1map: t.CSizeT = string.strlen(temp_dir)
p1_sha1_arr: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 17)
@@ -99,7 +104,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 不调用 resolve_annotation_type避免 list[...] 等不支持的语法触发 crash。
# 生成 .deps.txt 供依赖图按需翻译使用。
# ============================================================
stdio.printf("[Phase1a-pre] 扫描 import 依赖\n")
p1a_registered: int = 0
p1a_skipped: int = 0
p1a_failed: int = 0
@@ -178,9 +182,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 生成 .deps.txt记录依赖模块名供依赖图按需翻译使用
td_len_a: t.CSizeT = string.strlen(temp_dir)
deps_path_a: bytes = stdlib.malloc(td_len_a + 32)
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_a, sha1_a, "deps.txt")
if deps_path_a is not None:
viperlib.snprintf(deps_path_a, td_len_a + 32, "%s/%s.deps.txt", temp_dir, sha1_a)
df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W)
if not df_a.closed:
if tr_a._imported_modules is not None:
@@ -197,8 +200,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(src_buf_a)
stdio.printf("[Phase1a-pre] 完成: 扫描=%d 跳过=%d 失败=%d\n", p1a_registered, p1a_skipped, p1a_failed)
# ============================================================
# 依赖图按需翻译:构建可达 SHA1 集合
#
@@ -217,16 +218,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
reachable_count = StubMerger._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set)
if reachable_count > 0:
use_reachable = 1
stdio.printf("[Phase1b] 使用可达 SHA1 集合过滤: %d\n", reachable_count)
# 用可达集合重新生成 _sha1_map.txt按图求索的最终产物
# Phase B+ 只遍历这些条目,避免编译不需要的 includes如 asm.py
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count)
# 重新加载 sha1_set使后续 Phase 1a-pre/1a/1b 的过滤也使用可达集合
string.memset(sha1_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
set_count = StubMerger._load_includes_sha1_set(mb, temp_dir, sha1_set)
stdio.printf("[Phase1b] _sha1_map.txt 已重写为可达集合: %d\n", set_count)
else:
stdio.printf("[Phase1b] 可达 SHA1 集合构建失败,回退到全量集合\n")
stdlib.free(reachable_set)
reachable_set = None
@@ -238,8 +236,6 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# Phase 1b 全量翻译时 struct 已注册,走 existing 路径只翻译方法体。
# 只处理可达文件,避免翻译不需要的 includes如 Test 不依赖 ast 模块)。
# ============================================================
stdio.printf("[Phase1a] 注册可达文件 struct/enum/union\n")
stdio.fflush(0)
p1a_reg: int = 0
p1a_skp: int = 0
p1a_fl: int = 0
@@ -327,11 +323,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(tr_r._global_names)
if tr_r._nonlocal_names is not None:
stdlib.free(tr_r._nonlocal_names)
stdlib.free(src_buf_r)
stdio.printf("[Phase1a] 完成: 注册=%d 跳过=%d 失败=%d\n", p1a_reg, p1a_skp, p1a_fl)
# ============================================================
# Phase 1b: 全量翻译struct 已注册,走 existing 路径翻译方法体)
# ============================================================
@@ -354,32 +347,30 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
continue
# 检查 SHA1 是否在翻译集合中(按需翻译:只翻译可达的文件)
in_set: int = 0
if use_reachable != 0:
if StubMerger._is_in_sha1_set(sha1, reachable_set, reachable_count) == 0:
skipped += 1
continue
in_set = StubMerger._is_in_sha1_set(sha1, reachable_set, reachable_count)
else:
if StubMerger._is_in_sha1_set(sha1, sha1_set, set_count) == 0:
skipped += 1
continue
in_set = StubMerger._is_in_sha1_set(sha1, sha1_set, set_count)
if in_set == 0:
skipped += 1
continue
# 构造 stub 路径: {temp_dir}/{sha1}.stub.ll
dir_len: t.CSizeT = string.strlen(temp_dir)
sha1_len: t.CSizeT = string.strlen(sha1)
stub_path: bytes = stdlib.malloc(dir_len + sha1_len + 16)
stub_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "stub.ll")
if stub_path is None:
failed += 1
continue
viperlib.snprintf(stub_path, dir_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, sha1)
# 检查 stub 是否已存在(按需翻译:跳过已存在的)
sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R)
if not sf.closed:
sf.close()
# 检查 text.ll 是否也存在(虚表扫描需要 text.ll
text_path: bytes = stdlib.malloc(dir_len + sha1_len + 16)
text_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "text.ll")
if text_path is not None:
viperlib.snprintf(text_path, dir_len + sha1_len + 16, "%s/%s.text.ll", temp_dir, sha1)
tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
if not tf.closed:
tf.close()
@@ -388,18 +379,27 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
continue
stdlib.free(text_path)
# text.ll 不存在,需要重新翻译
stdio.printf("[Phase1] text.ll 不存在,重新翻译: %s (sha1=%s)\n", entry.RelPath, sha1)
rp: str = entry.RelPath
stdio.printf("[Phase1] text.ll 不存在,重新翻译: %s (sha1=%s)\n", rp, sha1)
else:
# stub 不存在,需要翻译
stdio.printf("[Phase1] 翻译: %s (sha1=%s)\n", entry.RelPath, sha1)
rp: str = entry.RelPath
stdio.printf("[Phase1] 翻译: %s (sha1=%s)\n", rp, sha1)
stdio.fflush(0)
stdlib.free(stub_path)
# 读取文件内容
file_path: str = entry.Path
f: fileio.File | t.CPtr = fileio.File(file_path, fileio.MODE.R)
if f is None:
stdio.printf("[Phase1] 无法打开(None): %s\n", file_path)
stdio.fflush(0)
failed += 1
continue
if f.closed:
stdio.printf("[Phase1] 无法打开: %s\n", file_path)
stdio.fflush(0)
failed += 1
continue
@@ -413,6 +413,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
f.close()
if bytes_read <= 0:
stdio.printf("[Phase1] 读取失败: %s\n", file_path)
stdio.fflush(0)
stdlib.free(src_buf)
failed += 1
continue
@@ -432,10 +433,25 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
tree: ast.AST | t.CPtr = ast.parse_tokens(mb, tokens)
if tree is None:
stdio.printf("[Phase1] AST 解析失败: %s\n", file_path)
stdio.fflush(0)
stdlib.free(src_buf)
failed += 1
continue
# 生成 .pyi 存根文件(直接遍历 AST不依赖 PythonToStubConverter
pyi_buf: bytes = stdlib.malloc(PYI_BUF_SIZE)
if pyi_buf is not None:
pyi_pos: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree, entry.RelPath, pyi_buf, PYI_BUF_SIZE)
if pyi_pos > 0:
pyi_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "pyi")
if pyi_path is not None:
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W)
if not pf.closed:
pf.write(pyi_buf, pyi_pos)
pf.close()
stdlib.free(pyi_path)
stdlib.free(pyi_buf)
# 翻译 AST → LLVM IR
tr: HandlesTranslator.Translator | t.CPtr = HandlesTranslator.Translator()
if tr is None:
@@ -474,9 +490,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# save stub.ll
dir_len_p1: t.CSizeT = string.strlen(temp_dir)
stub_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32)
stub_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "stub.ll")
if stub_path_p1 is not None:
viperlib.snprintf(stub_path_p1, dir_len_p1 + 32, "%s/%s.stub.ll", temp_dir, sha1)
sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W)
if not sf_p1.closed:
sf_p1.write(stub_buf, stub_len)
@@ -498,9 +513,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
text_len: t.CSizeT = string.strlen(text_buf)
# save text.ll
text_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32)
text_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll")
if text_path_p1 is not None:
viperlib.snprintf(text_path_p1, dir_len_p1 + 32, "%s/%s.text.ll", temp_dir, sha1)
tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W)
if not tf_p1.closed:
tf_p1.write(text_buf, text_len)
@@ -509,9 +523,8 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
stdlib.free(text_buf)
# save dependencies (_imported_modules) for Phase B
deps_path_p1: bytes = stdlib.malloc(dir_len_p1 + 32)
deps_path_p1: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
if deps_path_p1 is not None:
viperlib.snprintf(deps_path_p1, dir_len_p1 + 32, "%s/%s.deps.txt", temp_dir, sha1)
df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W)
if not df_p1.closed:
if tr._imported_modules is not None:

View File

@@ -268,6 +268,25 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
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")
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_IR_SIZE: t.CSizeT = 262144
td_len_pa: t.CSizeT = string.strlen(temp_dir)
@@ -294,10 +313,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB)
stub_len_a: t.CSizeT = string.strlen(stub_buf_a)
# save stub.ll
stub_path_a: bytes = stdlib.malloc(td_len_pa + 32)
# save stub.ll (切片路径: temp_dir/{sha1前缀}/{sha1}.stub.ll)
stub_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "stub.ll")
if stub_path_a is not None:
viperlib.snprintf(stub_path_a, td_len_pa + 32, "%s/%s.stub.ll", temp_dir, ent.Sha1)
sf_a: fileio.File | t.CPtr = fileio.File(stub_path_a, fileio.MODE.W)
if not sf_a.closed:
sf_a.write(stub_buf_a, stub_len_a)
@@ -312,10 +330,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT)
text_len_a: t.CSizeT = string.strlen(text_buf_a)
# save text.ll
text_path_a: bytes = stdlib.malloc(td_len_pa + 32)
# save text.ll (切片路径)
text_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll")
if text_path_a is not None:
viperlib.snprintf(text_path_a, td_len_pa + 32, "%s/%s.text.ll", temp_dir, ent.Sha1)
tf_a: fileio.File | t.CPtr = fileio.File(text_path_a, fileio.MODE.W)
if not tf_a.closed:
tf_a.write(text_buf_a, text_len_a)
@@ -323,10 +340,9 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(text_path_a)
stdlib.free(text_buf_a)
# save dependencies (_imported_modules) for Phase B
deps_path_a: bytes = stdlib.malloc(td_len_pa + 32)
# save dependencies (_imported_modules) for Phase B (切片路径)
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "deps.txt")
if deps_path_a is not None:
viperlib.snprintf(deps_path_a, td_len_pa + 32, "%s/%s.deps.txt", temp_dir, ent.Sha1)
df_a: fileio.File | t.CPtr = fileio.File(deps_path_a, fileio.MODE.W)
if not df_a.closed:
if tr_a._imported_modules is not None:
@@ -369,15 +385,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
if ent is None or ent.Path is None or ent.Sha1 is None:
continue
stdio.printf("[Phase B] %s\n", ent.Path)
# 组合本地 stub + 所有依赖 stub + 本地 text → 完整 IR
stdio.printf("[Phase B] malloc %d bytes...\n", COMBINED_IR_SIZE)
combined_ir: bytes = stdlib.malloc(COMBINED_IR_SIZE)
if combined_ir is None:
stdio.printf("[Phase B] combined_ir 分配失败: %s\n", ent.Path)
continue
stdio.printf("[Phase B] malloc OK, calling BuildCombinedIR...\n")
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
if combined_len == 0:
stdio.printf("[Phase B] BuildCombinedIR 失败: %s\n", ent.Path)
@@ -397,26 +409,34 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# 构造 .obj 路径,检测是否是 main 模块test_main.py 或 main.py
od_len: t.CSizeT = string.strlen(output_dir)
sha1_len: t.CSizeT = string.strlen(ent.Sha1)
need: t.CSizeT = od_len + 1 + sha1_len + 6
is_main_mod: int = 0
if string.strstr(ent.Path, "test_main.py") is not None:
is_main_mod = 1
elif string.strstr(ent.Path, "main.py") is not None:
is_main_mod = 1
if is_main_mod != 0:
viperlib.snprintf(main_obj_path, 512, "%s/%s.obj", output_dir, ent.Sha1)
else:
if obj_pos + need < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
viperlib.snprintf(obj_paths + obj_pos, need, "%s/%s.obj", output_dir, ent.Sha1)
obj_pos += od_len + 1 + sha1_len + 4
obj_paths[obj_pos] = '\0'
# 切片路径: output_dir/{sha1前缀}/{sha1}.obj
obj_path_sliced: str = StubMerger._sliced_path(output_dir, od_len, ent.Sha1, "obj")
if obj_path_sliced is not None:
op_sliced_len: t.CSizeT = string.strlen(obj_path_sliced)
if is_main_mod != 0:
# main 模块: 复制到 main_obj_path确保链接时 main 在最前)
if op_sliced_len < 512:
string.strcpy(main_obj_path, obj_path_sliced)
else:
stdio.printf("[Phase B] 警告: main_obj_path 缓冲区不足\n")
else:
stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n")
# 其他模块: 追加到 obj_paths
if obj_pos + op_sliced_len + 2 < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
string.strcpy(obj_paths + obj_pos, obj_path_sliced)
obj_pos += op_sliced_len
obj_paths[obj_pos] = '\0'
else:
stdio.printf("[Phase B] 警告: .obj 路径缓冲区不足\n")
stdlib.free(obj_path_sliced)
stdio.printf("[Phase B] 编译完成: %d/%d\n", compiled_count, file_count)
@@ -503,9 +523,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# 检查是否为声明文件(只有 declare 没有实质 define
# 判断方法: text.ll 中若有混淆函数 define含 @\")则为实现文件
is_decl_mi: int = -1
tpath_mi: bytes = stdlib.malloc(td_len_mi + 32)
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
if tpath_mi is not None:
viperlib.snprintf(tpath_mi, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi)
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
if not tf_mi.closed:
is_decl_mi = 1
@@ -541,11 +560,8 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
tf_mi.close()
stdlib.free(tpath_mi)
if is_decl_mi == 1:
stdio.printf("[Phase B+] 跳过(声明文件): %s (sha1=%s)\n", src_fp_mi, inc_sha1_mi)
continue
stdio.printf("[Phase B+] 编译缺失 includes: %s (sha1=%s)\n", src_fp_mi, inc_sha1_mi)
# 尝试 BuildCombinedIRstub/text 应已由 Phase1 生成)
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
inc_combined_len_mi: t.CSizeT = 0
@@ -554,7 +570,6 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
# 如果 stub/text 不存在,翻译源文件并保存 stub + text然后重试
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
stdio.printf("[Phase B+] stub/text 不存在,翻译: %s\n", src_fp_mi)
# 计算 includes 文件的包名(相对 includes_dir 的目录部分)
inc_pkg_mi: str = None
if string.strlen(src_fp_mi) > inc_dir_len_mi + 1:
@@ -563,28 +578,26 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
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
# 保存 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: bytes = stdlib.malloc(td_len_mi + 32)
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
if inc_stub_path is not None:
viperlib.snprintf(inc_stub_path, td_len_mi + 32, "%s/%s.stub.ll", temp_dir, inc_sha1_mi)
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
# 保存 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: bytes = stdlib.malloc(td_len_mi + 32)
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
if inc_text_path is not None:
viperlib.snprintf(inc_text_path, td_len_mi + 32, "%s/%s.text.ll", temp_dir, inc_sha1_mi)
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)
@@ -611,17 +624,19 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
inc_compiled += 1
# 添加到 obj_paths
# 添加到 obj_paths (切片路径)
od_len_mi: t.CSizeT = string.strlen(output_dir)
sha1_len_mi: t.CSizeT = 16
need_mi: t.CSizeT = od_len_mi + 1 + sha1_len_mi + 6
if obj_pos + need_mi < OBJ_PATHS_SIZE:
if obj_pos > 0:
obj_paths[obj_pos] = ' '
obj_pos += 1
viperlib.snprintf(obj_paths + obj_pos, need_mi, "%s/%s.obj", output_dir, inc_sha1_mi)
obj_pos += od_len_mi + 1 + sha1_len_mi + 4
obj_paths[obj_pos] = '\0'
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)

View File

@@ -15,6 +15,8 @@ import lib.core.IncludesScanner as IncludesScanner
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesImports as HandlesImports
import lib.core.Handles.HandlesTranslator as HandlesTranslator
import lib.core.BuildPipeline as BuildPipeline
import lib.Projectrans.Config as Config
# ============================================================
@@ -42,6 +44,178 @@ STUB_READ_BUF_SIZE: t.CDefine = 262144
MAX_INCLUDES: t.CDefine = 256
# ============================================================
# _sliced_path - 构建切片路径stdlib.malloc 分配,调用者负责 free
#
# 根据 Config.Sha1SliceLevel 将文件分散到 SHA1 前缀子目录:
# level=0 → {temp_dir}/{sha1}.{ext}
# level=1 → {temp_dir}/b7/{sha1}.{ext}
# level=2 → {temp_dir}/b7/90/{sha1}.{ext}
#
# 自动调用 BuildPipeline.ensure_dir 创建子目录level>0 时)。
#
# Args:
# temp_dir: 基础目录
# td_len: temp_dir 长度(避免重复 strlen
# sha1: SHA1 字符串
# ext: 文件扩展名(如 "stub.ll"
#
# Returns:
# 完整路径stdlib.malloc 分配,需 stdlib.freeNone 失败
# ============================================================
def _sliced_path(temp_dir: str, td_len: t.CSizeT, sha1: str, ext: str) -> str:
"""构建切片路径stdlib.malloc 分配,调用者负责 free
level>0 时自动调用 ensure_dir 创建子目录。
"""
if temp_dir is None or sha1 is None or ext is None:
return None
sha1_len: t.CSizeT = string.strlen(sha1)
ext_len: t.CSizeT = string.strlen(ext)
# 子目录前缀缓冲区(最多 3 层 = 8 字节 + null = 16 足够)
SUBDIR_BUF_SIZE: t.CSizeT = 16
subdir_buf: bytes = stdlib.malloc(SUBDIR_BUF_SIZE)
if subdir_buf is None:
return None
subdir_buf[0] = '\0'
sub_len: t.CSizeT = 0
level: int = Config.Sha1SliceLevel
if level > 0:
li: int = 0
while li < level:
if li > 0:
subdir_buf[sub_len] = '/'
sub_len += 1
idx: int = li * 2
subdir_buf[sub_len] = sha1[idx]
subdir_buf[sub_len + 1] = sha1[idx + 1]
sub_len += 2
li += 1
subdir_buf[sub_len] = '\0'
# 确保子目录存在: {temp_dir}/{subdir}
# 不创建目录会导致 fileio.File(MODE.W) 静默失败file.closed==True
# 进而 BuildCombinedIR 读不到文件返回 0"BuildCombinedIR 失败")。
dir_path_len: t.CSizeT = td_len + sub_len + 2
dir_path: bytes = stdlib.malloc(dir_path_len)
if dir_path is not None:
viperlib.snprintf(dir_path, dir_path_len, "%s/%s", temp_dir, subdir_buf)
BuildPipeline.ensure_dir(dir_path)
stdlib.free(dir_path)
# 构建完整路径
path: str = None
path_len: t.CSizeT = 0
if sub_len > 0:
path_len = td_len + sub_len + sha1_len + ext_len + 4
path = stdlib.malloc(path_len)
if path is not None:
viperlib.snprintf(path, path_len, "%s/%s/%s.%s", temp_dir, subdir_buf, sha1, ext)
else:
path_len = td_len + sha1_len + ext_len + 3
path = stdlib.malloc(path_len)
if path is not None:
viperlib.snprintf(path, path_len, "%s/%s.%s", temp_dir, sha1, ext)
stdlib.free(subdir_buf)
return path
# ============================================================
# _collect_stub_sha1s - 递归扫描子目录,收集 .stub.ll 文件的 SHA1
#
# 根据 level 递归扫描子目录:
# level=0 → 扫描 {base_dir}/*.stub.ll从文件名提取 SHA1
# level>0 → 扫描 {base_dir}/* 的子目录,对每个子目录递归调用
#
# Args:
# base_dir: 当前扫描目录
# bd_len: base_dir 长度
# level: 剩余递归层数
# out_arr: 输出数组(每个 SHA1 17 字节 = 16字符 + null
# out_count: 当前已收集数量
# max_count: 最大数量
#
# Returns:
# 收集后的总数量
# ============================================================
def _collect_stub_sha1s(base_dir: str, bd_len: t.CSizeT, level: int,
out_arr: str, out_count: int, max_count: int) -> int:
"""递归扫描子目录,收集 .stub.ll 文件的 SHA1"""
if base_dir is None or out_arr is None:
return out_count
if out_count >= max_count:
return out_count
find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is None:
return out_count
string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__())
if level <= 0:
# 扫描 {base_dir}/*.stub.ll
pattern: bytes = stdlib.malloc(bd_len + 16)
if pattern is None:
stdlib.free(find_data)
return out_count
viperlib.snprintf(pattern, bd_len + 16, "%s/*.stub.ll", base_dir)
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
stdlib.free(pattern)
if handle != win32base.INVALID_HANDLE_VALUE:
while 1:
if out_count >= max_count:
break
fname: str = find_data.cFileName
if fname is not None:
if fname[0] != '\0':
# 从文件名提取 SHA1前 16 字符)
string.strncpy(out_arr + out_count * 17, fname, 16)
out_arr[out_count * 17 + 16] = '\0'
out_count += 1
if win32file.FindNextFileA(handle, find_data) == 0:
break
win32file.FindClose(handle)
else:
# 扫描 {base_dir}/* 的子目录
pattern = stdlib.malloc(bd_len + 4)
if pattern is None:
stdlib.free(find_data)
return out_count
viperlib.snprintf(pattern, bd_len + 4, "%s/*", base_dir)
handle = win32file.FindFirstFileA(pattern, find_data)
stdlib.free(pattern)
if handle != win32base.INVALID_HANDLE_VALUE:
while 1:
# 检查是否是目录FILE_ATTRIBUTE_DIRECTORY = 0x10 = 16
attrs: t.CUInt32T = find_data.dwFileAttributes
if (attrs & 16) != 0:
fname = find_data.cFileName
if fname is not None:
# 跳过 "." 和 ".."
is_dot: int = 0
if fname[0] == '.':
if fname[1] == '\0':
is_dot = 1
elif fname[1] == '.' and fname[2] == '\0':
is_dot = 1
if is_dot == 0:
# 构建子目录路径并递归扫描
fname_len: t.CSizeT = string.strlen(fname)
sub_dir: str = stdlib.malloc(bd_len + fname_len + 2)
if sub_dir is not None:
viperlib.snprintf(sub_dir, bd_len + fname_len + 2, "%s/%s", base_dir, fname)
sub_dir_len: t.CSizeT = string.strlen(sub_dir)
out_count = _collect_stub_sha1s(sub_dir, sub_dir_len, level - 1, out_arr, out_count, max_count)
stdlib.free(sub_dir)
if win32file.FindNextFileA(handle, find_data) == 0:
break
win32file.FindClose(handle)
stdlib.free(find_data)
return out_count
# ============================================================
# _load_includes_sha1_set - 读取 _sha1_map.txt收集 includes/ 开头的 SHA1
#
@@ -68,7 +242,6 @@ def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
# 打开文件
f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.R)
if f.closed:
stdio.printf("[StubMerger] _sha1_map.txt 不存在: %s\n", map_path)
return -1
# 读取内容(使用 stdlib.malloc 避免 mbuddy 池耗尽)
@@ -81,7 +254,10 @@ def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
f.close()
if bytes_read <= 0:
return -1
content[bytes_read] = '\0'
if bytes_read < MAP_BUF_SIZE:
content[bytes_read] = '\0'
else:
content[MAP_BUF_SIZE - 1] = '\0'
# 解析行: {sha1}:{rel_path}
count: int = 0
@@ -163,7 +339,6 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
# 打开文件写入CREATE_ALWAYS
f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.W)
if f.closed:
stdio.printf("[Phase1] 无法写入 _sha1_map.txt: %s\n", map_path)
return 1
# 写入每个 include 条目: {sha1}:includes/{rel_path}\n
@@ -189,7 +364,6 @@ def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
written_count += 1
f.close()
stdio.printf("[Phase1] 已写入 _sha1_map.txt (%d 个 includes)\n", written_count)
return 0
@@ -381,11 +555,9 @@ def _LoadAndAppendStub(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None:
return out_pos
sha1_len: t.CSizeT = string.strlen(dep_sha1)
dep_path: bytes = stdlib.malloc(td_len + sha1_len + 16)
dep_path: str = _sliced_path(temp_dir, td_len, dep_sha1, "stub.ll")
if dep_path is None:
return out_pos
viperlib.snprintf(dep_path, td_len + sha1_len + 16, "%s/%s.stub.ll", temp_dir, dep_sha1)
df_ls: fileio.File | t.CPtr = fileio.File(dep_path, fileio.MODE.R)
if df_ls.closed:
stdlib.free(dep_path)
@@ -541,11 +713,9 @@ def _LoadAndAppendTextDeclares(temp_dir: str, td_len: t.CSizeT, dep_sha1: str,
if temp_dir is None or dep_sha1 is None or dep_buf is None or out_buf is None:
return out_pos
sha1_len_lt: t.CSizeT = string.strlen(dep_sha1)
text_path: bytes = stdlib.malloc(td_len + sha1_len_lt + 16)
text_path: str = _sliced_path(temp_dir, td_len, dep_sha1, "text.ll")
if text_path is None:
return out_pos
viperlib.snprintf(text_path, td_len + sha1_len_lt + 16, "%s/%s.text.ll", temp_dir, dep_sha1)
tf_lt: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
if tf_lt.closed:
stdlib.free(text_path)
@@ -738,11 +908,13 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
count: int = 0
pos: t.CSizeT = 0
# 在循环外分配 sha1 缓冲区,避免反复 malloc/free 导致堆碎片化
sha1: t.CChar | t.CPtr = stdlib.malloc(17)
if sha1 is None:
stdlib.free(map_buf)
return 0
while pos < map_br and count < MAX_INCLUDES:
# 提取 SHA116 hex
sha1: t.CChar | t.CPtr = stdlib.malloc(17)
if sha1 is None:
break
string.strncpy(sha1, map_buf + pos, 16)
sha1[16] = '\0'
pos += 16
@@ -783,7 +955,7 @@ def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
mod_list[idx2 + 63] = '\0'
stdlib.free(mod_name)
count += 1
stdlib.free(sha1)
stdlib.free(sha1)
stdlib.free(map_buf)
return count
@@ -1104,9 +1276,8 @@ def _BuildReachableSha1Set(mb: memhub.MemBuddy | t.CPtr, source_dir: str,
reachable_count = _AddSha1ToSet(reachable_set, reachable_count, found_sha1)
# 读取 .deps.txt 追加到 worklist
deps_path: bytes = stdlib.malloc(td_len_r + 33)
deps_path: str = _sliced_path(temp_dir, td_len_r, found_sha1, "deps.txt")
if deps_path is not None:
viperlib.snprintf(deps_path, td_len_r + 33, "%s/%s.deps.txt", temp_dir, found_sha1)
df: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R)
if not df.closed:
deps_buf: bytes = stdlib.malloc(2048)
@@ -1155,16 +1326,14 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
if temp_dir is None or local_sha1 is None or out_buf is None or out_size == 0:
return 0
stdio.printf("[BuildCombinedIR] start: sha1=%s\n", local_sha1)
td_len: t.CSizeT = string.strlen(temp_dir)
out_buf[0] = '\0'
out_pos: t.CSizeT = 0
# 1. 读取并追加本地 stub.ll含 header
stub_path: bytes = stdlib.malloc(td_len + 32)
stub_path: str = _sliced_path(temp_dir, td_len, local_sha1, "stub.ll")
if stub_path is None:
return 0
viperlib.snprintf(stub_path, td_len + 32, "%s/%s.stub.ll", temp_dir, local_sha1)
sf: fileio.File | t.CPtr = fileio.File(stub_path, fileio.MODE.R)
if sf.closed:
stdlib.free(stub_path)
@@ -1177,7 +1346,6 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
stub_br: t.CInt64T = sf.read_all(stub_content, STUB_READ_BUF_SIZE)
sf.close()
stdlib.free(stub_path)
stdio.printf("[BuildCombinedIR] stub read: %d bytes\n", stub_br)
if stub_br <= 0:
stdlib.free(stub_content)
return 0
@@ -1207,7 +1375,6 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
stub_content[ext_off + 6] = ' '
stub_content[ext_off + 7] = ' '
fix_pos = ext_off + 8
stdio.printf("[BuildCombinedIR] stub_fix done, slen=%d\n", slen)
# 直接复制修复后的 stub 内容
if out_pos + slen + 2 < out_size:
string.strcpy(out_buf + out_pos, stub_content)
@@ -1230,9 +1397,8 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
# 2b. 读取 deps.txt 获取导入模块名集合
deps_buf: str = None
deps_loaded: int = 0
deps_path: bytes = stdlib.malloc(td_len + 32)
deps_path: str = _sliced_path(temp_dir, td_len, local_sha1, "deps.txt")
if deps_path is not None:
viperlib.snprintf(deps_path, td_len + 32, "%s/%s.deps.txt", temp_dir, local_sha1)
df_deps: fileio.File | t.CPtr = fileio.File(deps_path, fileio.MODE.R)
if not df_deps.closed:
deps_buf = stdlib.malloc(4096)
@@ -1247,52 +1413,41 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
df_deps.close()
stdlib.free(deps_path)
# 2c. 扫描 temp_dir 中所有 .stub.ll按需加载
pattern: bytes = stdlib.malloc(td_len + 16)
if pattern is not None:
viperlib.snprintf(pattern, td_len + 16, "%s/*.stub.ll", temp_dir)
find_data: win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(win32file.WIN32_FIND_DATAA.__sizeof__())
if find_data is not None:
string.memset(find_data, 0, win32file.WIN32_FIND_DATAA.__sizeof__())
handle: win32base.HANDLE = win32file.FindFirstFileA(pattern, find_data)
if handle != win32base.INVALID_HANDLE_VALUE:
dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE)
if dep_buf is not None:
while 1:
fname: str = find_data.cFileName
if fname is not None:
dep_sha1: str = stdlib.malloc(17)
if dep_sha1 is not None:
string.strncpy(dep_sha1, fname, 16)
dep_sha1[16] = '\0'
if string.strcmp(dep_sha1, local_sha1) != 0:
should_load: int = 0
# 检查是否在 includes 映射中
is_include: int = 0
if inc_count > 0:
for ii in range(inc_count):
idx_ii: t.CSizeT = t.CSizeT(ii) * 17
if string.strcmp(sha1_arr + idx_ii, dep_sha1) == 0:
is_include = 1
if deps_loaded != 0:
idx_mi: t.CSizeT = t.CSizeT(ii) * 64
if HandlesImports.is_module_imported(deps_buf, mod_arr + idx_mi) != 0:
should_load = 1
break
if is_include == 0:
# 非 includes stub用户文件总是加载
should_load = 1
if should_load != 0:
out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos)
out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos)
stdlib.free(dep_sha1)
if win32file.FindNextFileA(handle, find_data) == 0:
break
if dep_buf is not None:
stdlib.free(dep_buf)
win32file.FindClose(handle)
stdlib.free(find_data)
stdlib.free(pattern)
# 2c. 递归扫描 temp_dir 中所有 .stub.ll按需加载
all_sha1_arr: str = stdlib.malloc(MAX_INCLUDES_SHA1 * 17)
all_count: int = 0
if all_sha1_arr is not None:
string.memset(all_sha1_arr, 0, MAX_INCLUDES_SHA1 * 17)
all_count = _collect_stub_sha1s(temp_dir, td_len, Config.Sha1SliceLevel, all_sha1_arr, 0, MAX_INCLUDES_SHA1)
if all_count > 0:
dep_buf: bytes = stdlib.malloc(STUB_READ_BUF_SIZE)
if dep_buf is not None:
si: int = 0
while si < all_count:
dep_sha1: str = all_sha1_arr + t.CSizeT(si) * 17
if string.strcmp(dep_sha1, local_sha1) != 0:
should_load: int = 0
# 检查是否在 includes 映射中
is_include: int = 0
if inc_count > 0:
for ii in range(inc_count):
idx_ii: t.CSizeT = t.CSizeT(ii) * 17
if string.strcmp(sha1_arr + idx_ii, dep_sha1) == 0:
is_include = 1
if deps_loaded != 0:
idx_mi: t.CSizeT = t.CSizeT(ii) * 64
if HandlesImports.is_module_imported(deps_buf, mod_arr + idx_mi) != 0:
should_load = 1
break
if is_include == 0:
# 非 includes stub用户文件总是加载
should_load = 1
if should_load != 0:
out_pos = _LoadAndAppendStub(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos)
out_pos = _LoadAndAppendTextDeclares(temp_dir, td_len, dep_sha1, dep_buf, out_buf, out_size, out_pos)
si += 1
stdlib.free(dep_buf)
stdlib.free(all_sha1_arr)
# 2d. 验证 deps.txt 中所有依赖模块的 stub 文件都存在fail-fast
# 避免到 llc 才报 undefined value 错误。
@@ -1333,9 +1488,8 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
break
if found_s is not None:
# 检查 stub 文件是否存在
chk_path: bytes = stdlib.malloc(td_len + 32)
chk_path: str = _sliced_path(temp_dir, td_len, found_s, "stub.ll")
if chk_path is not None:
viperlib.snprintf(chk_path, td_len + 32, "%s/%s.stub.ll", temp_dir, found_s)
chk_f: fileio.File | t.CPtr = fileio.File(chk_path, fileio.MODE.R)
if chk_f.closed:
stdio.printf("[FATAL][BuildCombinedIR] 依赖模块 '%s' (sha1=%s) 的 stub 文件不存在: %s,立即终止编译\n", mod_nm, found_s, chk_path)
@@ -1345,10 +1499,9 @@ def BuildCombinedIR(temp_dir: str, local_sha1: str,
stdlib.free(mod_nm)
# 3. 读取并追加本地 text.ll行级去重跳过 stub.ll 中已存在的定义)
text_path: bytes = stdlib.malloc(td_len + 32)
text_path: str = _sliced_path(temp_dir, td_len, local_sha1, "text.ll")
if text_path is None:
return out_pos
viperlib.snprintf(text_path, td_len + 32, "%s/%s.text.ll", temp_dir, local_sha1)
tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
if tf.closed:
stdlib.free(text_path)