修正了种子编译器的错误

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

View File

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