fix(Phase2): Phase A 多遍重试修复同项目依赖翻译顺序
main.vp 先于其 import 的 mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析因依赖 text.ll 未生成而 fail-fast。新增 Translator._deps_pending + text.ll 存在性探测区分依赖未翻译/真错误,Phase A 循环改多遍,依赖就绪后下遍重译命中。
This commit is contained in:
1 parent
b5657b3790
commit
120a2d7ad7
3 files changed
+314
-82
No files matched your search
@@ -243,6 +243,13 @@ class CallGenMixin:
|
||||
# 第二遍:后缀匹配(.name)
|
||||
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
|
||||
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
|
||||
#
|
||||
# 修复:本模块 define 优先于跨模块 stub declare。
|
||||
# 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance)
|
||||
# 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀
|
||||
# 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被
|
||||
# bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针,
|
||||
# cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。
|
||||
cur = mod.FuncHead
|
||||
while cur is not None:
|
||||
cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
|
||||
@@ -257,6 +264,24 @@ class CallGenMixin:
|
||||
match = 0
|
||||
break
|
||||
if match == 1:
|
||||
if cur.IsDeclared == 0:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
# 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用)
|
||||
cur = mod.FuncHead
|
||||
while cur is not None:
|
||||
cur_name3: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
|
||||
if cur_name3 is not None:
|
||||
cur_len3: t.CSizeT = string.strlen(cur_name3)
|
||||
if cur_len3 > name_len + 1:
|
||||
suffix_start3: t.CSizeT = cur_len3 - name_len
|
||||
if cur_name3[suffix_start3 - 1] == '.':
|
||||
match3: int = 1
|
||||
for i in range(name_len):
|
||||
if cur_name3[suffix_start3 + i] != name[i]:
|
||||
match3 = 0
|
||||
break
|
||||
if match3 == 1:
|
||||
return cur
|
||||
cur = llvmlite.function_get_next(cur)
|
||||
return None
|
||||
@@ -564,6 +589,28 @@ class CallGenMixin:
|
||||
|
||||
return None
|
||||
|
||||
def _is_sha1_mangled_call(self, call_name: str) -> int:
|
||||
"""判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式)
|
||||
|
||||
C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0,
|
||||
不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。
|
||||
"""
|
||||
if call_name is None:
|
||||
return 0
|
||||
first_dot: t.CChar | t.CPtr = string.strchr(call_name, '.')
|
||||
if first_dot is None:
|
||||
return 0
|
||||
pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name))
|
||||
if pre_len != 16:
|
||||
return 0
|
||||
for hx in range(16):
|
||||
ch: int = call_name[hx]
|
||||
if ch < 48 or ch > 57:
|
||||
if ch < 97 or ch > 102:
|
||||
if ch < 65 or ch > 70:
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
builder: llvmlite.IRBuilder | t.CPtr,
|
||||
mod: llvmlite.LLVMModule | t.CPtr,
|
||||
@@ -2917,9 +2964,14 @@ class CallGenMixin:
|
||||
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
class_sha1: str,
|
||||
class_name: str,
|
||||
method_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""从依赖模块的 text.ll 中查找方法返回类型"""
|
||||
if pool is None or class_sha1 is None or class_name is None or method_name is None:
|
||||
method_name: str,
|
||||
use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr:
|
||||
"""从依赖模块的 text.ll 中查找方法返回类型
|
||||
|
||||
use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define,
|
||||
用于 new_lexer/tokenize 等模块函数;class_name 忽略)。
|
||||
"""
|
||||
if pool is None or class_sha1 is None or method_name is None:
|
||||
return None
|
||||
if self.TempDir is None or self.TempDirLen == 0:
|
||||
return None
|
||||
@@ -2968,16 +3020,24 @@ class CallGenMixin:
|
||||
else:
|
||||
read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0'
|
||||
|
||||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}"
|
||||
cls_len: t.CSizeT = string.strlen(class_name)
|
||||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}"
|
||||
cls_len: t.CSizeT = 0
|
||||
if class_name is not None:
|
||||
cls_len = string.strlen(class_name)
|
||||
meth_len: t.CSizeT = string.strlen(method_name)
|
||||
search_len: t.CSizeT = sha1_len + cls_len + meth_len + 4
|
||||
search_len: t.CSizeT = sha1_len + meth_len + 2
|
||||
if use_bare == 0:
|
||||
search_len = sha1_len + cls_len + meth_len + 4
|
||||
search_buf: bytes = stdlib.malloc(search_len)
|
||||
if search_buf is None:
|
||||
stdlib.free(read_buf)
|
||||
return None
|
||||
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
||||
class_sha1, class_name, method_name)
|
||||
if use_bare != 0:
|
||||
viperlib.snprintf(search_buf, search_len, "%s.%s",
|
||||
class_sha1, method_name)
|
||||
else:
|
||||
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
|
||||
class_sha1, class_name, method_name)
|
||||
search_str_len: t.CSizeT = string.strlen(search_buf)
|
||||
|
||||
# 在 text.ll 中搜索 define 行包含 search_buf
|
||||
@@ -3010,8 +3070,15 @@ class CallGenMixin:
|
||||
# 检查是否匹配 search_buf
|
||||
if name_start + search_str_len <= ls + ll:
|
||||
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
|
||||
# 匹配!提取返回类型: [ls+7, at_pos)
|
||||
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
||||
# 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾,
|
||||
# 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数
|
||||
name_end: t.CSizeT = name_start + search_str_len
|
||||
end_ch: int = 0
|
||||
if name_end < ls + ll:
|
||||
end_ch = read_buf[name_end]
|
||||
if end_ch == 34 or end_ch == 40 or end_ch == 0:
|
||||
# 匹配!提取返回类型: [ls+7, at_pos)
|
||||
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
|
||||
|
||||
pos = le + 1
|
||||
|
||||
@@ -3019,6 +3086,45 @@ class CallGenMixin:
|
||||
stdlib.free(read_buf)
|
||||
return result_ty
|
||||
|
||||
# ============================================================
|
||||
# _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成
|
||||
#
|
||||
# 用于区分跨模块返回类型精确解析失败的两种场景:
|
||||
# 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失)
|
||||
# 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译,
|
||||
# main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍
|
||||
# ============================================================
|
||||
def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
sha1: str) -> int:
|
||||
"""探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在"""
|
||||
if self.TempDir is None or self.TempDirLen == 0 or sha1 is None:
|
||||
return 0
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
if sha1_len < 2:
|
||||
return 0
|
||||
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
|
||||
path_buf: bytes = stdlib.malloc(path_len)
|
||||
subdir_buf: bytes = stdlib.malloc(3)
|
||||
if path_buf is None or subdir_buf is None:
|
||||
if path_buf is not None:
|
||||
stdlib.free(path_buf)
|
||||
if subdir_buf is not None:
|
||||
stdlib.free(subdir_buf)
|
||||
return 0
|
||||
subdir_buf[0] = sha1[0]
|
||||
subdir_buf[1] = sha1[1]
|
||||
subdir_buf[2] = '\0'
|
||||
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
|
||||
self.TempDir, subdir_buf, sha1)
|
||||
stdlib.free(subdir_buf)
|
||||
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
|
||||
exists: int = 0
|
||||
if not tf.closed:
|
||||
tf.close()
|
||||
exists = 1
|
||||
stdlib.free(path_buf)
|
||||
return exists
|
||||
|
||||
# ============================================================
|
||||
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
|
||||
#
|
||||
@@ -5997,6 +6103,71 @@ class CallGenMixin:
|
||||
re_inferred_ty: llvmlite.LLVMType | t.CPtr = self._infer_external_func_ret_ty(pool, orig_func_name)
|
||||
if re_inferred_ty is not None:
|
||||
call_ret_ty = re_inferred_ty
|
||||
# ============================================================
|
||||
# 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast)
|
||||
# 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数
|
||||
# (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32
|
||||
# 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃
|
||||
# (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare
|
||||
# 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。
|
||||
# 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。
|
||||
# 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。
|
||||
# Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。
|
||||
# ============================================================
|
||||
if self._is_sha1_mangled_call(call_name) != 0:
|
||||
if trans is None or trans._declare_only == 0:
|
||||
cf_dot: t.CChar | t.CPtr = string.strchr(call_name, '.')
|
||||
cf_last: t.CChar | t.CPtr = string.strrchr(call_name, '.')
|
||||
if cf_dot is not None and cf_last is not None:
|
||||
cf_sha1: t.CChar | t.CPtr = stdlib.malloc(17)
|
||||
cf_bare_len: t.CSizeT = string.strlen(call_name) - \
|
||||
(t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1
|
||||
cf_bare: t.CChar | t.CPtr = stdlib.malloc(cf_bare_len + 1)
|
||||
if cf_sha1 is not None and cf_bare is not None:
|
||||
string.strncpy(cf_sha1, call_name, 16)
|
||||
cf_sha1[16] = '\0'
|
||||
string.strcpy(cf_bare, cf_last + 1)
|
||||
cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||||
pool, cf_sha1, None, cf_bare, 1)
|
||||
if cf_ret is not None:
|
||||
call_ret_ty = cf_ret
|
||||
else:
|
||||
cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||||
pool, cf_sha1, None, cf_bare)
|
||||
if cf_vpi is not None:
|
||||
call_ret_ty = cf_vpi
|
||||
else:
|
||||
# 区分两种失败场景:
|
||||
# 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast
|
||||
# 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按
|
||||
# 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp
|
||||
# (同项目多源文件)。此时标记 trans._deps_pending=1,
|
||||
# 保持白名单类型继续,Phase A 多遍循环下遍重译——
|
||||
# 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。
|
||||
if self._dep_text_ll_exists(pool, cf_sha1) != 0:
|
||||
cf_err: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if cf_err is not None:
|
||||
viperlib.snprintf(
|
||||
cf_err, 1024,
|
||||
"跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中),"
|
||||
"默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name)
|
||||
VLogger.error(cf_err, "HandlesExprCall")
|
||||
HandlesType.fatal_error(
|
||||
node,
|
||||
f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}",
|
||||
"TypeError")
|
||||
else:
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if cf_dbg is not None:
|
||||
viperlib.snprintf(
|
||||
cf_dbg, 1024,
|
||||
"跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序),"
|
||||
"标记重试,本遍保持默认类型", call_name)
|
||||
VLogger.warning(cf_dbg, "HandlesExprCall")
|
||||
stdlib.free(cf_sha1)
|
||||
stdlib.free(cf_bare)
|
||||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||||
|
||||
@@ -132,6 +132,11 @@ class Translator:
|
||||
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
|
||||
_declare_only: t.CInt
|
||||
|
||||
# Phase A 依赖未就绪标志:1=本文件翻译时依赖模块的 text.ll 尚未生成
|
||||
# (同项目源文件按顺序翻译,main.vp 先于其 import 的 mbuddytest.vp),
|
||||
# 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。
|
||||
_deps_pending: t.CInt
|
||||
|
||||
# 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体)
|
||||
AssignH: HandlesAssign.AssignHandle | t.CPtr
|
||||
ReturnH: HandlesReturn.ReturnHandle | t.CPtr
|
||||
@@ -175,6 +180,7 @@ class Translator:
|
||||
self.GenericTypeParamNames = None
|
||||
self.GenericTypeArgs = None
|
||||
self._declare_only = 0
|
||||
self._deps_pending = 0
|
||||
self.AssignH = None
|
||||
self.ReturnH = None
|
||||
self.ImportsH = None
|
||||
|
||||
+127
-72
@@ -415,84 +415,139 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if app_deps_buf is not None:
|
||||
app_deps_buf[0] = '\0'
|
||||
|
||||
for i in range(file_count):
|
||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
if ent is None or ent.Path is None:
|
||||
continue
|
||||
fb_loop: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_loop is not None:
|
||||
viperlib.snprintf(fb_loop, 1024, "Phase A 开始翻译: %s", ent.Path)
|
||||
VLogger.info(fb_loop, "PhaseA-DBG")
|
||||
# 计算源文件的包名(相对 source_dir 的目录部分)
|
||||
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
||||
pkg_pa: str = None
|
||||
if string.strlen(ent.Path) > src_dir_len_pa + 1:
|
||||
rel_path_pa: str = ent.Path + src_dir_len_pa + 1
|
||||
pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa)
|
||||
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir)
|
||||
if tr_a is None:
|
||||
continue
|
||||
fb_ok: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_ok is not None:
|
||||
viperlib.snprintf(fb_ok, 1024, "Phase A 翻译完成: %s", ent.Path)
|
||||
VLogger.info(fb_ok, "PhaseA-DBG")
|
||||
# Phase A 多遍重试:同项目多源文件时,main.vp 可能先于其 import 的
|
||||
# mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析会因
|
||||
# 依赖 text.ll 未生成而标记 _deps_pending=1(见 CallGenMixin 跨模块
|
||||
# 返回类型解析段)。下遍重译即可命中(依赖已生成 text.ll)。
|
||||
# 每遍至少完成一个文件,最多 file_count 遍收敛。
|
||||
done_flags: bytes = stdlib.malloc(file_count)
|
||||
if done_flags is None:
|
||||
VLogger.error("Phase A done_flags 分配失败", "PhaseA")
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
string.memset(done_flags, 0, file_count)
|
||||
PHASE_A_MAX_PASSES: t.CInt = 32
|
||||
for pass_a in range(PHASE_A_MAX_PASSES):
|
||||
completed_this_pass: int = 0
|
||||
for i in range(file_count):
|
||||
if done_flags[i] != 0:
|
||||
continue
|
||||
ea: t.CUInt64T = t.CUInt64T(entries) + i * entry_size
|
||||
ent: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
if ent is None or ent.Path is None:
|
||||
done_flags[i] = 1
|
||||
completed_this_pass += 1
|
||||
continue
|
||||
fb_loop: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_loop is not None:
|
||||
viperlib.snprintf(fb_loop, 1024, "Phase A 开始翻译: %s", ent.Path)
|
||||
VLogger.info(fb_loop, "PhaseA-DBG")
|
||||
# 计算源文件的包名(相对 source_dir 的目录部分)
|
||||
src_dir_len_pa: t.CSizeT = string.strlen(source_dir)
|
||||
pkg_pa: str = None
|
||||
if string.strlen(ent.Path) > src_dir_len_pa + 1:
|
||||
rel_path_pa: str = ent.Path + src_dir_len_pa + 1
|
||||
pkg_pa = HandlesImports.compute_package_from_relpath(mb, rel_path_pa)
|
||||
tr_a: HandlesTranslator.Translator | t.CPtr = BuildPipeline.TranslateFileGetTrans(mb, ent.Path, ent.Sha1, pkg_pa, 0, temp_dir)
|
||||
if tr_a is None:
|
||||
# 翻译失败(语法/解析错误):记录待下遍重试,收敛检查统一报错
|
||||
continue
|
||||
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)。
|
||||
# 依赖在翻译早期已填充,即使 _deps_pending 也收集。
|
||||
if tr_a._imported_modules is not None and app_deps_buf is not None:
|
||||
im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
if im_len_a > 0 and app_deps_len + im_len_a + 1 < APP_DEPS_BUF_SIZE:
|
||||
if app_deps_len > 0:
|
||||
app_deps_buf[app_deps_len] = ' '
|
||||
app_deps_len = app_deps_len + 1
|
||||
string.strcpy(app_deps_buf + app_deps_len, tr_a._imported_modules)
|
||||
app_deps_len = app_deps_len + im_len_a
|
||||
app_deps_buf[app_deps_len] = '\0'
|
||||
if tr_a._deps_pending != 0:
|
||||
# 依赖模块 text.ll 未生成(同项目文件顺序),不写盘,下遍重试
|
||||
fb_dp: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_dp is not None:
|
||||
viperlib.snprintf(fb_dp, 1024,
|
||||
"Phase A 依赖未就绪,下遍重试: %s", ent.Path)
|
||||
VLogger.warning(fb_dp, "PhaseA-DBG")
|
||||
continue
|
||||
fb_ok: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_ok is not None:
|
||||
viperlib.snprintf(fb_ok, 1024, "Phase A 翻译完成: %s", ent.Path)
|
||||
VLogger.info(fb_ok, "PhaseA-DBG")
|
||||
|
||||
# dump stub IR (declarations only)
|
||||
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if stub_buf_a is None:
|
||||
continue
|
||||
tr_a.dump_ir(stub_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||
stub_len_a: t.CSizeT = string.strlen(stub_buf_a)
|
||||
# dump stub IR (declarations only)
|
||||
stub_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if stub_buf_a is None:
|
||||
continue
|
||||
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 (切片路径: 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:
|
||||
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)
|
||||
sf_a.close()
|
||||
stdlib.free(stub_path_a)
|
||||
stdlib.free(stub_buf_a)
|
||||
# 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:
|
||||
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)
|
||||
sf_a.close()
|
||||
stdlib.free(stub_path_a)
|
||||
stdlib.free(stub_buf_a)
|
||||
|
||||
# dump text IR (definitions only)
|
||||
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if text_buf_a is None:
|
||||
continue
|
||||
tr_a.dump_ir(text_buf_a, PHASE_A_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||
text_len_a: t.CSizeT = string.strlen(text_buf_a)
|
||||
# dump text IR (definitions only)
|
||||
text_buf_a: bytes = stdlib.malloc(PHASE_A_IR_SIZE)
|
||||
if text_buf_a is None:
|
||||
continue
|
||||
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: str = StubMerger._sliced_path(temp_dir, td_len_pa, ent.Sha1, "text.ll")
|
||||
if text_path_a is not None:
|
||||
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)
|
||||
tf_a.close()
|
||||
stdlib.free(text_path_a)
|
||||
stdlib.free(text_buf_a)
|
||||
# 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:
|
||||
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)
|
||||
tf_a.close()
|
||||
stdlib.free(text_path_a)
|
||||
stdlib.free(text_buf_a)
|
||||
|
||||
# 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:
|
||||
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:
|
||||
dl_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
df_a.write(tr_a._imported_modules, dl_a)
|
||||
df_a.close()
|
||||
stdlib.free(deps_path_a)
|
||||
# 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:
|
||||
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:
|
||||
dl_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
df_a.write(tr_a._imported_modules, dl_a)
|
||||
df_a.close()
|
||||
stdlib.free(deps_path_a)
|
||||
|
||||
# 收集 _imported_modules 到 app_deps_buf(供 Phase B+ 按需编译)
|
||||
if tr_a._imported_modules is not None and app_deps_buf is not None:
|
||||
im_len_a: t.CSizeT = string.strlen(tr_a._imported_modules)
|
||||
if im_len_a > 0 and app_deps_len + im_len_a + 1 < APP_DEPS_BUF_SIZE:
|
||||
if app_deps_len > 0:
|
||||
app_deps_buf[app_deps_len] = ' '
|
||||
app_deps_len = app_deps_len + 1
|
||||
string.strcpy(app_deps_buf + app_deps_len, tr_a._imported_modules)
|
||||
app_deps_len = app_deps_len + im_len_a
|
||||
app_deps_buf[app_deps_len] = '\0'
|
||||
done_flags[i] = 1
|
||||
completed_this_pass += 1
|
||||
# 收敛检查:所有文件完成则结束
|
||||
all_done: int = 1
|
||||
for i_ck in range(file_count):
|
||||
if done_flags[i_ck] == 0:
|
||||
all_done = 0
|
||||
break
|
||||
if all_done != 0:
|
||||
break
|
||||
if completed_this_pass == 0:
|
||||
# 无进展:剩余文件无法完成(真实编译错误),终止并列出未完成文件
|
||||
for i_err in range(file_count):
|
||||
if done_flags[i_err] == 0:
|
||||
ea_err: t.CUInt64T = t.CUInt64T(entries) + i_err * entry_size
|
||||
ent_err: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_err, t.CPtr))
|
||||
if ent_err is not None and ent_err.Path is not None:
|
||||
fb_err: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_err is not None:
|
||||
viperlib.snprintf(fb_err, 1024,
|
||||
"Phase A 无法完成翻译: %s(请检查依赖模块是否已编译/注册)", ent_err.Path)
|
||||
VLogger.error(fb_err, "PhaseA")
|
||||
stdlib.free(done_flags)
|
||||
VLogger.error("Phase A 多遍收敛失败,终止编译", "PhaseA")
|
||||
stdlib.free(entries)
|
||||
return 1
|
||||
stdlib.free(done_flags)
|
||||
|
||||
if do_phase2 == 0:
|
||||
VLogger.info("Phase A 完成(仅 stub 生成)", "project")
|
||||
|
||||
Reference in new issue
Block a user