refactor(core): StubMerger 拆 5 组(Collect/Store/Topo/IR/Build,2391→72 行)
直接移动+改调用方模式:35 个函数按功能移至 5 个子模块,主文件 仅保留常量与全局变量(main.vp 仍直接赋值 StubMerger._mbuddy)。 - 子模块函数体内裸调用映射为子模块前缀,全局变量经 StubMerger._xxx 跨模块访问 - 12 个调用方文件 StubMerger.func( → 对应子模块前缀并补 import - 全 App 语法/引用/import 验证通过
This commit is contained in:
1 parent
d0cf283228
commit
278893d203
18 files changed
+3867
-3733
No files matched your search
+1334
-1333
File diff suppressed because it is too large.
Load diff
@@ -36,6 +36,7 @@ import lib.core.StubMerger as StubMerger
|
||||
import lib.StubGen.Converter as StubConverter
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
|
||||
# ============================================================
|
||||
# BuildPipeline - 编译管线
|
||||
@@ -143,7 +144,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
if pyi_pos > 0:
|
||||
# 写入 {sha1}.vpi 到 temp_dir(切片路径)
|
||||
td_len_vpi: t.CSizeT = string.strlen(temp_dir)
|
||||
pyi_path: str = StubMerger._sliced_path(temp_dir, td_len_vpi, sha1_val, "vpi")
|
||||
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_vpi, sha1_val, "vpi")
|
||||
if pyi_path is not None:
|
||||
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W)
|
||||
if not pf.closed:
|
||||
|
||||
@@ -24,6 +24,8 @@ import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||||
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
|
||||
@@ -135,7 +137,7 @@ class CallGenBase:
|
||||
|
||||
委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。
|
||||
"""
|
||||
return StubMerger.LookupSha1ByModName(mod_name)
|
||||
return StubMergerStore.LookupSha1ByModName(mod_name)
|
||||
|
||||
|
||||
def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str:
|
||||
@@ -145,7 +147,7 @@ class CallGenBase:
|
||||
去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。
|
||||
委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。
|
||||
"""
|
||||
return StubMerger.LookupSha1ByModNameSuffix(mod_suffix)
|
||||
return StubMergerStore.LookupSha1ByModNameSuffix(mod_suffix)
|
||||
|
||||
|
||||
def _module_package_from_sha1(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
@@ -153,9 +155,9 @@ class CallGenBase:
|
||||
"""从 SHA1 存储器的 rel_path 计算模块所属包名(目录部分,'/' → '.')"""
|
||||
if pool is None or mod_sha1 is None:
|
||||
return None
|
||||
rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||
sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||||
count: int = StubMerger.GetSha1StoreCount()
|
||||
rel_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
sha1_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr()
|
||||
count: int = StubMergerStore.GetSha1StoreCount()
|
||||
if rel_arr_ptr is None or sha1_arr_ptr is None or count <= 0:
|
||||
return None
|
||||
for i in range(count):
|
||||
@@ -199,7 +201,7 @@ class CallGenBase:
|
||||
if temp_dir is None:
|
||||
return None
|
||||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||||
vpi_path: str = StubMerger._sliced_path(temp_dir, td_len, mod_sha1, "vpi")
|
||||
vpi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, mod_sha1, "vpi")
|
||||
if vpi_path is None:
|
||||
return None
|
||||
READ_SZ: t.CSizeT = 1048576
|
||||
|
||||
@@ -21,6 +21,7 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.ClassGenBase as ClassGenBase
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
# 泛型特化递归深度上限(泛型循环套用防护)
|
||||
@@ -456,7 +457,7 @@ class ClassGenGeneric(ClassGenBase.ClassGenBase):
|
||||
"""将模板模块的 imports 并入 trans._imported_modules(空格分隔)"""
|
||||
if trans is None or template_sha1 is None:
|
||||
return
|
||||
tdeps: str = StubMerger.LookupIncludesDeps(template_sha1)
|
||||
tdeps: str = StubMergerStore.LookupIncludesDeps(template_sha1)
|
||||
if tdeps is None or tdeps[0] == '\0':
|
||||
return
|
||||
cur: str = trans._imported_modules
|
||||
|
||||
@@ -28,6 +28,8 @@ import lib.Projectrans.Utils as Utils
|
||||
|
||||
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
# ============================================================
|
||||
# ExprGenCdef - ExprGenMixin 拆分(阶段 D):跨模块 CDefine 查找
|
||||
@@ -59,11 +61,11 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if Config.IncludesDir is None:
|
||||
return None
|
||||
# 从 StubMerger 全局存储器获取相对路径数组
|
||||
rel_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||
count: int = StubMerger.GetSha1StoreCount()
|
||||
rel_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
count: int = StubMergerStore.GetSha1StoreCount()
|
||||
if rel_arr_ptr is None or count <= 0:
|
||||
return None
|
||||
sha1_arr_ptr: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||||
sha1_arr_ptr: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr()
|
||||
if sha1_arr_ptr is None:
|
||||
return None
|
||||
# 遍历查找匹配的 SHA1
|
||||
@@ -301,7 +303,7 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
|
||||
# 6. 构建 vpi 文件路径
|
||||
td_len: t.CSizeT = string.strlen(temp_dir)
|
||||
pyi_path: str = StubMerger._sliced_path(temp_dir, td_len, sha1, "vpi")
|
||||
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "vpi")
|
||||
if pyi_path is None:
|
||||
return -1
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import lib.Projectrans.Utils as Utils
|
||||
|
||||
|
||||
import lib.core.Gen.ExprGenBase as ExprGenBase
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
# ============================================================
|
||||
# ExprGenCls - ExprGenMixin 拆分(阶段 D):类名推断/docstring 登记
|
||||
@@ -185,9 +186,9 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
return 1
|
||||
# 3. 模块名(模块本身,少见);用 StubMerger 模块级函数(避免
|
||||
# 跨 Mixin self 调用生成不存在符号)
|
||||
mod_sha1: str = StubMerger.LookupSha1ByModName(name_id)
|
||||
mod_sha1: str = StubMergerStore.LookupSha1ByModName(name_id)
|
||||
if mod_sha1 is None:
|
||||
mod_sha1 = StubMerger.LookupSha1ByModNameSuffix(name_id)
|
||||
mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(name_id)
|
||||
if mod_sha1 is not None:
|
||||
string.strcpy(out_mod, mod_sha1)
|
||||
string.strcpy(out_sym, name_id)
|
||||
@@ -235,9 +236,9 @@ class ExprGenCls(ExprGenBase.ExprGenBase):
|
||||
is_mod: int = 0
|
||||
mod_sha1: str = None
|
||||
if HandlesVar.lookup_var(trans.SymTab, head_id) is None:
|
||||
mod_sha1 = StubMerger.LookupSha1ByModName(head_id)
|
||||
mod_sha1 = StubMergerStore.LookupSha1ByModName(head_id)
|
||||
if mod_sha1 is None:
|
||||
mod_sha1 = StubMerger.LookupSha1ByModNameSuffix(head_id)
|
||||
mod_sha1 = StubMergerStore.LookupSha1ByModNameSuffix(head_id)
|
||||
if mod_sha1 is not None:
|
||||
is_mod = 1
|
||||
if is_mod != 0:
|
||||
|
||||
@@ -11,6 +11,7 @@ import w32.fileio as fileio
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -615,7 +616,7 @@ class ImportsGenMixin:
|
||||
# ctraits 是纯编译期宏库(.vpi 后缀,IncludesScanner 不扫描 .vpi),豁免检查
|
||||
if string.strcmp(mod_name, "t") == 0 or string.strcmp(mod_name, "c") == 0 or string.strcmp(mod_name, "ctraits") == 0:
|
||||
return 1
|
||||
mod_sha1: str = StubMerger.LookupSha1ByModName(mod_name)
|
||||
mod_sha1: str = StubMergerStore.LookupSha1ByModName(mod_name)
|
||||
if mod_sha1 is None:
|
||||
# App 兄弟模块豁免:当前文件同目录存在 {mod_name}.vp/.py
|
||||
# (如 Test/G4/App/caller1.vp import g4node——同项目源文件,
|
||||
|
||||
@@ -16,6 +16,7 @@ import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -85,7 +86,7 @@ class AssignHandle(HandlesBase.Mixin):
|
||||
# 通过 sha1 查找文件名(人类可读)
|
||||
rel_path: str = None
|
||||
if sha1 is not None:
|
||||
rel_path = StubMerger.LookupSha1RelPath(sha1)
|
||||
rel_path = StubMergerStore.LookupSha1RelPath(sha1)
|
||||
# 根据 AST 节点类型提取详情
|
||||
if val_kind == ast.ASTKind.Attribute:
|
||||
at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value)
|
||||
|
||||
@@ -25,6 +25,7 @@ import lib.core.Handles.HandlesFunctions as HandlesFunctions
|
||||
import lib.core.Handles.HandlesType as HandlesType
|
||||
import lib.core.Handles.HandlesStruct as HandlesStruct
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
|
||||
# ============================================================
|
||||
# HandlesTranslator - 翻译器状态管理 + 主入口
|
||||
@@ -454,7 +455,7 @@ class Translator:
|
||||
import lib.core.StubMerger as StubMerger
|
||||
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
|
||||
HandlesType.push_trace(HandlesType.get_current_file(), cur_imp_lineno)
|
||||
StubMerger.LoadDepVpiIntoModule(
|
||||
StubMergerBuild.LoadDepVpiIntoModule(
|
||||
pool, mod, self._imported_modules, self._from_imports,
|
||||
HandlesType.get_temp_dir(), self)
|
||||
HandlesType.pop_trace()
|
||||
|
||||
+33
-29
@@ -23,6 +23,10 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.StubGen.Converter as StubConverter
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerIR as StubMergerIR
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
@@ -101,9 +105,9 @@ def _ScanClassInheritance(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 按需翻译过滤
|
||||
in_set: int = 0
|
||||
if use_reachable != 0:
|
||||
in_set = StubMerger._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||||
else:
|
||||
in_set = StubMerger._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||||
if in_set == 0:
|
||||
continue
|
||||
|
||||
@@ -596,9 +600,9 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
sha1_e: str = entry.Sha1
|
||||
in_set: int = 0
|
||||
if use_reachable != 0:
|
||||
in_set = StubMerger._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, reachable_set, reachable_count)
|
||||
else:
|
||||
in_set = StubMerger._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||||
in_set = StubMergerCollect._is_in_sha1_set(sha1_e, sha1_set, set_count)
|
||||
if in_set == 0:
|
||||
continue
|
||||
|
||||
@@ -675,13 +679,13 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
mod_arr_ts: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
map_count_ts: int = 0
|
||||
if sha1_arr_ts is not None and mod_arr_ts is not None:
|
||||
map_count_ts = StubMerger._BuildIncludesSha1Map(
|
||||
map_count_ts = StubMergerIR._BuildIncludesSha1Map(
|
||||
temp_dir, td_len_ts, sha1_arr_ts, mod_arr_ts)
|
||||
for fi_imp in range(file_count):
|
||||
if map_count_ts <= 0:
|
||||
break
|
||||
fsha1_imp: str = file_sha1s_buf + fi_imp * SHA1_LEN
|
||||
deps_imp: str = StubMerger.LookupIncludesDeps(fsha1_imp)
|
||||
deps_imp: str = StubMergerStore.LookupIncludesDeps(fsha1_imp)
|
||||
if deps_imp is None:
|
||||
continue
|
||||
dl_imp: t.CSizeT = string.strlen(deps_imp)
|
||||
@@ -700,7 +704,7 @@ def _TopoSortFiles(mb: memhub.MemBuddy | t.CPtr,
|
||||
continue
|
||||
string.strncpy(dname_imp, deps_imp + dstart_imp, dlen_imp)
|
||||
dname_imp[dlen_imp] = '\0'
|
||||
dsha1_imp: str = StubMerger._FindSha1ByModName(
|
||||
dsha1_imp: str = StubMergerIR._FindSha1ByModName(
|
||||
sha1_arr_ts, mod_arr_ts, map_count_ts, dname_imp)
|
||||
stdlib.free(dname_imp)
|
||||
if dsha1_imp is None:
|
||||
@@ -950,9 +954,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
set_count += 1
|
||||
# 先填充全局 SHA1 映射存储器(即使 set_count==0 也填充,确保 Phase2 能获取 includes 条目)
|
||||
# 注意:PopulateSha1MapStore 会先 free 旧存储器再重新分配
|
||||
StubMerger.PopulateSha1MapStore(result)
|
||||
StubMergerStore.PopulateSha1MapStore(result)
|
||||
# 写入 _sha1_map.txt(人类可读输出,程序内部不读取;机器分析使用 PopulateSha1MapStore 内存存储器)
|
||||
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
|
||||
StubMergerCollect.WriteIncludesSha1Map(mb, temp_dir, result, None, 0)
|
||||
if set_count <= 0:
|
||||
VLogger.warning("扫描结果无有效 SHA1,跳过 Phase1(项目可能无 includes 依赖)", "Phase1")
|
||||
stdlib.free(sha1_set)
|
||||
@@ -993,7 +997,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
p1a_failed += 1
|
||||
continue
|
||||
|
||||
if StubMerger._is_in_sha1_set(sha1_a, sha1_set, set_count) == 0:
|
||||
if StubMergerCollect._is_in_sha1_set(sha1_a, sha1_set, set_count) == 0:
|
||||
p1a_skipped += 1
|
||||
continue
|
||||
|
||||
@@ -1086,7 +1090,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 同时填充内存依赖存储器(PopulateIncludesDeps),供 _BuildReachableSha1Set
|
||||
# 直接从内存读取,不依赖 .deps.txt 过程文件
|
||||
td_len_a: t.CSizeT = string.strlen(temp_dir)
|
||||
deps_path_a: str = StubMerger._sliced_path(temp_dir, td_len_a, sha1_a, "deps.txt")
|
||||
deps_path_a: str = StubMergerCollect._sliced_path(temp_dir, td_len_a, sha1_a, "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:
|
||||
@@ -1097,7 +1101,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
stdlib.free(deps_path_a)
|
||||
# 填充内存依赖存储器(供 _BuildReachableSha1Set 使用,不读 .deps.txt)
|
||||
if tr_a._imported_modules is not None:
|
||||
StubMerger.PopulateIncludesDeps(sha1_a, tr_a._imported_modules)
|
||||
StubMergerStore.PopulateIncludesDeps(sha1_a, tr_a._imported_modules)
|
||||
|
||||
# 释放 Translator 的 C malloc 资源
|
||||
if tr_a._global_names is not None:
|
||||
@@ -1131,7 +1135,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
reachable_set = stdlib.malloc(StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||
if reachable_set is not None:
|
||||
string.memset(reachable_set, 0, StubMerger.MAX_INCLUDES_SHA1 * 17)
|
||||
reachable_count = StubMerger._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set)
|
||||
reachable_count = StubMergerBuild._BuildReachableSha1Set(mb, Config.SourceDir, temp_dir, reachable_set)
|
||||
if reachable_count < 0:
|
||||
VLogger.error("可达集合构建失败,终止", "Phase1")
|
||||
return 1
|
||||
@@ -1139,10 +1143,10 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
use_reachable = 1
|
||||
# 用可达集合重新生成 _sha1_map.txt(按图求索的最终产物)
|
||||
# Phase B+ 只遍历这些条目,避免编译不需要的 includes(如 asm.vp)
|
||||
StubMerger.WriteIncludesSha1Map(mb, temp_dir, result, reachable_set, reachable_count)
|
||||
StubMergerCollect.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)
|
||||
set_count = StubMergerCollect._load_includes_sha1_set(mb, temp_dir, sha1_set)
|
||||
else:
|
||||
VLogger.warning("可达集合为空,回退全量扫描", "Phase1")
|
||||
stdlib.free(reachable_set)
|
||||
@@ -1272,11 +1276,11 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 按需翻译过滤(拓扑排序已过滤,但字母序回退需要检查)
|
||||
if topo_count == 0:
|
||||
if use_reachable != 0:
|
||||
if StubMerger._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0:
|
||||
if StubMergerCollect._is_in_sha1_set(sha1_r, reachable_set, reachable_count) == 0:
|
||||
p1a_skp += 1
|
||||
continue
|
||||
else:
|
||||
if StubMerger._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0:
|
||||
if StubMergerCollect._is_in_sha1_set(sha1_r, sha1_set, set_count) == 0:
|
||||
p1a_skp += 1
|
||||
continue
|
||||
|
||||
@@ -1403,13 +1407,13 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
sha1_pv: str = entry_pv.Sha1
|
||||
in_set_pv: int = 0
|
||||
if use_reachable != 0:
|
||||
in_set_pv = StubMerger._is_in_sha1_set(sha1_pv, reachable_set, reachable_count)
|
||||
in_set_pv = StubMergerCollect._is_in_sha1_set(sha1_pv, reachable_set, reachable_count)
|
||||
else:
|
||||
in_set_pv = StubMerger._is_in_sha1_set(sha1_pv, sha1_set, set_count)
|
||||
in_set_pv = StubMergerCollect._is_in_sha1_set(sha1_pv, sha1_set, set_count)
|
||||
if in_set_pv == 0:
|
||||
continue
|
||||
# vpi 已存在则跳过
|
||||
vpi_path_pv: str = StubMerger._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi")
|
||||
vpi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi")
|
||||
if vpi_path_pv is None:
|
||||
p1bpre_failed += 1
|
||||
continue
|
||||
@@ -1456,7 +1460,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
if pyi_buf_pv is not None:
|
||||
pyi_pos_pv: t.CSizeT = StubConverter._GeneratePyiFromAst(mb, tree_pv, entry_pv.RelPath, pyi_buf_pv, PYI_BUF_SIZE)
|
||||
if pyi_pos_pv > 0:
|
||||
pyi_path_pv: str = StubMerger._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi")
|
||||
pyi_path_pv: str = StubMergerCollect._sliced_path(temp_dir, dir_len_pv, sha1_pv, "vpi")
|
||||
if pyi_path_pv is not None:
|
||||
pf_pv: fileio.File | t.CPtr = fileio.File(pyi_path_pv, fileio.MODE.W)
|
||||
if not pf_pv.closed:
|
||||
@@ -1510,9 +1514,9 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
if topo_count == 0:
|
||||
in_set = 0
|
||||
if use_reachable != 0:
|
||||
in_set = StubMerger._is_in_sha1_set(sha1, reachable_set, reachable_count)
|
||||
in_set = StubMergerCollect._is_in_sha1_set(sha1, reachable_set, reachable_count)
|
||||
else:
|
||||
in_set = StubMerger._is_in_sha1_set(sha1, sha1_set, set_count)
|
||||
in_set = StubMergerCollect._is_in_sha1_set(sha1, sha1_set, set_count)
|
||||
if in_set == 0:
|
||||
skipped += 1
|
||||
continue
|
||||
@@ -1520,7 +1524,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# 构造 stub 路径: {temp_dir}/{sha1}.stub.ll
|
||||
dir_len: t.CSizeT = string.strlen(temp_dir)
|
||||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||||
stub_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "stub.ll")
|
||||
stub_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "stub.ll")
|
||||
if stub_path is None:
|
||||
failed += 1
|
||||
continue
|
||||
@@ -1530,7 +1534,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
if not sf.closed:
|
||||
sf.close()
|
||||
# 检查 text.ll 是否也存在(虚表扫描需要 text.ll)
|
||||
text_path: str = StubMerger._sliced_path(temp_dir, dir_len, sha1, "text.ll")
|
||||
text_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "text.ll")
|
||||
if text_path is not None:
|
||||
tf: fileio.File | t.CPtr = fileio.File(text_path, fileio.MODE.R)
|
||||
if not tf.closed:
|
||||
@@ -1617,7 +1621,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
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, "vpi")
|
||||
pyi_path: str = StubMergerCollect._sliced_path(temp_dir, dir_len, sha1, "vpi")
|
||||
if pyi_path is not None:
|
||||
pf: fileio.File | t.CPtr = fileio.File(pyi_path, fileio.MODE.W)
|
||||
if not pf.closed:
|
||||
@@ -1690,7 +1694,7 @@ 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: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "stub.ll")
|
||||
stub_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "stub.ll")
|
||||
if stub_path_p1 is not None:
|
||||
sf_p1: fileio.File | t.CPtr = fileio.File(stub_path_p1, fileio.MODE.W)
|
||||
if not sf_p1.closed:
|
||||
@@ -1713,7 +1717,7 @@ 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: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll")
|
||||
text_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "text.ll")
|
||||
if text_path_p1 is not None:
|
||||
tf_p1: fileio.File | t.CPtr = fileio.File(text_path_p1, fileio.MODE.W)
|
||||
if not tf_p1.closed:
|
||||
@@ -1723,7 +1727,7 @@ 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: str = StubMerger._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
|
||||
deps_path_p1: str = StubMergerCollect._sliced_path(temp_dir, dir_len_p1, sha1, "deps.txt")
|
||||
if deps_path_p1 is not None:
|
||||
df_p1: fileio.File | t.CPtr = fileio.File(deps_path_p1, fileio.MODE.W)
|
||||
if not df_p1.closed:
|
||||
|
||||
+35
-30
@@ -26,6 +26,11 @@ import lib.core.CompilerFactory as CompilerFactory
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerIR as StubMergerIR
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
import lib.core.StubMergerTopo as StubMergerTopo
|
||||
|
||||
# 全局 mbuddy 指针
|
||||
_mbuddy: memhub.MemBuddy | t.CPtr
|
||||
@@ -321,12 +326,12 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# Phase2 不依赖 Phase1 的副作用:如果 Sha1Store 为空(Phase1 未运行或提前返回),
|
||||
# 自行扫描 includes 目录并填充 Sha1Store,确保后续"编译缺失 includes"逻辑能正常工作
|
||||
if includes_dir is not None:
|
||||
if StubMerger.GetSha1StoreCount() == 0:
|
||||
if StubMergerStore.GetSha1StoreCount() == 0:
|
||||
inc_scan_result: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
|
||||
if inc_scan_result is None:
|
||||
VLogger.error("includes 扫描失败,无法填充 Sha1Store", "project")
|
||||
if inc_scan_result is not None:
|
||||
inc_filled: int = StubMerger.PopulateSha1MapStore(inc_scan_result)
|
||||
inc_filled: int = StubMergerStore.PopulateSha1MapStore(inc_scan_result)
|
||||
fb_inc: str = VLogger.fmt_buf()
|
||||
if fb_inc is not None:
|
||||
viperlib.snprintf(fb_inc, 1024, "Phase2 自主填充 includes Sha1Store: %d 个", inc_filled)
|
||||
@@ -358,7 +363,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
rel_path_am = p_str + src_dir_len_am + 1
|
||||
# 同步追加到内存存储器(供跨模块 CDefine 查找)
|
||||
# rel_path_am 格式如 "lib/core/StubMerger.vp",与 _sha1_map.txt 一致
|
||||
if StubMerger.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0:
|
||||
if StubMergerStore.AppendToSha1MapStore(ent_am.Sha1, rel_path_am) != 0:
|
||||
fb_apf: str = VLogger.fmt_buf()
|
||||
if fb_apf is not None:
|
||||
viperlib.snprintf(fb_apf, 1024, "AppendToSha1MapStore 失败: %s", rel_path_am)
|
||||
@@ -404,11 +409,11 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 同时填充 PopulateIncludesDeps,供 Phase B+ 的 _BuildReachableSha1Set 使用。
|
||||
# 多遍扫描:解决跨文件继承问题(如 Constant(AST) 在 AST 未注册时被跳过)。
|
||||
if includes_dir is not None and includes_binary_dir is not None:
|
||||
store_count_inc_pre: int = StubMerger.GetSha1StoreCount()
|
||||
store_count_inc_pre: int = StubMergerStore.GetSha1StoreCount()
|
||||
if store_count_inc_pre > 0:
|
||||
store_sha1_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreArrPtr()
|
||||
store_rel_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||
store_incdir_inc_pre: bytes | t.CPtr = StubMerger.GetSha1StoreIncdirArrPtr()
|
||||
store_sha1_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreArrPtr()
|
||||
store_rel_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
store_incdir_inc_pre: bytes | t.CPtr = StubMergerStore.GetSha1StoreIncdirArrPtr()
|
||||
deps_filled_pre: int = 0
|
||||
PHASE_A_INC_MAX_PASSES: t.CInt = 3
|
||||
# [修复] 记录预注册失败的 includes:多遍后仍失败 → 报错终止编译。
|
||||
@@ -467,7 +472,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 依赖填充只在第一遍执行(PopulateIncludesDeps 内部有去重)
|
||||
# 注意:必须在 reset_to(mark2) 之前调用——内部深拷贝到 stdlib
|
||||
if pass_inc_i == 0 and tr_inc_pre._imported_modules is not None \
|
||||
and StubMerger.PopulateIncludesDeps(
|
||||
and StubMergerStore.PopulateIncludesDeps(
|
||||
inc_sha1_pre, tr_inc_pre._imported_modules) == 0:
|
||||
deps_filled_pre = deps_filled_pre + 1
|
||||
# OOM 清理:回收本 includes 文件预注册翻译的瞬时数据
|
||||
@@ -618,7 +623,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
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")
|
||||
stub_path_a: str = StubMergerCollect._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:
|
||||
@@ -635,7 +640,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
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")
|
||||
text_path_a: str = StubMergerCollect._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:
|
||||
@@ -645,7 +650,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
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")
|
||||
deps_path_a: str = StubMergerCollect._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:
|
||||
@@ -732,7 +737,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
viperlib.snprintf(fb, 1024, "combined_ir 分配失败: %s", ent.Path)
|
||||
VLogger.error(fb, "PhaseB")
|
||||
continue
|
||||
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
||||
combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, ent.Sha1, combined_ir, COMBINED_IR_SIZE)
|
||||
if combined_len == 0:
|
||||
fb: str = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
@@ -768,7 +773,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
is_main_mod = 1
|
||||
|
||||
# 切片路径: output_dir/{sha1前缀}/{sha1}.obj
|
||||
obj_path_sliced: str = StubMerger._sliced_path(output_dir, od_len, ent.Sha1, "obj")
|
||||
obj_path_sliced: str = StubMergerCollect._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:
|
||||
@@ -811,7 +816,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if fb_pbp_enter is not None:
|
||||
viperlib.snprintf(fb_pbp_enter, 1024,
|
||||
"PhaseB+ 入口: store_count=%d includes_binary_dir=%s",
|
||||
StubMerger.GetSha1StoreCount(), includes_binary_dir)
|
||||
StubMergerStore.GetSha1StoreCount(), includes_binary_dir)
|
||||
VLogger.info(fb_pbp_enter, "PhaseB+")
|
||||
|
||||
# 创建 includes_binary_dir 目录(确保 .obj 能写入和 collect_obj_files 能扫描)
|
||||
@@ -828,7 +833,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
reachable_count: int = 0
|
||||
if reachable_set is not None:
|
||||
string.memset(reachable_set, 0, REACHABLE_SET_SIZE)
|
||||
reachable_count = StubMerger._BuildReachableSha1Set(
|
||||
reachable_count = StubMergerBuild._BuildReachableSha1Set(
|
||||
mb, source_dir, temp_dir, reachable_set, app_deps_buf)
|
||||
fb_reach: str = VLogger.fmt_buf()
|
||||
if fb_reach is not None:
|
||||
@@ -856,10 +861,10 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
store_mod_arr_mi: bytes = stdlib.malloc(StubMerger.MAX_INCLUDES * 64)
|
||||
store_count_mi: int = 0
|
||||
if store_sha1_arr_mi is not None and store_mod_arr_mi is not None:
|
||||
store_count_mi = StubMerger._BuildIncludesSha1Map(
|
||||
store_count_mi = StubMergerIR._BuildIncludesSha1Map(
|
||||
temp_dir, td_len_pb, store_sha1_arr_mi, store_mod_arr_mi)
|
||||
store_rel_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreRelArrPtr()
|
||||
store_incdir_arr_mi: bytes | t.CPtr = StubMerger.GetSha1StoreIncdirArrPtr()
|
||||
store_rel_arr_mi: bytes | t.CPtr = StubMergerStore.GetSha1StoreRelArrPtr()
|
||||
store_incdir_arr_mi: bytes | t.CPtr = StubMergerStore.GetSha1StoreIncdirArrPtr()
|
||||
if store_count_mi > 0:
|
||||
|
||||
# 拓扑排序可达 includes:被依赖模块先完整翻译。跨模块 vtable 生成
|
||||
@@ -870,7 +875,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
VLogger.error("拓扑排序索引分配失败,终止编译", "PhaseB+")
|
||||
topo_count = 0
|
||||
else:
|
||||
topo_count = StubMerger.BuildTopoSortedIndices(
|
||||
topo_count = StubMergerTopo.BuildTopoSortedIndices(
|
||||
store_count_mi, store_sha1_arr_mi, store_mod_arr_mi,
|
||||
reachable_set, reachable_count, topo_idx)
|
||||
|
||||
@@ -882,7 +887,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(ti) * StubMerger.MAX_REL_PATH_LEN
|
||||
# 检查 .obj 是否已存在于 includes.binary(切片子目录)
|
||||
ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
check_pat_mi: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj")
|
||||
check_pat_mi: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj")
|
||||
check_fd_mi: w32.win32file.WIN32_FIND_DATAA | t.CPtr = stdlib.malloc(w32.win32file.WIN32_FIND_DATAA.__sizeof__())
|
||||
obj_exists_mi: int = 0
|
||||
if check_pat_mi is not None and check_fd_mi is not None:
|
||||
@@ -916,7 +921,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
# 检查是否为声明文件(只有 declare 没有实质 define)
|
||||
# 判断方法: text.ll 中若有混淆函数 define(含 @")则为实现文件
|
||||
is_decl_mi: int = -1
|
||||
tpath_mi: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
tpath_mi: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
if tpath_mi is not None:
|
||||
tf_mi: fileio.File | t.CPtr = fileio.File(tpath_mi, fileio.MODE.R)
|
||||
if not tf_mi.closed:
|
||||
@@ -964,7 +969,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
inc_combined_mi: bytes = stdlib.malloc(COMBINED_IR_SIZE)
|
||||
inc_combined_len_mi: t.CSizeT = 0
|
||||
if inc_combined_mi is not None:
|
||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
|
||||
# 如果 stub/text 不存在,翻译源文件并保存 stub + text,然后重试
|
||||
if inc_combined_len_mi == 0 and inc_combined_mi is not None:
|
||||
@@ -981,7 +986,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if inc_stub_buf is not None:
|
||||
tr_mi.dump_ir(inc_stub_buf, PBP_IR_SIZE, llvmlite.OUTPUT_STUB)
|
||||
inc_stub_len: t.CSizeT = string.strlen(inc_stub_buf)
|
||||
inc_stub_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||
inc_stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||
if inc_stub_path is not None:
|
||||
isf: fileio.File | t.CPtr = fileio.File(inc_stub_path, fileio.MODE.W)
|
||||
if not isf.closed:
|
||||
@@ -994,7 +999,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
if inc_text_buf is not None:
|
||||
tr_mi.dump_ir(inc_text_buf, PBP_IR_SIZE, llvmlite.OUTPUT_TEXT)
|
||||
inc_text_len: t.CSizeT = string.strlen(inc_text_buf)
|
||||
inc_text_path: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
inc_text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
if inc_text_path is not None:
|
||||
itf: fileio.File | t.CPtr = fileio.File(inc_text_path, fileio.MODE.W)
|
||||
if not itf.closed:
|
||||
@@ -1003,15 +1008,15 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
stdlib.free(inc_text_path)
|
||||
stdlib.free(inc_text_buf)
|
||||
# 重试 BuildCombinedIR
|
||||
inc_combined_len_mi = StubMerger.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
inc_combined_len_mi = StubMergerBuild.BuildCombinedIR(temp_dir, inc_sha1_mi, inc_combined_mi, COMBINED_IR_SIZE)
|
||||
# OOM 清理:stub/text 已写盘,回收本 includes 文件翻译瞬时数据
|
||||
# (AST/tokens/lexer/IR/Handler);BuildCombinedIR 只读文件,不受影响
|
||||
mb.reset_to(mark2)
|
||||
|
||||
if inc_combined_len_mi == 0:
|
||||
# 诊断:检查 stub.ll/text.ll 是否存在
|
||||
diag_stub: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||
diag_text: str = StubMerger._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
diag_stub: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "stub.ll")
|
||||
diag_text: str = StubMergerCollect._sliced_path(temp_dir, td_len_mi, inc_sha1_mi, "text.ll")
|
||||
diag_stub_ex: int = 0
|
||||
diag_text_ex: int = 0
|
||||
if diag_stub is not None:
|
||||
@@ -1062,7 +1067,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
# 添加到 obj_paths (切片路径,从 includes_binary_dir 取)
|
||||
ibd_len_mi2: t.CSizeT = string.strlen(includes_binary_dir)
|
||||
inc_obj_sliced: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_mi2, inc_sha1_mi, "obj")
|
||||
inc_obj_sliced: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi2, inc_sha1_mi, "obj")
|
||||
|
||||
if inc_obj_sliced is not None:
|
||||
inc_obj_len: t.CSizeT = string.strlen(inc_obj_sliced)
|
||||
@@ -1156,7 +1161,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
rsha1_pc: str = reachable_set + t.CSizeT(ri_pc) * 17
|
||||
if rsha1_pc[0] == '\0':
|
||||
continue
|
||||
obj_path_pc: str = StubMerger._sliced_path(includes_binary_dir, ibd_len_pc, rsha1_pc, "obj")
|
||||
obj_path_pc: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_pc, rsha1_pc, "obj")
|
||||
if obj_path_pc is not None:
|
||||
# 检查 .obj 文件是否存在
|
||||
cf_pc: fileio.File | t.CPtr = fileio.File(obj_path_pc, fileio.MODE.R)
|
||||
@@ -1174,7 +1179,7 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr,
|
||||
else:
|
||||
# .obj 缺失:纯声明模块(text.ll 无 define 行,如 stdio.vp 全 pass)
|
||||
# 无需 .obj,静默跳过;实现文件缺失才是编译产物异常(fail-fast)
|
||||
if StubMerger.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1:
|
||||
if StubMergerIR.IsDeclOnlyModule(temp_dir, td_len_pc, rsha1_pc) != 1:
|
||||
fb_pc: str = VLogger.fmt_buf()
|
||||
if fb_pc is not None:
|
||||
viperlib.snprintf(fb_pc, 1024, "可达模块 .obj 缺失: %s", obj_path_pc)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,286 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import llvmlite
|
||||
import w32.win32file as win32file
|
||||
import w32.win32base as win32base
|
||||
import w32.fileio as fileio
|
||||
import viperlib
|
||||
import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
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.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
import lib.core.StubMergerTopo as StubMergerTopo
|
||||
import lib.core.StubMergerIR as StubMergerIR
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# StubMergerCollect - StubMerger 拆分(阶段 E):StubMergerCollect
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# _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.free),None 失败
|
||||
# ============================================================
|
||||
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)
|
||||
|
||||
# 子目录前缀:复用 Config.slice_subdir(SHA1 切片唯一权威实现,mbuddy 分配无需 free)
|
||||
subdir_buf: str = Config.slice_subdir(sha1, Config.Sha1SliceLevel)
|
||||
sub_len: t.CSizeT = 0
|
||||
if subdir_buf is not None:
|
||||
sub_len = string.strlen(subdir_buf)
|
||||
|
||||
# 确保子目录存在: {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)
|
||||
|
||||
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:
|
||||
# 构建子目录路径并递归扫描
|
||||
sub_dir: str = Utils.JoinPath(base_dir, fname)
|
||||
if sub_dir is not None:
|
||||
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 - 从全局内存存储器收集 includes 的 SHA1
|
||||
#
|
||||
# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。
|
||||
# 用于过滤 stub 文件,避免加载 TransPyV 自身源文件(lib/*)的 stub 导致链接失败。
|
||||
# ============================================================
|
||||
def _load_includes_sha1_set(pool: memhub.MemBuddy | t.CPtr,
|
||||
temp_dir: str,
|
||||
sha1_set: str) -> int:
|
||||
"""从全局内存存储器将 includes 的 SHA1 写入 sha1_set
|
||||
|
||||
pool/temp_dir 参数保留以兼容现有调用者,但不再使用。
|
||||
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||||
sha1_set 大小为 MAX_INCLUDES_SHA1 * 17(每个 SHA1 16字符+null)
|
||||
返回找到的 includes SHA1 数量,-1 表示错误"""
|
||||
if sha1_set is None:
|
||||
return -1
|
||||
if StubMerger._sha1_store_arr is None:
|
||||
return -1
|
||||
count: int = 0
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
if count >= MAX_INCLUDES_SHA1:
|
||||
break
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
string.strcpy(sha1_set + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
count += 1
|
||||
return count
|
||||
# ============================================================
|
||||
# _is_in_sha1_set - 检查 SHA1 是否在集合中
|
||||
# ============================================================
|
||||
def _is_in_sha1_set(sha1: str, sha1_set: str, set_count: int) -> int:
|
||||
"""检查 sha1 是否在集合中"""
|
||||
if sha1 is None or sha1_set is None:
|
||||
return 0
|
||||
for i in range(set_count):
|
||||
if string.strcmp(sha1_set + i * 17, sha1) == 0:
|
||||
return 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# WriteIncludesSha1Map - 将 includes 扫描结果写入 _sha1_map.txt(人类可读输出)
|
||||
#
|
||||
# _sha1_map.txt 仅作为人类可读的调试输出,程序内部不读取此文件。
|
||||
# 机器分析使用 PopulateSha1MapStore 填充的全局内存存储器。
|
||||
#
|
||||
# Args:
|
||||
# mb: 内存池
|
||||
# temp_dir: 临时目录(_sha1_map.txt 写入位置)
|
||||
# scan_result: IncludesScanner 扫描结果
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功,非 0 失败
|
||||
# ============================================================
|
||||
def WriteIncludesSha1Map(mb: memhub.MemBuddy | t.CPtr, temp_dir: str,
|
||||
scan_result: IncludesScanner.ScanResult | t.CPtr,
|
||||
filter_set: str,
|
||||
filter_count: int) -> int:
|
||||
"""将 includes 扫描结果写入 _sha1_map.txt(人类可读输出,程序内部使用内存存储器)
|
||||
|
||||
若 filter_set 不为 None 且 filter_count > 0,只写入 filter_set 中的条目。
|
||||
"""
|
||||
if temp_dir is None or scan_result is None:
|
||||
return 1
|
||||
|
||||
# 构造路径 temp_dir/_sha1_map.txt
|
||||
dir_len: t.CSizeT = string.strlen(temp_dir)
|
||||
map_path: bytes = stdlib.malloc(dir_len + 32)
|
||||
if map_path is None:
|
||||
return 1
|
||||
viperlib.snprintf(map_path, dir_len + 32, "%s/_sha1_map.txt", temp_dir)
|
||||
|
||||
# 打开文件写入(CREATE_ALWAYS)
|
||||
f: fileio.File | t.CPtr = fileio.File(map_path, fileio.MODE.W)
|
||||
if f.closed:
|
||||
return 1
|
||||
|
||||
# 写入每个 include 条目: {sha1}:includes/{rel_path}\n
|
||||
entry_size_w: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
line_buf: bytes = stdlib.malloc(512)
|
||||
if line_buf is None:
|
||||
f.close()
|
||||
return 1
|
||||
|
||||
written_count: int = 0
|
||||
for i in range(scan_result.Count):
|
||||
ea_w: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_w
|
||||
ent_w: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea_w, t.CPtr))
|
||||
if ent_w is None or ent_w.Sha1 is None or ent_w.RelPath is None:
|
||||
continue
|
||||
# 若提供过滤集合,只写入集合中的条目
|
||||
if filter_set is not None and filter_count > 0:
|
||||
if _is_in_sha1_set(ent_w.Sha1, filter_set, filter_count) == 0:
|
||||
continue
|
||||
viperlib.snprintf(line_buf, 512, "%s:includes/%s\n", ent_w.Sha1, ent_w.RelPath)
|
||||
line_len_w: t.CSizeT = string.strlen(line_buf)
|
||||
f.write(line_buf, line_len_w)
|
||||
written_count += 1
|
||||
|
||||
f.close()
|
||||
return 0
|
||||
@@ -0,0 +1,416 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import llvmlite
|
||||
import w32.win32file as win32file
|
||||
import w32.win32base as win32base
|
||||
import w32.fileio as fileio
|
||||
import viperlib
|
||||
import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
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.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
import lib.core.StubMergerTopo as StubMergerTopo
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# StubMergerIR - StubMerger 拆分(阶段 E):StubMergerIR
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# IsDeclOnlyModule - 判断模块是否为纯声明文件
|
||||
#
|
||||
# 读取 {temp_dir}/{sha1}.text.ll,扫描是否含 "define " 行:
|
||||
# 返回 1 = 纯声明(无函数体,如 stdio.vp 全 pass),无需 .obj
|
||||
# 返回 0 = 实现文件(含 define 函数体)
|
||||
# 返回 -1 = text.ll 不存在/无法判断
|
||||
#
|
||||
# 与 Phase B+(Phase2.vp 编译缺失 includes 时)的内联判断逻辑一致,
|
||||
# 供 Phase C 链接时区分"声明文件无需 .obj"与"实现文件缺失"。
|
||||
# ============================================================
|
||||
def IsDeclOnlyModule(temp_dir: str, td_len: t.CSizeT, sha1: str) -> int:
|
||||
"""判断模块是否为纯声明文件(text.ll 无 define 行)"""
|
||||
if temp_dir is None or sha1 is None:
|
||||
return -1
|
||||
tpath: str = StubMergerCollect._sliced_path(temp_dir, td_len, sha1, "text.ll")
|
||||
if tpath is None:
|
||||
return -1
|
||||
tf_d: fileio.File | t.CPtr = fileio.File(tpath, fileio.MODE.R)
|
||||
stdlib.free(tpath)
|
||||
if tf_d.closed:
|
||||
return -1
|
||||
tbuf_d: bytes = stdlib.malloc(STUB_READ_BUF_SIZE)
|
||||
tbr_d: t.CInt64T = 0
|
||||
if tbuf_d is not None:
|
||||
tbr_d = tf_d.read_all(tbuf_d, STUB_READ_BUF_SIZE)
|
||||
tf_d.close()
|
||||
if tbuf_d is None:
|
||||
return -1
|
||||
if tbr_d <= 0:
|
||||
# 空 text.ll:无函数体,纯声明
|
||||
stdlib.free(tbuf_d)
|
||||
return 1
|
||||
if tbr_d < STUB_READ_BUF_SIZE:
|
||||
tbuf_d[tbr_d] = '\0'
|
||||
else:
|
||||
tbuf_d[STUB_READ_BUF_SIZE - 1] = '\0'
|
||||
# 逐行扫描:找 "define " 行即为实现文件
|
||||
tpos_d: t.CSizeT = 0
|
||||
while tpos_d < tbr_d:
|
||||
tls_d: t.CSizeT = tpos_d
|
||||
while tpos_d < tbr_d:
|
||||
if tbuf_d[tpos_d] == '\n':
|
||||
break
|
||||
tpos_d += 1
|
||||
tll_d: t.CSizeT = tpos_d - tls_d
|
||||
if tpos_d < tbr_d:
|
||||
tpos_d += 1
|
||||
if tll_d >= 7 and string.strncmp(tbuf_d + tls_d, "define ", 7) == 0:
|
||||
stdlib.free(tbuf_d)
|
||||
return 0
|
||||
stdlib.free(tbuf_d)
|
||||
return 1
|
||||
# ============================================================
|
||||
# _IsFuncDeclaredOrDefined - 检查 out_buf 中是否已有函数的 declare/define
|
||||
#
|
||||
# 逐字节strncmp搜索 func_sig(如 @"sha1.func"(/ @printf( ),每次
|
||||
# 找到匹配后检查行首是否以 "declare " 或 "define " 开头,跳过 call 语句。
|
||||
# 避免 strstr 子串匹配误匹配 call ... @"func"(...) 中的 @"func"( 子串。
|
||||
#
|
||||
# Args:
|
||||
# out_buf: 已有的 IR 文本缓冲区
|
||||
# func_sig: 函数签名片段,如 @"sha1.func"(/ @printf(
|
||||
#
|
||||
# Returns:
|
||||
# 1=已存在 declare/define, 0=不存在
|
||||
# ============================================================
|
||||
def _IsFuncDeclaredOrDefined(out_buf: bytes, func_sig: str) -> int:
|
||||
"""检查 out_buf 中是否已有函数的 declare 或 define 行"""
|
||||
if out_buf is None or func_sig is None:
|
||||
return 0
|
||||
sig_len: t.CSizeT = string.strlen(func_sig)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + sig_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||||
ls: t.CSizeT = pos
|
||||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||||
ls -= 1
|
||||
if string.strncmp(out_buf + ls, "declare ", 8) == 0:
|
||||
return 1
|
||||
if string.strncmp(out_buf + ls, "define ", 7) == 0:
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _CommentOutDeclareInBuf - 将 out_buf 中匹配 func_sig 的 declare 行注释掉
|
||||
#
|
||||
# 用于解决 declare/define 冲突:当本地 text.ll 包含 define 而依赖
|
||||
# text.ll 已生成了同函数的 declare 时,将 declare 行首字符改为 ';'
|
||||
# 使其成为注释,然后追加 define 行。
|
||||
# ============================================================
|
||||
def _CommentOutDeclareInBuf(out_buf: bytes, func_sig: str) -> int:
|
||||
"""在 out_buf 中搜索 declare 行(包含 func_sig),将其注释掉"""
|
||||
if out_buf is None or func_sig is None:
|
||||
return 0
|
||||
sig_len: t.CSizeT = string.strlen(func_sig)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if sig_len == 0 or out_len == 0 or sig_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + sig_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, func_sig, sig_len) == 0:
|
||||
ls: t.CSizeT = pos
|
||||
while ls > 0 and out_buf[ls - 1] != '\n':
|
||||
ls -= 1
|
||||
if string.strncmp(out_buf + ls, "declare ", 8) == 0:
|
||||
out_buf[ls] = ';'
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _CommentOutGlobalInBuf - 将 out_buf 中匹配全局变量名的行注释掉
|
||||
#
|
||||
# 解决 stub/text 全局变量重复定义问题:stub 中可能是 external 声明
|
||||
# 或完整定义,以 text 中的定义为准,将 stub 中的同名行注释掉。
|
||||
# ============================================================
|
||||
def _CommentOutGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||||
"""在 out_buf 中搜索全局变量定义行(以 global_name 开头),将行首改为 ';'
|
||||
|
||||
注释掉**所有**匹配行(而非仅第一个):跨模块同名裸全局(如 main.vp 与
|
||||
argparse.vp 都声明 StubMerger._mbuddy)时,本地 stub external + 依赖 stub external +
|
||||
依赖 text 定义会同时存在。只注释第一个会导致依赖 text 的定义残留 →
|
||||
合成 IR 重复定义 → llc "redefinition of global '@StubMerger._mbuddy'"(ArgparseTest
|
||||
回归根因)。"以 text 中定义为准"的语义:后追加者注释掉全部旧行,最终
|
||||
只保留最后一个定义。
|
||||
"""
|
||||
if out_buf is None or global_name is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(global_name)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
commented: int = 0
|
||||
while pos + name_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0)
|
||||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||||
out_buf[pos] = ';'
|
||||
commented = 1
|
||||
pos += 1
|
||||
return commented
|
||||
def _HasGlobalInBuf(out_buf: bytes, global_name: str) -> int:
|
||||
"""检测 out_buf 中是否已有同名全局变量行(行首匹配,未注释)
|
||||
|
||||
用于跳过重复追加依赖全局强定义:stub 注入已提供 external 声明,
|
||||
依赖 text.ll 的强定义只需在定义模块存在一份,复制进每个依赖方
|
||||
会导致 ld.lld duplicate symbol(如 _op_head、MemBuddy.vtable)。
|
||||
"""
|
||||
if out_buf is None or global_name is None:
|
||||
return 0
|
||||
name_len: t.CSizeT = string.strlen(global_name)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if name_len == 0 or out_len == 0 or name_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + name_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, global_name, name_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0)
|
||||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _CommentOutOpaqueTypeInBuf - 将 out_buf 中匹配类型名的 opaque 声明行注释掉
|
||||
#
|
||||
# 解决跨模块类型定义冲突:本地 stub 可能包含自动生成的 opaque 声明
|
||||
#(如 %"sha1.Widget" = type opaque),而依赖 stub 包含完整定义
|
||||
#(如 %"sha1.Widget" = type { i8*, i32 })。去重时需要将 opaque 声明
|
||||
# 注释掉,让完整定义被追加,否则 LLC 报错 "Cannot allocate unsized type"。
|
||||
# ============================================================
|
||||
def _CommentOutOpaqueTypeInBuf(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
"""在 out_buf 中搜索 type_name_prefix 对应的 opaque 声明行,将行首改为 ';'
|
||||
|
||||
type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=' 和后续内容)
|
||||
返回 1=已注释, 0=未找到
|
||||
"""
|
||||
if out_buf is None or type_name_prefix is None:
|
||||
return 0
|
||||
prefix_len: t.CSizeT = string.strlen(type_name_prefix)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if prefix_len == 0 or out_len == 0 or prefix_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + prefix_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0)
|
||||
if pos == 0 or out_buf[pos - 1] == '\n':
|
||||
# 检查后面是否是 " = type opaque"
|
||||
p: t.CSizeT = pos + prefix_len
|
||||
# 跳过空格
|
||||
while p < out_len and out_buf[p] == ' ':
|
||||
p += 1
|
||||
if p < out_len and out_buf[p] == '=':
|
||||
p += 1
|
||||
while p < out_len and out_buf[p] == ' ':
|
||||
p += 1
|
||||
if p + 11 <= out_len:
|
||||
if string.strncmp(out_buf + p, "type opaque", 11) == 0:
|
||||
# 找到 opaque 声明,将行首改为 ';'
|
||||
out_buf[pos] = ';'
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _is_submodule_of_imported - 检查模块名是否是已导入包的子模块
|
||||
#
|
||||
# deps.txt 只记录直接导入的模块名(如 "ast"),但包的 __init__.vp
|
||||
# 内部 from .lexer import Lexer 会让 IR 引用 ast.lexer 子模块类型。
|
||||
# 当模块名包含 '.' 时,检查其顶层包名是否在 deps_buf 中。
|
||||
#
|
||||
# 例如:
|
||||
# deps_buf = "ast stdio string"
|
||||
# mod_name = "ast.lexer" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||||
# mod_name = "ast.token" → 顶层包 "ast" 在 deps_buf 中 → 返回 1
|
||||
# mod_name = "foo.bar" → 顶层包 "foo" 不在 deps_buf 中 → 返回 0
|
||||
# ============================================================
|
||||
def _is_submodule_of_imported(deps_buf: str, mod_name: str) -> int:
|
||||
"""检查 mod_name 是否是 deps_buf 中已导入包的子模块"""
|
||||
if deps_buf is None or mod_name is None:
|
||||
return 0
|
||||
# 查找第一个 '.',提取顶层包名
|
||||
dot_pos: str = string.strchr(mod_name, 46) # '.' = 46
|
||||
if dot_pos is None:
|
||||
return 0
|
||||
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_pos) - t.CUInt64T(mod_name))
|
||||
if pkg_len == 0 or pkg_len >= 256:
|
||||
return 0
|
||||
# 构造顶层包名(截断到 '.' 之前)
|
||||
# 直接在 mod_name 上临时截断检查,避免分配
|
||||
saved_ch: t.CChar = mod_name[pkg_len]
|
||||
mod_name[pkg_len] = '\0'
|
||||
result: int = HandlesImports.is_module_imported(deps_buf, mod_name)
|
||||
mod_name[pkg_len] = saved_ch
|
||||
return result
|
||||
# ============================================================
|
||||
# _HasFullTypeDefinition - 检查 out_buf 中是否已有完整类型定义(非 opaque)
|
||||
#
|
||||
# type_name_prefix 格式: '%"sha1.ClassName"'(不含 '=')
|
||||
# 完整定义: %"name" = type { ... } 或 %"name" = type < { ... } >
|
||||
# 返回 1=已有完整定义, 0=无完整定义
|
||||
# ============================================================
|
||||
def _HasFullTypeDefinition(out_buf: bytes, type_name_prefix: str) -> int:
|
||||
"""检查 out_buf 中是否已有 type_name_prefix 的完整定义"""
|
||||
if out_buf is None or type_name_prefix is None:
|
||||
return 0
|
||||
prefix_len: t.CSizeT = string.strlen(type_name_prefix)
|
||||
out_len: t.CSizeT = string.strlen(out_buf)
|
||||
if prefix_len == 0 or out_len == 0 or prefix_len > out_len:
|
||||
return 0
|
||||
pos: t.CSizeT = 0
|
||||
while pos + prefix_len <= out_len:
|
||||
if string.strncmp(out_buf + pos, type_name_prefix, prefix_len) == 0:
|
||||
# 确认是行首(前一个是换行或 pos==0),且未被注释(行首不是 ';')
|
||||
is_line_start: int = 0
|
||||
if pos == 0:
|
||||
is_line_start = 1
|
||||
elif out_buf[pos - 1] == '\n':
|
||||
is_line_start = 1
|
||||
if is_line_start == 1:
|
||||
# 检查后面是否是 " = type {" 或 " = type <"
|
||||
p: t.CSizeT = pos + prefix_len
|
||||
while p < out_len and out_buf[p] == ' ':
|
||||
p += 1
|
||||
if p < out_len and out_buf[p] == '=':
|
||||
p += 1
|
||||
while p < out_len and out_buf[p] == ' ':
|
||||
p += 1
|
||||
if p + 5 < out_len:
|
||||
if string.strncmp(out_buf + p, "type ", 5) == 0:
|
||||
p += 5
|
||||
if p < out_len:
|
||||
if out_buf[p] == '{' or out_buf[p] == '<':
|
||||
return 1
|
||||
pos += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# _BuildIncludesSha1Map - 从全局内存存储器构建 sha1 → module_name 映射
|
||||
#
|
||||
# 数据来源是 PopulateSha1MapStore 填充的全局存储器(不读取 _sha1_map.txt)。
|
||||
# 返回两个数组(sha1_list 和 mod_list),长度存储在 count 中。
|
||||
# 所有内存由 stdlib.malloc 分配,调用者负责释放。
|
||||
# ============================================================
|
||||
def _BuildIncludesSha1Map(temp_dir: str, td_len: t.CSizeT,
|
||||
sha1_list: str,
|
||||
mod_list: str) -> int:
|
||||
"""从全局内存存储器复制 sha1→module_name 映射到调用者数组
|
||||
|
||||
temp_dir/td_len 参数保留以兼容现有调用者,但不再使用。
|
||||
数据来源是 PopulateSha1MapStore 填充的全局存储器。
|
||||
"""
|
||||
if sha1_list is None or mod_list is None:
|
||||
return 0
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||||
return 0
|
||||
count: int = 0
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
if count >= MAX_INCLUDES:
|
||||
break
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||
string.strcpy(sha1_list + t.CSizeT(count) * 17, StubMerger._sha1_store_arr + idx)
|
||||
string.strcpy(mod_list + t.CSizeT(count) * 64, StubMerger._sha1_store_mod + idx2)
|
||||
count += 1
|
||||
return count
|
||||
# ============================================================
|
||||
# _FindSha1ByModName - 从模块名查找 SHA1(精确匹配)
|
||||
#
|
||||
# 在 sha1_arr/mod_arr 映射中查找模块名对应的 SHA1。
|
||||
# 用于依赖图分析:模块名 → SHA1。
|
||||
#
|
||||
# Args:
|
||||
# sha1_arr: SHA1 数组(每个 17 字节)
|
||||
# mod_arr: 模块名数组(每个 64 字节)
|
||||
# count: 映射条目数
|
||||
# mod_name: 要查找的模块名
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向 sha1_arr 内部,无需释放),未找到返回 None
|
||||
# ============================================================
|
||||
def _FindSha1ByModName(sha1_arr: str, mod_arr: str,
|
||||
count: int, mod_name: str) -> str:
|
||||
"""从模块名查找 SHA1(精确匹配 + 包名回退)
|
||||
|
||||
精确匹配失败时,尝试 "{mod_name}.__init__" 回退,
|
||||
支持 import ast(包)→ ast.__init__ 的 SHA1 查找。
|
||||
"""
|
||||
if sha1_arr is None or mod_arr is None or mod_name is None:
|
||||
return None
|
||||
if count <= 0:
|
||||
return None
|
||||
# 第一遍:精确匹配
|
||||
for i in range(count):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(mod_arr + idx, mod_name) == 0:
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
return sha1_arr + sidx
|
||||
# 第二遍:包名回退("ast" → "ast.__init__")
|
||||
nm_len: t.CSizeT = string.strlen(mod_name)
|
||||
init_buf: bytes = stdlib.malloc(nm_len + 12)
|
||||
if init_buf is not None:
|
||||
viperlib.snprintf(init_buf, nm_len + 12, "%s.__init__", mod_name)
|
||||
for i in range(count):
|
||||
idx2: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(mod_arr + idx2, init_buf) == 0:
|
||||
sidx2: t.CSizeT = t.CSizeT(i) * 17
|
||||
stdlib.free(init_buf)
|
||||
return sha1_arr + sidx2
|
||||
stdlib.free(init_buf)
|
||||
return None
|
||||
# ============================================================
|
||||
# _AddSha1ToSet - 将 SHA1 加入集合(去重)
|
||||
#
|
||||
# 检查 SHA1 是否已在集合中,若不在则加入。返回新的 count。
|
||||
#
|
||||
# Args:
|
||||
# set_buf: SHA1 集合缓冲区(每个 17 字节)
|
||||
# count: 当前集合中的 SHA1 数量
|
||||
# sha1: 要加入的 SHA1
|
||||
#
|
||||
# Returns:
|
||||
# 新的 count(如果已存在则不变)
|
||||
# ============================================================
|
||||
def _AddSha1ToSet(set_buf: str, count: int, sha1: str) -> int:
|
||||
"""将 SHA1 加入集合,返回新 count"""
|
||||
if set_buf is None or sha1 is None:
|
||||
return count
|
||||
for i in range(count):
|
||||
idx: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(set_buf + idx, sha1) == 0:
|
||||
return count
|
||||
if count < MAX_INCLUDES_SHA1:
|
||||
idx: t.CSizeT = t.CSizeT(count) * 17
|
||||
string.strcpy(set_buf + idx, sha1)
|
||||
return count + 1
|
||||
return count
|
||||
@@ -0,0 +1,409 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import llvmlite
|
||||
import w32.win32file as win32file
|
||||
import w32.win32base as win32base
|
||||
import w32.fileio as fileio
|
||||
import viperlib
|
||||
import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
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.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerTopo as StubMergerTopo
|
||||
import lib.core.StubMergerIR as StubMergerIR
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# StubMergerStore - StubMerger 拆分(阶段 E):StubMergerStore
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# PopulateSha1MapStore - 从扫描结果填充全局 SHA1 映射存储器
|
||||
#
|
||||
# 遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||||
# 模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||||
# 内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||
#
|
||||
# Args:
|
||||
# scan_result: IncludesScanner 扫描结果
|
||||
#
|
||||
# Returns:
|
||||
# 填充的条目数,-1 表示失败
|
||||
# ============================================================
|
||||
def PopulateSha1MapStore(scan_result: IncludesScanner.ScanResult | t.CPtr) -> int:
|
||||
"""从扫描结果填充全局 SHA1 映射存储器
|
||||
|
||||
遍历 ScanResult.Entries,为每个条目构建 sha1→module_name 映射。
|
||||
模块名通过 _PathToModuleName(includes/rel_path) 计算。
|
||||
内存用 stdlib.malloc 分配(全局存储器,不随 mbuddy 释放)。
|
||||
"""
|
||||
if scan_result is None:
|
||||
return -1
|
||||
# 释放旧存储器
|
||||
if StubMerger._sha1_store_arr is not None:
|
||||
stdlib.free(StubMerger._sha1_store_arr)
|
||||
if StubMerger._sha1_store_mod is not None:
|
||||
stdlib.free(StubMerger._sha1_store_mod)
|
||||
if StubMerger._sha1_store_rel is not None:
|
||||
stdlib.free(StubMerger._sha1_store_rel)
|
||||
if StubMerger._sha1_store_incdir is not None:
|
||||
stdlib.free(StubMerger._sha1_store_incdir)
|
||||
StubMerger._sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17)
|
||||
StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
|
||||
StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||
StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN)
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||||
return -1
|
||||
string.memset(StubMerger._sha1_store_arr, 0, MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64)
|
||||
string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||
string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
|
||||
StubMerger._sha1_store_count = 0
|
||||
p_bad: int = 0
|
||||
entry_size_p: t.CSizeT = IncludesScanner.FileEntry.__sizeof__()
|
||||
for i in range(scan_result.Count):
|
||||
if StubMerger._sha1_store_count >= MAX_INCLUDES:
|
||||
VLogger.error("includes SHA1 存储超上限,终止", "StubMerger")
|
||||
ea: t.CUInt64T = t.CUInt64T(scan_result.Entries) + i * entry_size_p
|
||||
ent: IncludesScanner.FileEntry | t.CPtr = (IncludesScanner.FileEntry | t.CPtr)(t.CVoid(ea, t.CPtr))
|
||||
if ent is None or ent.Sha1 is None or ent.RelPath is None:
|
||||
p_bad += 1
|
||||
continue
|
||||
# 构建完整路径 includes/{RelPath}(_PathToModuleName 需要)
|
||||
rp_len: t.CSizeT = string.strlen(ent.RelPath)
|
||||
full_path_buf: bytes = stdlib.malloc(rp_len + 10)
|
||||
if full_path_buf is None:
|
||||
p_bad += 1
|
||||
continue
|
||||
viperlib.snprintf(full_path_buf, rp_len + 10, "includes/%s", ent.RelPath)
|
||||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||||
stdlib.free(full_path_buf)
|
||||
if mod_name is not None:
|
||||
idx: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
|
||||
string.strcpy(StubMerger._sha1_store_arr + idx, ent.Sha1)
|
||||
idx2: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64
|
||||
mn_len: t.CSizeT = string.strlen(mod_name)
|
||||
if mn_len < 64:
|
||||
string.strcpy(StubMerger._sha1_store_mod + idx2, mod_name)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_mod + idx2, mod_name, 63)
|
||||
StubMerger._sha1_store_mod[idx2 + 63] = '\0'
|
||||
stdlib.free(mod_name)
|
||||
# 保存 rel_path(供 Phase2 3.5 编译缺失 includes 使用)
|
||||
idx3: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN
|
||||
if rp_len < MAX_REL_PATH_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_rel + idx3, ent.RelPath)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_rel + idx3, ent.RelPath, MAX_REL_PATH_LEN - 1)
|
||||
StubMerger._sha1_store_rel[idx3 + MAX_REL_PATH_LEN - 1] = '\0'
|
||||
# 保存所属 includes 根目录(Phase2 预注册/按需编译拼路径用)
|
||||
idx_inc: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN
|
||||
if ent.IncDir is not None:
|
||||
icd_len: t.CSizeT = string.strlen(ent.IncDir)
|
||||
if icd_len < MAX_INC_DIR_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_incdir + idx_inc, ent.IncDir, MAX_INC_DIR_LEN - 1)
|
||||
StubMerger._sha1_store_incdir[idx_inc + MAX_INC_DIR_LEN - 1] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
if p_bad > 0:
|
||||
fb_pbad: str = VLogger.fmt_buf()
|
||||
if fb_pbad is not None:
|
||||
viperlib.snprintf(fb_pbad, 1024, "includes SHA1 存储有 %d 个条目失败", p_bad)
|
||||
VLogger.error(fb_pbad, "StubMerger")
|
||||
return StubMerger._sha1_store_count
|
||||
# ============================================================
|
||||
# AppendToSha1MapStore - 追加条目到全局 SHA1 映射存储器
|
||||
#
|
||||
# Phase1 调用 PopulateSha1MapStore 填充 includes 文件,
|
||||
# Phase2 扫描 App 源文件后调用此函数追加 App 模块条目,
|
||||
# 确保编译 App 自身时跨模块 CDefine 查找能命中 App 模块
|
||||
# (如 StubMerger.MAX_INCLUDES 在编译 Phase2 时通过
|
||||
# _build_source_path_from_sha1 查找 StubMerger 的源路径)。
|
||||
#
|
||||
# 若存储器未初始化(PopulateSha1MapStore 未调用),自动初始化。
|
||||
# 若 SHA1 已存在(去重),跳过。
|
||||
#
|
||||
# Args:
|
||||
# sha1: SHA1 字符串(16 字符 + null)
|
||||
# rel_path: 相对路径(如 "lib/core/StubMerger.vp",
|
||||
# 不含 includes/ 前缀,与 _sha1_map.txt 格式一致)
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功(含去重跳过),1 失败
|
||||
# ============================================================
|
||||
def AppendToSha1MapStore(sha1: str, rel_path: str) -> int:
|
||||
"""追加条目到全局 SHA1 映射存储器(Phase2 用)"""
|
||||
if sha1 is None or rel_path is None:
|
||||
return 1
|
||||
# 存储器未初始化:自动初始化(Phase2 可能先于 Phase1 调用)
|
||||
if StubMerger._sha1_store_arr is None:
|
||||
StubMerger._sha1_store_arr = stdlib.malloc(MAX_INCLUDES * 17)
|
||||
StubMerger._sha1_store_mod = stdlib.malloc(MAX_INCLUDES * 64)
|
||||
StubMerger._sha1_store_rel = stdlib.malloc(MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||
StubMerger._sha1_store_incdir = stdlib.malloc(MAX_INCLUDES * MAX_INC_DIR_LEN)
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None or StubMerger._sha1_store_incdir is None:
|
||||
return 1
|
||||
string.memset(StubMerger._sha1_store_arr, 0, MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._sha1_store_mod, 0, MAX_INCLUDES * 64)
|
||||
string.memset(StubMerger._sha1_store_rel, 0, MAX_INCLUDES * MAX_REL_PATH_LEN)
|
||||
string.memset(StubMerger._sha1_store_incdir, 0, MAX_INCLUDES * MAX_INC_DIR_LEN)
|
||||
StubMerger._sha1_store_count = 0
|
||||
if StubMerger._sha1_store_count >= MAX_INCLUDES:
|
||||
return 1
|
||||
# 去重:若 SHA1 已存在则跳过
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
sidx_d: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx_d, sha1) == 0:
|
||||
return 0
|
||||
# 模块名:rel_path "lib/core/StubMerger.vp" → "lib.core.StubMerger"
|
||||
full_path_buf: bytes = stdlib.malloc(string.strlen(rel_path) + 10)
|
||||
if full_path_buf is None:
|
||||
return 1
|
||||
viperlib.snprintf(full_path_buf, string.strlen(rel_path) + 10, "includes/%s", rel_path)
|
||||
mod_name: str = Utils.PathToModuleName(full_path_buf, 1)
|
||||
stdlib.free(full_path_buf)
|
||||
if mod_name is None:
|
||||
return 1
|
||||
# 写入 SHA1
|
||||
idx_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 17
|
||||
string.strcpy(StubMerger._sha1_store_arr + idx_a, sha1)
|
||||
# 写入模块名
|
||||
idx_m: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * 64
|
||||
mn_len: t.CSizeT = string.strlen(mod_name)
|
||||
if mn_len < 64:
|
||||
string.strcpy(StubMerger._sha1_store_mod + idx_m, mod_name)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_mod + idx_m, mod_name, 63)
|
||||
StubMerger._sha1_store_mod[idx_m + 63] = '\0'
|
||||
stdlib.free(mod_name)
|
||||
# 写入相对路径
|
||||
idx_r: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_REL_PATH_LEN
|
||||
rp_len: t.CSizeT = string.strlen(rel_path)
|
||||
if rp_len < MAX_REL_PATH_LEN:
|
||||
string.strcpy(StubMerger._sha1_store_rel + idx_r, rel_path)
|
||||
else:
|
||||
string.strncpy(StubMerger._sha1_store_rel + idx_r, rel_path, MAX_REL_PATH_LEN - 1)
|
||||
StubMerger._sha1_store_rel[idx_r + MAX_REL_PATH_LEN - 1] = '\0'
|
||||
# App 源文件不属于任何 includes 目录:IncDir 留空(Phase2 回退 includes_dir 参数)
|
||||
idx_inc_a: t.CSizeT = t.CSizeT(StubMerger._sha1_store_count) * MAX_INC_DIR_LEN
|
||||
StubMerger._sha1_store_incdir[idx_inc_a] = '\0'
|
||||
StubMerger._sha1_store_count += 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# GetSha1StoreCount - 获取全局存储器条目数
|
||||
# ============================================================
|
||||
def GetSha1StoreCount() -> int:
|
||||
"""返回全局 SHA1 存储器的条目数"""
|
||||
return StubMerger._sha1_store_count
|
||||
# ============================================================
|
||||
# LookupSha1ByModName - 从模块名查找 SHA1(直接查全局存储器)
|
||||
#
|
||||
# 精确匹配失败时,尝试 "{mod_name}.__init__" 回退,
|
||||
# 支持 import ast(包)→ ast.__init__ 的 SHA1 查找。
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||||
# ============================================================
|
||||
def LookupSha1ByModName(mod_name: str) -> str:
|
||||
"""从模块名查找 SHA1(精确匹配 + 包名回退),委托通用实现 _FindSha1ByModName"""
|
||||
return StubMergerIR._FindSha1ByModName(StubMerger._sha1_store_arr, StubMerger._sha1_store_mod, StubMerger._sha1_store_count, mod_name)
|
||||
# ============================================================
|
||||
# LookupSha1ByModNameSuffix - 后缀匹配查找模块 SHA1
|
||||
#
|
||||
# 用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点),
|
||||
# 去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。
|
||||
# 包含三种匹配方式:精确、后缀、反向后缀。
|
||||
#
|
||||
# Returns:
|
||||
# SHA1 字符串指针(指向全局存储器内部,无需释放),None 未找到
|
||||
# ============================================================
|
||||
def LookupSha1ByModNameSuffix(mod_suffix: str) -> str:
|
||||
"""后缀匹配查找模块 SHA1"""
|
||||
if mod_suffix is None:
|
||||
return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None:
|
||||
return None
|
||||
if StubMerger._sha1_store_count <= 0:
|
||||
return None
|
||||
suffix_len_sf: t.CSizeT = string.strlen(mod_suffix)
|
||||
if suffix_len_sf == 0:
|
||||
return None
|
||||
i_sf: int
|
||||
for i_sf in range(StubMerger._sha1_store_count):
|
||||
idx_sf: t.CSizeT = t.CSizeT(i_sf) * 64
|
||||
mod_name_sf: str = StubMerger._sha1_store_mod + idx_sf
|
||||
mod_len_sf: t.CSizeT = string.strlen(mod_name_sf)
|
||||
if mod_len_sf == 0:
|
||||
continue
|
||||
# 精确匹配
|
||||
if mod_len_sf == suffix_len_sf:
|
||||
if string.strcmp(mod_name_sf, mod_suffix) == 0:
|
||||
sidx_sf: t.CSizeT = t.CSizeT(i_sf) * 17
|
||||
return StubMerger._sha1_store_arr + sidx_sf
|
||||
# 后缀匹配:mod_name 以 "." + mod_suffix 结尾
|
||||
if mod_len_sf > suffix_len_sf:
|
||||
if mod_name_sf[mod_len_sf - suffix_len_sf - 1] == '.':
|
||||
cmp_start_sf: str = mod_name_sf + mod_len_sf - suffix_len_sf
|
||||
if string.strcmp(cmp_start_sf, mod_suffix) == 0:
|
||||
sidx2_sf: t.CSizeT = t.CSizeT(i_sf) * 17
|
||||
return StubMerger._sha1_store_arr + sidx2_sf
|
||||
# 反向后缀匹配:mod_suffix 以 "." + mod_name 结尾
|
||||
if suffix_len_sf > mod_len_sf:
|
||||
if mod_suffix[suffix_len_sf - mod_len_sf - 1] == '.':
|
||||
cmp_start_rev_sf: str = mod_suffix + suffix_len_sf - mod_len_sf
|
||||
if string.strcmp(cmp_start_rev_sf, mod_name_sf) == 0:
|
||||
sidx_rev_sf: t.CSizeT = t.CSizeT(i_sf) * 17
|
||||
return StubMerger._sha1_store_arr + sidx_rev_sf
|
||||
return None
|
||||
# ============================================================
|
||||
# PopulateIncludesDeps - 将 includes 文件的依赖存入内存
|
||||
#
|
||||
# Phase B+ 前用 declare_only 翻译 includes 文件,提取 _imported_modules
|
||||
# 后调用此函数存入内存。_BuildReachableSha1Set 从内存读取,不读 deps.txt。
|
||||
#
|
||||
# Args:
|
||||
# sha1: includes 文件的 SHA1(16字符)
|
||||
# deps_str: 依赖模块名字符串(空格分隔,如 "t c stdint string")
|
||||
#
|
||||
# Returns:
|
||||
# 0 成功,非 0 失败
|
||||
# ============================================================
|
||||
def PopulateIncludesDeps(sha1: str, deps_str: str) -> int:
|
||||
"""将 includes 文件的依赖存入内存"""
|
||||
if sha1 is None:
|
||||
return 1
|
||||
# 延迟初始化
|
||||
if StubMerger._includes_deps_sha1 is None:
|
||||
StubMerger._includes_deps_sha1 = stdlib.malloc(MAX_INCLUDES * 17)
|
||||
StubMerger._includes_deps_str = stdlib.malloc(MAX_INCLUDES * MAX_DEPS_STR_LEN)
|
||||
if StubMerger._includes_deps_sha1 is None or StubMerger._includes_deps_str is None:
|
||||
return 1
|
||||
string.memset(StubMerger._includes_deps_sha1, 0, MAX_INCLUDES * 17)
|
||||
string.memset(StubMerger._includes_deps_str, 0, MAX_INCLUDES * MAX_DEPS_STR_LEN)
|
||||
StubMerger._includes_deps_count = 0
|
||||
if StubMerger._includes_deps_count >= MAX_INCLUDES:
|
||||
return 1
|
||||
# 去重:若 SHA1 已存在则跳过
|
||||
for i in range(StubMerger._includes_deps_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||||
return 0
|
||||
# 写入 SHA1
|
||||
idx: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * 17
|
||||
string.strcpy(StubMerger._includes_deps_sha1 + idx, sha1)
|
||||
# 写入依赖字符串
|
||||
idx2: t.CSizeT = t.CSizeT(StubMerger._includes_deps_count) * MAX_DEPS_STR_LEN
|
||||
if deps_str is not None:
|
||||
dl: t.CSizeT = string.strlen(deps_str)
|
||||
if dl < MAX_DEPS_STR_LEN:
|
||||
string.strcpy(StubMerger._includes_deps_str + idx2, deps_str)
|
||||
else:
|
||||
string.strncpy(StubMerger._includes_deps_str + idx2, deps_str, MAX_DEPS_STR_LEN - 1)
|
||||
else:
|
||||
StubMerger._includes_deps_str[idx2] = '\0'
|
||||
StubMerger._includes_deps_count = StubMerger._includes_deps_count + 1
|
||||
return 0
|
||||
# ============================================================
|
||||
# LookupIncludesDeps - 从内存查找 includes 文件的依赖
|
||||
#
|
||||
# Args:
|
||||
# sha1: includes 文件的 SHA1(16字符)
|
||||
#
|
||||
# Returns:
|
||||
# 依赖模块名字符串指针(空格分隔),None 表示未找到
|
||||
# ============================================================
|
||||
def LookupIncludesDeps(sha1: str) -> str:
|
||||
"""从内存查找 includes 文件的依赖"""
|
||||
if sha1 is None or StubMerger._includes_deps_sha1 is None:
|
||||
return None
|
||||
if StubMerger._includes_deps_count <= 0:
|
||||
return None
|
||||
for i in range(StubMerger._includes_deps_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(StubMerger._includes_deps_sha1 + sidx, sha1) == 0:
|
||||
idx2: t.CSizeT = t.CSizeT(i) * MAX_DEPS_STR_LEN
|
||||
return StubMerger._includes_deps_str + idx2
|
||||
return None
|
||||
def GetSha1StoreArrPtr() -> bytes | t.CPtr:
|
||||
"""返回 SHA1 数组指针(每个条目 17 字节)"""
|
||||
return StubMerger._sha1_store_arr
|
||||
def GetSha1StoreModArrPtr() -> bytes | t.CPtr:
|
||||
"""返回模块名数组指针(每个条目 64 字节)"""
|
||||
return StubMerger._sha1_store_mod
|
||||
def GetSha1StoreRelArrPtr() -> bytes | t.CPtr:
|
||||
"""返回相对路径数组指针(每个条目 MAX_REL_PATH_LEN 字节)"""
|
||||
return StubMerger._sha1_store_rel
|
||||
def GetSha1StoreIncdirArrPtr() -> bytes | t.CPtr:
|
||||
"""返回所属 includes 根目录数组指针(每个条目 MAX_INC_DIR_LEN 字节,空串表示不属于任何 includes 目录)"""
|
||||
return StubMerger._sha1_store_incdir
|
||||
# ============================================================
|
||||
# GetSha1StoreArr - 获取全局存储器数组指针(直接遍历用)
|
||||
#
|
||||
# 返回 sha1_arr、mod_arr、rel_arr 三个数组的指针和条目数。
|
||||
# 调用者直接遍历数组:sha1_arr[i*17]、mod_arr[i*64]、rel_arr[i*MAX_REL_PATH_LEN]
|
||||
# 内存归全局存储器所有,调用者不要 free
|
||||
# ============================================================
|
||||
def GetSha1StoreArr(out_sha1_arr: t.CPtr, out_mod_arr: t.CPtr, out_rel_arr: t.CPtr) -> int:
|
||||
"""获取全局存储器数组指针
|
||||
|
||||
out_sha1_arr/out_mod_arr/out_rel_arr 是调用者提供的 t.CPtr 指针,
|
||||
函数将存储器数组指针写入这些位置。
|
||||
返回条目数,-1 失败
|
||||
"""
|
||||
if out_sha1_arr is None or out_mod_arr is None or out_rel_arr is None:
|
||||
return -1
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_mod is None or StubMerger._sha1_store_rel is None:
|
||||
return -1
|
||||
sp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_sha1_arr, t.CPtr))
|
||||
if sp is not None:
|
||||
sp[0] = StubMerger._sha1_store_arr
|
||||
mp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_mod_arr, t.CPtr))
|
||||
if mp is not None:
|
||||
mp[0] = StubMerger._sha1_store_mod
|
||||
rp: t.CPtr = (t.CPtr | t.CPtr)(t.CVoid(out_rel_arr, t.CPtr))
|
||||
if rp is not None:
|
||||
rp[0] = StubMerger._sha1_store_rel
|
||||
return StubMerger._sha1_store_count
|
||||
# ============================================================
|
||||
# LookupSha1RelPath - 通过 SHA1 查找相对路径
|
||||
#
|
||||
# 遍历全局存储器,返回 sha1 对应的相对路径指针(只读,不要 free)。
|
||||
# 用于错误提示:将 sha1 转换为人类可读的文件路径。
|
||||
#
|
||||
# Args:
|
||||
# sha1: SHA1 字符串(16 字符)
|
||||
#
|
||||
# Returns:
|
||||
# 相对路径字符串指针(只读),None=未找到
|
||||
# ============================================================
|
||||
def LookupSha1RelPath(sha1: str) -> str:
|
||||
"""通过 SHA1 查找相对路径,返回只读指针,None=未找到"""
|
||||
if sha1 is None:
|
||||
return None
|
||||
if StubMerger._sha1_store_arr is None or StubMerger._sha1_store_rel is None:
|
||||
return None
|
||||
for i in range(StubMerger._sha1_store_count):
|
||||
sidx: t.CSizeT = t.CSizeT(i) * 17
|
||||
if string.strcmp(StubMerger._sha1_store_arr + sidx, sha1) == 0:
|
||||
ridx: t.CSizeT = t.CSizeT(i) * MAX_REL_PATH_LEN
|
||||
return StubMerger._sha1_store_rel + ridx
|
||||
return None
|
||||
@@ -0,0 +1,168 @@
|
||||
import t, c
|
||||
from stdint import *
|
||||
import memhub
|
||||
import string
|
||||
import stdlib
|
||||
import llvmlite
|
||||
import w32.win32file as win32file
|
||||
import w32.win32base as win32base
|
||||
import w32.fileio as fileio
|
||||
import viperlib
|
||||
import sys
|
||||
import ast
|
||||
import lib.core.VLogger as VLogger
|
||||
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.StubGen.VpiReader as VpiReader
|
||||
import lib.Projectrans.Utils as Utils
|
||||
import lib.Projectrans.Config as Config
|
||||
|
||||
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
import lib.core.StubMergerStore as StubMergerStore
|
||||
import lib.core.StubMergerIR as StubMergerIR
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMerger as StubMerger
|
||||
|
||||
# ============================================================
|
||||
# StubMergerTopo - StubMerger 拆分(阶段 E):StubMergerTopo
|
||||
#
|
||||
# 直接移动模式:函数实现迁至此模块,原 StubMerger.vp 仅保留
|
||||
# 常量/全局变量;调用方经本模块前缀访问。全局变量跨模块经
|
||||
# StubMerger._xxx 访问(main.vp 先例)。
|
||||
# ============================================================
|
||||
|
||||
# ============================================================
|
||||
# BuildTopoSortedIndices - 对可达 includes 逆拓扑排序(被依赖者先)
|
||||
#
|
||||
# 背景:跨模块 vtable 生成要求被依赖模块先完整翻译(如 astaux.vp 继承
|
||||
# base.vp 的 AST,vtable 槽位需 AST.accept 的 TypeStr 已注册到全局表)。
|
||||
# Phase B+ 原先按 store 扫描顺序编译,依赖顺序不保证 → fail-fast 暴露。
|
||||
#
|
||||
# 算法:Kahn 逆拓扑。边 m→d 表示 m 依赖 d(d 在 m 的 deps 中)。
|
||||
# indegree[m] = m 在可达集合内的直接依赖数;
|
||||
# 入度为 0(不依赖任何可达模块)者先输出,输出后对依赖它的模块
|
||||
# 减入度,入度归 0 者入队。结果即"被依赖者先编译"。
|
||||
# reachable_count <= 0 时对全部 store 排序(与既有全量编译行为一致)。
|
||||
#
|
||||
# Args:
|
||||
# store_count / store_sha1_arr / store_mod_arr: store 元数据
|
||||
# reachable_set / reachable_count: 可达集合(_BuildReachableSha1Set 输出)
|
||||
# sorted_idx: 输出数组(store_count+1 个 8 字节槽),前 N 个为拓扑序 store 索引
|
||||
#
|
||||
# Returns:
|
||||
# 拓扑序条数;有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||||
# ============================================================
|
||||
def BuildTopoSortedIndices(store_count: int, store_sha1_arr: bytes,
|
||||
store_mod_arr: bytes, reachable_set: bytes,
|
||||
reachable_count: int,
|
||||
sorted_idx: t.CSizeT | t.CPtr) -> int:
|
||||
"""对可达 includes 逆拓扑排序(被依赖者先),store 索引写入 sorted_idx"""
|
||||
if store_count <= 0 or store_sha1_arr is None or store_mod_arr is None or sorted_idx is None:
|
||||
return 0
|
||||
indegree: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||||
queue: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||||
rel_idx: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(stdlib.malloc(8 * (store_count + 1)))
|
||||
if indegree is None or queue is None or rel_idx is None:
|
||||
if indegree is not None:
|
||||
stdlib.free(indegree)
|
||||
if queue is not None:
|
||||
stdlib.free(queue)
|
||||
if rel_idx is not None:
|
||||
stdlib.free(rel_idx)
|
||||
return 0
|
||||
# 收集可达 store 索引(reachable_count<=0 时全量,对齐既有全量编译行为)
|
||||
rel_count: int = 0
|
||||
i_t: int
|
||||
if reachable_set is None or reachable_count <= 0:
|
||||
for i_t in range(store_count):
|
||||
rel_idx[rel_count] = i_t
|
||||
rel_count += 1
|
||||
else:
|
||||
for i_t in range(store_count):
|
||||
if StubMergerCollect._is_in_sha1_set(store_sha1_arr + t.CSizeT(i_t) * 17, reachable_set, reachable_count) != 0:
|
||||
rel_idx[rel_count] = i_t
|
||||
rel_count += 1
|
||||
# 计算入度:m 在可达集合内的直接依赖数
|
||||
i_r: int
|
||||
for i_r in range(rel_count):
|
||||
si: int = rel_idx[i_r]
|
||||
deps_si: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si) * 17)
|
||||
if deps_si is None:
|
||||
continue
|
||||
dl_si: t.CSizeT = string.strlen(deps_si)
|
||||
dpos: t.CSizeT = 0
|
||||
while dpos < dl_si:
|
||||
dstart: t.CSizeT = dpos
|
||||
while dpos < dl_si and deps_si[dpos] != ' ':
|
||||
dpos += 1
|
||||
dlen: t.CSizeT = dpos - dstart
|
||||
if dpos < dl_si:
|
||||
dpos += 1
|
||||
if dlen == 0:
|
||||
continue
|
||||
dname_buf: bytes = stdlib.malloc(dlen + 1)
|
||||
if dname_buf is None:
|
||||
continue
|
||||
string.strncpy(dname_buf, deps_si + dstart, dlen)
|
||||
dname_buf[dlen] = '\0'
|
||||
dsha1: str = StubMergerIR._FindSha1ByModName(store_sha1_arr, store_mod_arr, store_count, dname_buf)
|
||||
stdlib.free(dname_buf)
|
||||
if dsha1 is not None and StubMergerCollect._is_in_sha1_set(dsha1, reachable_set, reachable_count) != 0:
|
||||
indegree[si] = indegree[si] + 1
|
||||
# Kahn:入度为 0(不依赖任何可达模块)者先出 → 最先编译
|
||||
q_head: int = 0
|
||||
q_tail: int = 0
|
||||
for i_r in range(rel_count):
|
||||
si2: int = rel_idx[i_r]
|
||||
if indegree[si2] == 0:
|
||||
queue[q_tail] = si2
|
||||
q_tail += 1
|
||||
out_count: int = 0
|
||||
while q_head < q_tail:
|
||||
m: int = queue[q_head]
|
||||
q_head += 1
|
||||
sorted_idx[out_count] = m
|
||||
out_count += 1
|
||||
# 对依赖 m 的可达模块减入度
|
||||
mod_m: str = store_mod_arr + t.CSizeT(m) * 64
|
||||
mod_m_len: t.CSizeT = string.strlen(mod_m)
|
||||
for i_r in range(rel_count):
|
||||
si3: int = rel_idx[i_r]
|
||||
if indegree[si3] == 0:
|
||||
continue
|
||||
deps_si3: str = StubMergerStore.LookupIncludesDeps(store_sha1_arr + t.CSizeT(si3) * 17)
|
||||
if deps_si3 is None:
|
||||
continue
|
||||
dl_si3: t.CSizeT = string.strlen(deps_si3)
|
||||
dpos3: t.CSizeT = 0
|
||||
found_dep: int = 0
|
||||
while dpos3 < dl_si3 and found_dep == 0:
|
||||
dstart3: t.CSizeT = dpos3
|
||||
while dpos3 < dl_si3 and deps_si3[dpos3] != ' ':
|
||||
dpos3 += 1
|
||||
dlen3: t.CSizeT = dpos3 - dstart3
|
||||
if dpos3 < dl_si3:
|
||||
dpos3 += 1
|
||||
if dlen3 == 0:
|
||||
continue
|
||||
if dlen3 == mod_m_len and string.strncmp(deps_si3 + dstart3, mod_m, mod_m_len) == 0:
|
||||
found_dep = 1
|
||||
if found_dep == 1:
|
||||
indegree[si3] = indegree[si3] - 1
|
||||
if indegree[si3] == 0:
|
||||
queue[q_tail] = si3
|
||||
q_tail += 1
|
||||
# 有环时剩余条目按 store 顺序补齐(避免漏编译)
|
||||
for i_r in range(rel_count):
|
||||
si4: int = rel_idx[i_r]
|
||||
if indegree[si4] > 0:
|
||||
sorted_idx[out_count] = si4
|
||||
out_count += 1
|
||||
stdlib.free(indegree)
|
||||
stdlib.free(queue)
|
||||
stdlib.free(rel_idx)
|
||||
return out_count
|
||||
+5
-3
@@ -47,6 +47,8 @@ import subprocess
|
||||
import viperlib
|
||||
import hashlib
|
||||
import t, c
|
||||
import lib.core.StubMergerBuild as StubMergerBuild
|
||||
import lib.core.StubMergerCollect as StubMergerCollect
|
||||
|
||||
|
||||
# Main Pool 1 GiB
|
||||
@@ -599,7 +601,7 @@ TermiNexus Age %sY\n\n""", VIPER_VERSION, RUNTIME_VERSION, TPV_VERSION, TERMINEX
|
||||
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: str = StubMerger._sliced_path(temp_dir, td_len_sf, module_name, "stub.ll")
|
||||
sf_stub_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_sf, module_name, "stub.ll")
|
||||
if sf_stub_path is not None:
|
||||
sf_f: fileio.File | t.CPtr = fileio.File(sf_stub_path, fileio.MODE.W)
|
||||
if not sf_f.closed:
|
||||
@@ -612,7 +614,7 @@ TermiNexus Age %sY\n\n""", VIPER_VERSION, RUNTIME_VERSION, TPV_VERSION, TERMINEX
|
||||
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: str = StubMerger._sliced_path(temp_dir, td_len_sf, module_name, "text.ll")
|
||||
sf_text_path: str = StubMergerCollect._sliced_path(temp_dir, td_len_sf, module_name, "text.ll")
|
||||
if sf_text_path is not None:
|
||||
sf_tf: fileio.File | t.CPtr = fileio.File(sf_text_path, fileio.MODE.W)
|
||||
if not sf_tf.closed:
|
||||
@@ -637,7 +639,7 @@ TermiNexus Age %sY\n\n""", VIPER_VERSION, RUNTIME_VERSION, TPV_VERSION, TERMINEX
|
||||
SF_COMBINED_SIZE: t.CSizeT = 4194304 # 4MB
|
||||
combined_buf: bytes = stdlib.malloc(SF_COMBINED_SIZE)
|
||||
if combined_buf is not None:
|
||||
combined_len: t.CSizeT = StubMerger.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE)
|
||||
combined_len: t.CSizeT = StubMergerBuild.BuildCombinedIR(temp_dir, module_name, combined_buf, SF_COMBINED_SIZE)
|
||||
if combined_len > 0:
|
||||
final_ir = combined_buf
|
||||
final_ir_len = combined_len
|
||||
|
||||
Reference in new issue
Block a user