From 9b56d1d75c6dce064f8f99e1b9a15a2d8a6d0348 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Wed, 26 Aug 2026 17:23:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20Phase=20B+=20=E4=B8=8E=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E8=B7=B3=E8=BF=87=20App=20=E6=BA=90=E6=96=87=E4=BB=B6?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E9=93=BE=E6=8E=A5=20duplicate=20sym?= =?UTF-8?q?bol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scene3D 的 App 源文件 gfx.vp 同时被 includes 扫描(includes 目录 ../.. =ViperOS 含 Apps/),且被 main.vp import → 进入可达集合 → Phase B+ 编译 一份 .obj 到 includes_binary,与 Phase A/B 编译到 output/ 的 .obj 同 sha1 同符号(9aab6ff7475c1bbf.Vec3.__init__ 等)→ ld.lld duplicate symbol。 - Phase B+ 编译循环:sha1 命中 App 源文件(entries)则跳过(其 .obj 已由 Phase A/B 产出到 output/) - 链接期 reachable obj 收集:同样跳过 App 源文件,避免 includes_binary 残留同 sha1 .obj 与 output obj 重复入链 --- App/lib/Phase/Phase2/__init__.vp | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/App/lib/Phase/Phase2/__init__.vp b/App/lib/Phase/Phase2/__init__.vp index bf73d76..54362e7 100644 --- a/App/lib/Phase/Phase2/__init__.vp +++ b/App/lib/Phase/Phase2/__init__.vp @@ -1323,6 +1323,22 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, # 获取当前条目的 SHA1 和 rel_path inc_sha1_mi: str = store_sha1_arr_mi + t.CSizeT(ti) * 17 inc_rel_mi: str = store_rel_arr_mi + t.CSizeT(ti) * StubMerger.MAX_REL_PATH_LEN + # 跳过 App 源文件:App 文件可能同时被 includes 扫描(includes + # 目录含 source_dir 上层,如 ViperOS 含 Apps/),且被其他 App + # import(Scene3D 的 gfx.vp)→ 在可达集合中。若 Phase B+ 再编译 + # 一份 .obj 到 includes_binary,与 Phase A/B 编译到 output/ 的 + # .obj 同 sha1 同符号 → 链接 duplicate symbol + # (9aab6ff7475c1bbf.Vec3.__init__ 等,Scene3D 根因)。 + app_skip_mi: int = 0 + for ai_mi in range(file_count): + ea_ap: t.CUInt64T = t.CUInt64T(entries) + ai_mi * entry_size + ent_ap: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_ap, t.CPtr)) + if ent_ap is not None and ent_ap.Sha1 is not None: + if string.strcmp(ent_ap.Sha1, inc_sha1_mi) == 0: + app_skip_mi = 1 + break + if app_skip_mi != 0: + continue # 检查 .obj 是否已存在于 includes.binary(切片子目录) ibd_len_mi: t.CSizeT = string.strlen(includes_binary_dir) check_pat_mi: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_mi, inc_sha1_mi, "obj") @@ -1612,6 +1628,20 @@ def RunMultiFileProject(mb: memhub.MemBuddy | t.CPtr, rsha1_pc: str = reachable_set + t.CSizeT(ri_pc) * 17 if rsha1_pc[0] == '\0': continue + # 跳过 App 源文件:其 .obj 已在 output/(Phase A/B 编译,obj_paths + # 已入 final_obj_paths),若 includes_binary 残留同 sha1 的 .obj + # (上一轮/缓存),收集进来会与 output obj 同符号 → 链接 + # duplicate symbol(Scene3D gfx 9aab 根因)。 + app_skip_pc: int = 0 + for ai_pc in range(file_count): + ea_pc: t.CUInt64T = t.CUInt64T(entries) + ai_pc * entry_size + ent_pc: SrcFileEntry | t.CPtr = (SrcFileEntry | t.CPtr)(t.CVoid(ea_pc, t.CPtr)) + if ent_pc is not None and ent_pc.Sha1 is not None: + if string.strcmp(ent_pc.Sha1, rsha1_pc) == 0: + app_skip_pc = 1 + break + if app_skip_pc != 0: + continue obj_path_pc: str = StubMergerCollect._sliced_path(includes_binary_dir, ibd_len_pc, rsha1_pc, "obj") if obj_path_pc is not None: # 检查 .obj 文件是否存在