修正了种子编译器的错误

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

@@ -18,8 +18,9 @@ _mbuddy: memhub.MemManager | t.CPtr
# 配置值(从 project.vpj 加载)
SourceDir: str
TempDir: str
OutputDir: str
BuildDir: str
TempDir: str # = {BuildDir}/temp自动计算
OutputDir: str # = {BuildDir}/output自动计算
ProjectName: str
ProjectVersion: str
CompilerCmd: str
@@ -29,7 +30,7 @@ LinkerFlags: str # 链接器参数(空格分隔,从 linker.flags
LinkerOutput: str
TargetTriple: str
TargetDataLayout: str
SliceLevel: t.CInt
Sha1SliceLevel: t.CInt # SHA1 切片层数(目录分散等级)
StrictMode: t.CInt
IncludesDir: str # includes 目录路径(从 includes 数组首元素)
@@ -43,9 +44,9 @@ def Load_project_config(path: str) -> int:
Returns:
0 表示成功,非 0 表示失败
"""
global SourceDir, TempDir, OutputDir, ProjectName, ProjectVersion
global SourceDir, BuildDir, TempDir, OutputDir, ProjectName, ProjectVersion
global CompilerCmd, CompilerFlags, LinkerCmd, LinkerFlags, LinkerOutput
global TargetTriple, TargetDataLayout, SliceLevel, StrictMode
global TargetTriple, TargetDataLayout, Sha1SliceLevel, StrictMode
global IncludesDir
if path is None:
@@ -79,8 +80,12 @@ def Load_project_config(path: str) -> int:
# 读取顶层字段
SourceDir = root["source_dir"].as_string() if root["source_dir"] is not None else None
TempDir = root["temp_dir"].as_string() if root["temp_dir"] is not None else None
OutputDir = root["output_dir"].as_string() if root["output_dir"] is not None else None
# build_dir: 统一构建目录(默认 ./.tpv_buildtemp 和 output 作为其子目录
bd_val: JsonValue | t.CPtr = root["build_dir"]
if bd_val is not None and bd_val.is_string():
BuildDir = bd_val.as_string()
else:
BuildDir = "./.tpv_build"
ProjectName = root["name"].as_string() if root["name"] is not None else None
ProjectVersion = root["version"].as_string() if root["version"] is not None else None
@@ -108,11 +113,17 @@ def Load_project_config(path: str) -> int:
TargetDataLayout = target["datalayout"].as_string() if target["datalayout"] is not None else None
# 读取 options 子对象
# Sha1SliceLevel: SHA1 切片层数(默认 1每层取 SHA1 前 2 字符作为子目录)
# level=0 → 不切片,文件直接放 base_dir
# level=1 → b7/{sha1}.ext
# level=2 → b7/90/{sha1}.ext
options: JsonValue | t.CPtr = root["options"]
Sha1SliceLevel = 1
StrictMode = 1
if options is not None and options.is_object():
sl: JsonValue | t.CPtr = options["slice_level"]
sl: JsonValue | t.CPtr = options["sha1_slice_level"]
if sl is not None and sl.is_int():
SliceLevel = sl.as_int()
Sha1SliceLevel = sl.as_int()
sm: JsonValue | t.CPtr = options["strict_mode"]
if sm is not None and sm.is_bool():
StrictMode = 1 if sm.as_bool() else 0
@@ -241,9 +252,10 @@ def _join_path(rel: str, project_dir: str) -> str:
def resolve_paths(project_dir: str) -> int:
"""解析并规范化工程路径src/temp/output/includes
"""解析并规范化工程路径src/build/includes
将 project.vpj 中的相对路径(以 ./ 开头)转换为基于 project_dir 的路径。
BuildDir 解析后TempDir = {BuildDir}/tempOutputDir = {BuildDir}/output。
Args:
project_dir: 工程根目录project.vpj 所在目录)
@@ -251,15 +263,28 @@ def resolve_paths(project_dir: str) -> int:
Returns:
0 表示成功,非 0 表示失败
"""
global SourceDir, TempDir, OutputDir, IncludesDir
global SourceDir, BuildDir, TempDir, OutputDir, IncludesDir
if project_dir is None:
return 1
if _mbuddy is None:
return 1
SourceDir = _join_path(SourceDir, project_dir)
TempDir = _join_path(TempDir, project_dir)
OutputDir = _join_path(OutputDir, project_dir)
BuildDir = _join_path(BuildDir, project_dir)
# TempDir = {BuildDir}/temp
if BuildDir is not None:
bd_len: t.CSizeT = string.strlen(BuildDir)
temp_buf: str = _mbuddy.alloc(bd_len + 8)
if temp_buf is not None:
viperlib.snprintf(temp_buf, bd_len + 8, "%s/temp", BuildDir)
TempDir = temp_buf
# OutputDir = {BuildDir}/output
output_buf: str = _mbuddy.alloc(bd_len + 8)
if output_buf is not None:
viperlib.snprintf(output_buf, bd_len + 8, "%s/output", BuildDir)
OutputDir = output_buf
# includes 路径可能是 ../includes 形式,需要基于 project_dir 解析
if IncludesDir is not None:
IncludesDir = _join_path(IncludesDir, project_dir)
@@ -287,6 +312,8 @@ def print_config():
stdio.printf(" project: %s v%s\n", ProjectName, ProjectVersion if ProjectVersion is not None else "?")
if SourceDir is not None:
stdio.printf(" source_dir: %s\n", SourceDir)
if BuildDir is not None:
stdio.printf(" build_dir: %s\n", BuildDir)
if TempDir is not None:
stdio.printf(" temp_dir: %s\n", TempDir)
if OutputDir is not None:
@@ -296,4 +323,48 @@ def print_config():
if LinkerCmd is not None:
stdio.printf(" linker: %s -> %s\n", LinkerCmd, LinkerOutput if LinkerOutput is not None else "?")
if IncludesDir is not None:
stdio.printf(" includes: %s\n", IncludesDir)
stdio.printf(" includes: %s\n", IncludesDir)
stdio.printf(" sha1_slice_level: %d\n", Sha1SliceLevel)
# ============================================================
# slice_subdir - 根据 SHA1 和切片层数返回子目录路径
#
# 每层取 SHA1 的 2 个字符作为子目录名:
# level=0 → None不切片
# level=1 → "b7"
# level=2 → "b7/90"
# level=3 → "b7/90/23"
#
# Args:
# sha1: SHA1 字符串(至少 2*level 字符)
# level: 切片层数
#
# Returns:
# 子目录路径字符串mbuddy 分配无需释放level<=0 时返回 None
# ============================================================
def slice_subdir(sha1: str, level: int) -> str:
"""根据 SHA1 和切片层数返回子目录路径"""
if level <= 0 or sha1 is None:
return None
if _mbuddy is None:
return None
# 每层 2 字符 + 分隔符,最后无分隔符 + null
# buf 大小: level * 2 + (level - 1) + 1 = level * 3
buf_len: t.CSizeT = t.CSizeT(level * 3)
buf: str = _mbuddy.alloc(buf_len)
if buf is None:
return None
pos: int = 0
i: int = 0
while i < level:
if i > 0:
buf[pos] = '/'
pos += 1
idx: int = i * 2
buf[pos] = sha1[idx]
buf[pos + 1] = sha1[idx + 1]
pos += 2
i += 1
buf[pos] = '\0'
return buf

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)

View File

@@ -425,9 +425,8 @@ def main() -> int:
if sf_stub_buf is not None:
tr.dump_ir(sf_stub_buf, SF_IR_SIZE, llvmlite.OUTPUT_STUB)
sf_stub_len: t.CSizeT = string.strlen(sf_stub_buf)
sf_stub_path: bytes = stdlib.malloc(td_len_sf + 32)
sf_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_sf, module_name, "stub.ll")
if sf_stub_path is not None:
viperlib.snprintf(sf_stub_path, td_len_sf + 32, "%s/%s.stub.ll", temp_dir, module_name)
sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W)
if not sf_f.closed:
sf_f.write(sf_stub_buf, sf_stub_len)
@@ -439,9 +438,8 @@ def main() -> int:
if sf_text_buf is not None:
tr.dump_ir(sf_text_buf, SF_IR_SIZE, llvmlite.OUTPUT_TEXT)
sf_text_len: t.CSizeT = string.strlen(sf_text_buf)
sf_text_path: bytes = stdlib.malloc(td_len_sf + 32)
sf_text_path: str = StubMerger._sliced_path(temp_dir, td_len_sf, module_name, "text.ll")
if sf_text_path is not None:
viperlib.snprintf(sf_text_path, td_len_sf + 32, "%s/%s.text.ll", temp_dir, module_name)
sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W)
if not sf_tf.closed:
sf_tf.write(sf_text_buf, sf_text_len)