fix(generic): 恢复泛型特化发射主路径
补回 _specialize_generic_class 的 deepcopy/改名/字段与方法 T 替换/_EmitClassLlvm 发射逻辑,list[...].__len__ 与 get 正常生成;源码不再支持 CPtr[...],统一写 T*;编译错误只由主进程输出一次。
This commit is contained in:
1 parent
09553401e7
commit
369afb5011
13 files changed
+413
-95
No files matched your search
@@ -27,6 +27,15 @@ from StubGen import PythonToStubConverter
|
||||
from lib.core.LLVMCG.IRMetadataFix import SanitizeIRMetadata
|
||||
|
||||
|
||||
class ReportedCompileError(RuntimeError):
|
||||
"""主进程已输出完整编译错误(含源码定位)的终止信号。
|
||||
|
||||
该异常只用于"错误已经打印过"的路径:main()/run() 抛出后,
|
||||
顶层入口(Projectrans.py)不得再次打印错误内容,直接以失败退出码结束,
|
||||
否则同一错误会在 worker/主进程/顶层各出现一遍。
|
||||
"""
|
||||
|
||||
|
||||
# PROF 热点:nt._path_isfile 2.6 万次 16.4s(Windows 磁盘 stat ~0.6ms/次)。
|
||||
# 编译进程内文件状态稳定(obj/ll 一旦生成不删除、不被移动),用模块级缓存
|
||||
# 避免重复 stat。仅用于"存在性检查"类调用(不用于内容变化的判断)。
|
||||
@@ -763,11 +772,9 @@ def _parallel_translate_worker(src_path: str, out_path: str, src_root: str, temp
|
||||
trans._translate_file(src_path, out_path, prebuilt_ModuleSha1Map=prebuilt_ModuleSha1Map, dwarf_enabled=dwarf_enabled)
|
||||
return ('ok', src_path, '')
|
||||
except Exception as e:
|
||||
# fail-fast:只输出单行错误(含源码定位),不打印 Python 内部调用栈
|
||||
sys.stderr.write(
|
||||
f"[FATAL] 翻译失败: {src_path}\n{type(e).__name__}: {e}\n")
|
||||
sys.stderr.flush()
|
||||
os._exit(88)
|
||||
# fail-fast:worker 不写 stderr,只把错误(含源码定位)返回主进程;
|
||||
# 由主进程统一输出一次,避免同一错误打印两遍。
|
||||
return ('error', src_path, f'{type(e).__name__}: {e}')
|
||||
|
||||
|
||||
def _parallel_translate_batch(batch: list, src_root: str, temp_dir: str, output_dir: str,
|
||||
@@ -787,7 +794,10 @@ def _parallel_translate_batch(batch: list, src_root: str, temp_dir: str, output_
|
||||
批内每个文件翻译前从 symbol_table_bytes 反序列化出干净副本,前文件的
|
||||
符号写入不会残留到后文件(否则跨模块 struct 类型前缀错位)。
|
||||
返回 (错误列表[(src_path, err)], batch, per_file_times[(src_path, elapsed, rel)])。
|
||||
错误只回传、不写 stderr:完整错误由主进程统一输出一次(含源码定位)。
|
||||
"""
|
||||
_current_src: str = batch[0][1] if batch else ''
|
||||
per_file_times: list[tuple[str, float, str]] = []
|
||||
try:
|
||||
trans = Phase2Translator(src_root, temp_dir, output_dir,
|
||||
compile_cmd='llc', include_dirs=include_dirs,
|
||||
@@ -830,28 +840,21 @@ def _parallel_translate_batch(batch: list, src_root: str, temp_dir: str, output_
|
||||
trans._build_shared_symbol_data()
|
||||
|
||||
batch_errors: list = []
|
||||
per_file_times: list[tuple[str, float, str]] = []
|
||||
for _i, src_path, out_path, _sha1, msm in batch:
|
||||
_f0: float = time.time()
|
||||
try:
|
||||
# 每文件前重置 SymbolTable 为干净副本(防跨文件污染)
|
||||
if symbol_table_bytes is not None:
|
||||
trans._shared_symbol_table = pickle.loads(symbol_table_bytes)
|
||||
trans._shared_symbol_table.translator = None
|
||||
trans._translate_file(src_path, out_path, prebuilt_ModuleSha1Map=msm, dwarf_enabled=dwarf_enabled)
|
||||
per_file_times.append((src_path, time.time() - _f0, os.path.relpath(src_path, src_root)))
|
||||
except Exception as e:
|
||||
# fail-fast(2026-08-18):任意文件编译出错立即终止整个编译进程,
|
||||
# 不再收集错误继续翻译批内剩余文件(避免浪费大量时间)。主进程
|
||||
# 收到 BrokenProcessPool/future 异常后取消全部剩余批次退出。
|
||||
sys.stderr.write(
|
||||
f"[FATAL] 文件翻译失败: {src_path}\n"
|
||||
f"{type(e).__name__}: {e}\n")
|
||||
sys.stderr.flush()
|
||||
os._exit(88)
|
||||
_current_src = src_path
|
||||
# 每文件前重置 SymbolTable 为干净副本(防跨文件污染)
|
||||
if symbol_table_bytes is not None:
|
||||
trans._shared_symbol_table = pickle.loads(symbol_table_bytes)
|
||||
trans._shared_symbol_table.translator = None
|
||||
trans._translate_file(src_path, out_path, prebuilt_ModuleSha1Map=msm, dwarf_enabled=dwarf_enabled)
|
||||
per_file_times.append((src_path, time.time() - _f0, os.path.relpath(src_path, src_root)))
|
||||
return (batch_errors, batch, per_file_times)
|
||||
except Exception as e:
|
||||
return ([(item[1], f'{type(e).__name__}: {e}') for item in batch], batch, [])
|
||||
# fail-fast:任意文件编译出错立即终止本批(不再翻译批内剩余文件)。
|
||||
# worker 不写 stderr —— 错误(含源码定位)随返回值交给主进程统一输出一次。
|
||||
_src: str = _current_src or (batch[0][1] if batch else '')
|
||||
return ([(_src, f'{type(e).__name__}: {e}')], batch, per_file_times)
|
||||
|
||||
|
||||
# ==================================================================
|
||||
@@ -1709,7 +1712,6 @@ class Phase2Translator:
|
||||
_vlog().warning(f"符号表序列化失败({e}),worker将自行构建")
|
||||
shared_pickle_path = ''
|
||||
|
||||
errors = []
|
||||
# 复用 self._executor_pool:避免局部变量 GC 时 finalizer 阻塞 ~99s
|
||||
# (join_executor_internals 在 GC 时同步等待 worker 退出队列)
|
||||
if self._executor_pool is None:
|
||||
@@ -1770,17 +1772,11 @@ class Phase2Translator:
|
||||
bidx, rel_first, bcount = futures[future]
|
||||
try:
|
||||
batch_errors, batch, per_file_times = future.result()
|
||||
for src, elapsed, rel in per_file_times:
|
||||
done_files += 1
|
||||
_vlog().info(f" [{done_files}/{total_files}] {rel} ({elapsed:.1f}s)")
|
||||
for src, err in batch_errors:
|
||||
rel = os.path.relpath(src, self.src_root)
|
||||
_vlog().error(f" {rel}: {err}")
|
||||
errors.append((rel, err))
|
||||
_vlog().info(f" [批次完成] {bcount} 文件, 首个 {rel_first}")
|
||||
except ReportedCompileError:
|
||||
raise
|
||||
except Exception as e:
|
||||
# fail-fast:worker 已 os._exit(文件编译出错)或进程池
|
||||
# 已 broken → 立即取消全部剩余批次并终止编译,不空等。
|
||||
# fail-fast:进程池已 broken(worker 异常退出)→ 取消
|
||||
# 全部剩余批次并终止编译,不空等。
|
||||
_vlog().error(f" 批次 {bidx} 异常(worker 已终止): {e}")
|
||||
for fut in futures:
|
||||
if not fut.done():
|
||||
@@ -1788,8 +1784,26 @@ class Phase2Translator:
|
||||
if self._executor_pool is not None:
|
||||
self._executor_pool.shutdown(wait=False, cancel_futures=True)
|
||||
self._executor_pool = None
|
||||
raise RuntimeError(
|
||||
f"批次 {bidx} worker 异常终止,编译立即停止: {e}")
|
||||
raise ReportedCompileError(
|
||||
f"批次 {bidx} worker 异常终止,编译立即停止") from None
|
||||
if batch_errors:
|
||||
# worker 只回传错误、不写 stderr:完整错误(含源码定位)
|
||||
# 只在这里输出一次,随后立即终止(fail-fast)。
|
||||
src, err = batch_errors[0]
|
||||
rel = os.path.relpath(src, self.src_root) if src else rel_first
|
||||
_vlog().error(f"\n文件翻译失败: {rel}\n{err}")
|
||||
for fut in futures:
|
||||
if not fut.done():
|
||||
fut.cancel()
|
||||
if self._executor_pool is not None:
|
||||
self._executor_pool.shutdown(wait=False, cancel_futures=True)
|
||||
self._executor_pool = None
|
||||
raise ReportedCompileError(
|
||||
f"{rel} 翻译失败,编译立即停止") from None
|
||||
for src, elapsed, rel in per_file_times:
|
||||
done_files += 1
|
||||
_vlog().info(f" [{done_files}/{total_files}] {rel} ({elapsed:.1f}s)")
|
||||
_vlog().info(f" [批次完成] {bcount} 文件, 首个 {rel_first}")
|
||||
except Exception:
|
||||
# 异常时立即清理,正常流程不 shutdown(留给 includes 阶段复用)
|
||||
if self._executor_pool is not None:
|
||||
@@ -1797,11 +1811,6 @@ class Phase2Translator:
|
||||
self._executor_pool = None
|
||||
raise
|
||||
|
||||
if errors:
|
||||
_vlog().error(f"\n{len(errors)} 个文件翻译失败,立即终止编译")
|
||||
for rel, err in errors:
|
||||
_vlog().error(f" {rel}: {err}")
|
||||
raise RuntimeError(f"{len(errors)} 个文件翻译失败,已终止编译")
|
||||
else:
|
||||
for idx, (i, src_path, out_path, sha1, msm) in enumerate(need_translate):
|
||||
rel = os.path.relpath(src_path, self.src_root)
|
||||
@@ -1811,9 +1820,10 @@ class Phase2Translator:
|
||||
t1 = time.time()
|
||||
_vlog().info(f" [{idx+1}/{len(need_translate)}] {rel} ({t1-t0:.1f}s)")
|
||||
except Exception as e:
|
||||
_vlog().error(f" {rel}: {e}")
|
||||
traceback.print_exc()
|
||||
raise RuntimeError(f"翻译 {rel} 失败,已终止编译: {e}") from e
|
||||
# 单点输出:完整错误(含源码定位)只打印这一次
|
||||
_vlog().error(f"\n文件翻译失败: {rel}\n{type(e).__name__}: {e}")
|
||||
raise ReportedCompileError(
|
||||
f"翻译 {rel} 失败,已终止编译") from None
|
||||
t_end = time.time()
|
||||
_vlog().info(f" 翻译总耗时: {t_end-t_start:.1f}s")
|
||||
|
||||
@@ -3841,13 +3851,8 @@ class Phase2Translator:
|
||||
done_count += 1
|
||||
try:
|
||||
status, _, err = future.result()
|
||||
if status == 'ok':
|
||||
_vlog().info(f" [{done_count}/{len(need_translate)}] 翻译完成: {module_name}.py")
|
||||
else:
|
||||
# fail-fast:文件编译出错立即终止(worker 已 os._exit,
|
||||
# 此处兜底处理残留的 error 返回)
|
||||
raise RuntimeError(
|
||||
f"include 翻译失败,立即终止: {module_name}.py: {err}")
|
||||
except ReportedCompileError:
|
||||
raise
|
||||
except Exception as e:
|
||||
_vlog().error(f" {module_name}.py: {e}")
|
||||
for f2 in in_progress:
|
||||
@@ -3855,8 +3860,21 @@ class Phase2Translator:
|
||||
if self._executor_pool is not None:
|
||||
self._executor_pool.shutdown(wait=False, cancel_futures=True)
|
||||
self._executor_pool = None
|
||||
raise RuntimeError(
|
||||
f"include worker 异常终止,编译立即停止: {e}")
|
||||
raise ReportedCompileError(
|
||||
"include worker 异常终止,编译立即停止") from None
|
||||
if status == 'ok':
|
||||
_vlog().info(f" [{done_count}/{len(need_translate)}] 翻译完成: {module_name}.py")
|
||||
else:
|
||||
# worker 只回传错误、不写 stderr:完整错误(含源码定位)
|
||||
# 只在这里输出一次,随后立即终止(fail-fast)。
|
||||
_vlog().error(f"\n文件翻译失败: {module_name}.py\n{err}")
|
||||
for f2 in in_progress:
|
||||
f2.cancel()
|
||||
if self._executor_pool is not None:
|
||||
self._executor_pool.shutdown(wait=False, cancel_futures=True)
|
||||
self._executor_pool = None
|
||||
raise ReportedCompileError(
|
||||
"include 翻译失败,编译立即停止") from None
|
||||
except Exception:
|
||||
if self._executor_pool is not None:
|
||||
self._executor_pool.shutdown(wait=False, cancel_futures=True)
|
||||
@@ -3871,12 +3889,24 @@ class Phase2Translator:
|
||||
for item in need_translate:
|
||||
src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item
|
||||
_vlog().info(f" 翻译: {module_name}.py -> {sha1}.ll")
|
||||
self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map, dwarf_enabled=self.traceback_enabled)
|
||||
try:
|
||||
self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map, dwarf_enabled=self.traceback_enabled)
|
||||
except Exception as e:
|
||||
# 单点输出:完整错误(含源码定位)只打印这一次
|
||||
_vlog().error(f"\n文件翻译失败: {module_name}.py\n{type(e).__name__}: {e}")
|
||||
raise ReportedCompileError(
|
||||
"include 翻译失败,编译立即停止") from None
|
||||
else:
|
||||
item = need_translate[0]
|
||||
src_path, sha1, module_name, ll_path, obj_path, precompiled_obj = item
|
||||
_vlog().info(f" 翻译: {module_name}.py -> {sha1}.ll")
|
||||
self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map, dwarf_enabled=self.traceback_enabled)
|
||||
try:
|
||||
self._translate_file(src_path, ll_path, prebuilt_ModuleSha1Map=include_ModuleSha1Map, dwarf_enabled=self.traceback_enabled)
|
||||
except Exception as e:
|
||||
# 单点输出:完整错误(含源码定位)只打印这一次
|
||||
_vlog().error(f"\n文件翻译失败: {module_name}.py\n{type(e).__name__}: {e}")
|
||||
raise ReportedCompileError(
|
||||
"include 翻译失败,编译立即停止") from None
|
||||
|
||||
# ========== 阶段2:串行后处理(dso_local + stub_decls 注入)==========
|
||||
compile_tasks = [] # [(dso_ll_path, obj_path, src_path, sha1, module_name, ll_path, precompiled_obj, ll_content)]
|
||||
|
||||
Reference in new issue
Block a user