From 1050e5a23a80d64a7717bfb072c2151f6fa685d6 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sat, 10 Oct 2026 20:29:59 +0800 Subject: [PATCH] =?UTF-8?q?fix(decl):=20stub=20=E8=B7=B3=E8=BF=87=E8=81=94?= =?UTF-8?q?=E5=90=88=E5=BD=A2=E6=80=81=20CDefine=20+=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E8=AE=BF=E9=97=AE=E5=9B=9E=E9=80=80=20=5Fall?= =?UTF-8?q?=5Fdefine=5Fconstants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 链接报 undefined symbol: STD_INPUT/OUTPUT/ERROR_HANDLE。根因两处:① DeclarationGenerator._generate_global_decl 的 CDefine 跳过判据只认裸 t.CDefine,而 define X: T = V 展开为注解 T | t.CDefine,于是 stub 里写出 @STD_OUTPUT_HANDLE = external global i32(该符号无人定义);② 模块属性访问 win32file.STD_OUTPUT_HANDLE 的 _try_resolve_nested_cdefine 只查 SymbolTable/_define_constants,缺裸名路径已有的 _all_define_constants 回退,解析落空后转去加载那条错误的 stub 全局 → 链接期未定义符号。改为 AnnotationContainsName 判据 + 补 _all_define_constants 回退(仅在本模块无同名全局时,避免遮蔽真实模块全局)。 --- lib/Projectrans/DeclarationGenerator.py | 8 +++++++- lib/core/Handles/HandlesExprAttr.py | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/Projectrans/DeclarationGenerator.py b/lib/Projectrans/DeclarationGenerator.py index 189dd80..590c947 100644 --- a/lib/Projectrans/DeclarationGenerator.py +++ b/lib/Projectrans/DeclarationGenerator.py @@ -253,7 +253,13 @@ class DeclarationGenerator: if not isinstance(node.target, ast.Name): return None var_name: str = node.target.id - if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine': + # CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global。 + # `define X: T = V` 会展开为注解 `T | t.CDefine`,故判据必须能识别**联合形态**—— + # 原判据只认裸 `t.CDefine`(注解为单个 Attribute),联合注解会漏判 → + # stub 出现 `@X = external global i32` → 其他模块引用它时变成未定义符号(链接失败), + # 且会遮住跨模块 CDefine 常量回退(同名全局优先于常量)。与 _check_annotation_for_export + # 一样用递归判据。 + if AnnotationContainsName(node.annotation, 'CDefine'): return None if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef': return None diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index 0b77647..3407c93 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -2215,6 +2215,24 @@ class ExprAttrHandle(BaseHandle): return ir.Constant(ir.IntType(32), val) elif isinstance(val, float): return ir.Constant(ir.FloatType(), val) + # 回退:_all_define_constants(Phase2Translator 从所有 .pyi 预提取的跨模块 CDefine, + # 与 _HandleNameLlvm 的裸名回退同源)。此前只覆盖裸名/from-import,**模块属性访问** + # (如 `win32file.STD_OUTPUT_HANDLE`)走到这里就落空 → 转去基座求值 + 字段/全局加载, + # 命中 stub 里那条错误的 `@STD_OUTPUT_HANDLE = external global`,最终链接期未定义符号。 + # 与裸名路径同口径:仅当本模块没有同名全局时才用常量(避免遮蔽真正的模块全局)。 + _mod_globals: Any = getattr(Gen, 'module', None) + _has_mod_global: bool = _mod_globals is not None and attr_name in getattr(_mod_globals, 'globals', {}) + if not _has_mod_global: + all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {} + for key2 in (attr_name, full_path): + if key2 in all_dc: + val2: Any = all_dc[key2] + if isinstance(val2, int): + if val2 > 0x7FFFFFFF or val2 < -0x80000000: + return ir.Constant(ir.IntType(64), val2 & 0xFFFFFFFFFFFFFFFF) + return ir.Constant(ir.IntType(32), val2) + elif isinstance(val2, float): + return ir.Constant(ir.FloatType(), val2) return None def _try_resolve_cross_module_enum(self, module_alias: str, enum_class_name: str, member_name: str) -> ir.Value | None: