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: