#!/usr/bin/env python3 """ C/H 文件到 Python 存根文件生成器 将 C 头文件 (.h) 或 C 源文件 (.c) 转换为 Python 存根文件 (.vpi) 生成的 Python 代码使用 TransPyC 语法,包含类型注解 """ from __future__ import annotations import os import re import sys from typing import Any from lib.core.VLogger import get_logger as _vlog # PROF 热点:C 头文件解析阶段对每一行 / 每个成员反复调用未预编译的 re.match / # re.finditer(模块级入口),每次都要「模式串哈希 → re 缓存查找 → 未命中就重新编译」。 # 这些模式全是字面量 → 提升为模块级预编译常量(模式串与调用点字面量逐字一致)。 # _ParseDefines 用:#define 指令(含可选值),模式带 re.MULTILINE _RE_DEFINE: re.Pattern[str] = re.compile(r'#define\s+(\w+)(?:\s+(.+?))?\s*$', re.MULTILINE) # _ParseTypedefStructs / _ParseTypedefEnums / _ParseTypedefUnions 用:typedef 结尾的 `别名;` _RE_ALIAS: re.Pattern[str] = re.compile(r'(\w+)\s*;') # _ParseFunctions 用:返回类型是否以数字开头 _RE_DIGIT_START: re.Pattern[str] = re.compile(r'^\d') # _ParseFunctions / _ParseVariables 用:标识符是否以字母或下划线开头 _RE_IDENT_START: re.Pattern[str] = re.compile(r'^[A-Za-z_]') # _ParseVariables 用:排除 C 关键字作为变量名 _RE_C_KEYWORD: re.Pattern[str] = re.compile(r'^(if|else|while|for|return|switch|case|break|continue|do|goto)$') # _ParseStructMembers 用:结构体数组成员 _RE_STRUCT_ARRAY_MEMBER: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s+(\w+)\s*\[(\d*)\]') # _ParseStructMembers 用:结构体指针成员 _RE_STRUCT_PTR_MEMBER: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s*\*\s*(\w+)') # _ParseStructMembers 用:结构体普通成员 _RE_STRUCT_SIMPLE_MEMBER: re.Pattern[str] = re.compile(r'([\w\s]+?)\s+(\w+)') # _ParseEnumValues 用:枚举项名是否合法 _RE_ENUM_NAME: re.Pattern[str] = re.compile(r'^[A-Za-z_]\w*$') # _ParseFuncParams 用:函数指针参数 _RE_FUNC_PTR_PARAM: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s*\(\s*\*\s*(\w*)\s*\)\s*\([^)]*\)') # _ParseFuncParams 用:数组参数 _RE_ARRAY_PARAM: re.Pattern[str] = re.compile(r'([\w\s\*]+?)\s+(\w+)\s*\[\d*\]') class CTypeMapper: # C 类型名 → 新语法内建类型名 # (int/uint/int8..uint64/sizet/short/long/uchar/float8..float128/char8..char32/rawptr) _CNAME_TO_PY: dict[str, str] = { # 基本类型 'char': 'char', 'int': 'int', 'short': 'short', 'long': 'long', 'long long': 'longlong', 'float': 'float', 'double': 'double', 'void': 'void', # unsigned / signed 变体 'unsigned': 'uint', 'unsigned char': 'uchar', 'unsigned int': 'uint', 'unsigned short': 'ushort', 'unsigned long': 'ulong', 'unsigned long long': 'ulonglong', 'signed char': 'char', # bool / size_t 'bool': 'bool', '_Bool': 'bool', 'size_t': 'sizet', 'ssize_t': 'ptrdifft', # stdint 固定宽度类型 'int8_t': 'int8', 'int16_t': 'int16', 'int32_t': 'int32', 'int64_t': 'int64', 'uint8_t': 'uint8', 'uint16_t': 'uint16', 'uint32_t': 'uint32', 'uint64_t': 'uint64', 'intptr_t': 'intptr', 'uintptr_t': 'uintptr', 'ptrdiff_t': 'ptrdifft', # 宽字符 / 字符类型 'wchar_t': 'wchar', 'char8_t': 'char8', 'char16_t': 'char16', 'char32_t': 'char32', # 浮点特化类型 'float8_t': 'float8', 'float16_t': 'float16', 'float32_t': 'float32', 'float64_t': 'float64', 'float128_t': 'float128', # signed 速记 'signed': 'int', 'signed int': 'int', 'signed short': 'short', 'signed long': 'long', } @classmethod def _ResolveCNameToPyType(cls, c_type: str) -> str: """将 C 类型名解析为新语法内建类型名(如 'int' → 'int') 使用硬编码映射表,不再依赖 CTypeRegistry._cname_to_class。 未识别的类型原样返回(用于 struct/union/enum/typedef 用户自定义名)。 """ py: str | None = cls._CNAME_TO_PY.get(c_type) if py is not None: return py return c_type @classmethod def MapType(cls, c_type: str, IsPtr: bool = False, IsArray: bool = False) -> str: """C 类型 → 新语法类型(指针写成 `T*`,不再产出 `T | CPtr`)。""" c_type = c_type.strip() IsConst: bool = 'const ' in c_type c_type = c_type.replace('const ', '').replace('const', '').strip() IsVolatile: bool = 'volatile ' in c_type c_type = c_type.replace('volatile ', '').replace('volatile', '').strip() # static / extern / register / inline 是声明级修饰,不是类型的一部分。 c_type = c_type.replace('static ', '').replace('static', '').strip() c_type = c_type.replace('extern ', '').replace('extern', '').strip() c_type = c_type.replace('register ', '').replace('register', '').strip() c_type = c_type.replace('inline ', '').replace('inline', '').strip() # 指针层数:类型文本里的 '*' 已表达层数;IsPtr 只在文本无 '*' 时补一层, # 避免 `IsPtr=True` + 文本 '*' 被重复计数(Node**)。 StarCount: int = len(c_type) - len(c_type.rstrip('*')) PtrCount: int = StarCount if StarCount > 0 else (1 if IsPtr else 0) c_type = c_type.rstrip('*').strip() if c_type.startswith('struct '): c_type = c_type[7:].strip() elif c_type.startswith('union '): c_type = c_type[6:].strip() elif c_type.startswith('enum '): c_type = c_type[5:].strip() PyType: str = cls._ResolveCNameToPyType(c_type) Prefix: str = '' if IsConst: Prefix += 'const ' if IsVolatile: Prefix += 'volatile ' return Prefix + PyType + ('*' * PtrCount) def _find_matching_brace(text: str, start: int) -> int: depth: int = 0 i: int = start while i < len(text): if text[i] == '{': depth += 1 elif text[i] == '}': depth -= 1 if depth == 0: return i elif text[i] == '"' or text[i] == "'": quote: str = text[i] i += 1 while i < len(text) and text[i] != quote: if text[i] == '\\': i += 1 i += 1 elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '/': while i < len(text) and text[i] != '\n': i += 1 continue elif text[i] == '/' and i + 1 < len(text) and text[i + 1] == '*': i += 2 while i + 1 < len(text) and not (text[i] == '*' and text[i + 1] == '/'): i += 1 i += 1 i += 1 return -1 def _strip_comments(content: str) -> str: result: list[str] = [] i: int = 0 while i < len(content): if content[i] == '/' and i + 1 < len(content) and content[i + 1] == '/': while i < len(content) and content[i] != '\n': i += 1 elif content[i] == '/' and i + 1 < len(content) and content[i + 1] == '*': i += 2 while i + 1 < len(content) and not (content[i] == '*' and content[i + 1] == '/'): i += 1 i += 2 elif content[i] == '"' or content[i] == "'": quote: str = content[i] result.append(content[i]) i += 1 while i < len(content) and content[i] != quote: if content[i] == '\\' and i + 1 < len(content): result.append(content[i]) i += 1 result.append(content[i]) i += 1 if i < len(content): result.append(content[i]) i += 1 else: result.append(content[i]) i += 1 return ''.join(result) def _strip_preprocessor_guards(content: str) -> str: lines: list[str] = content.split('\n') filtered: list[str] = [] for line in lines: stripped: str = line.strip() if stripped.startswith('#ifndef') and '_H' in stripped.upper(): continue if stripped.startswith('#define') and '_H' in stripped.upper(): continue if stripped == '#endif': continue filtered.append(line) return '\n'.join(filtered) class CHeaderParser: """C 头文件解析器""" def __init__(self) -> None: self.defines: list[dict[str, str | None]] = [] self.structs: dict[str, dict[str, Any]] = {} self.enums: dict[str, dict[str, Any]] = {} self.typedefs: list[dict[str, str]] = [] self.functions: dict[str, dict[str, Any]] = {} self.variables: dict[str, dict[str, Any]] = {} self.unions: dict[str, dict[str, Any]] = {} self.func_ptr_typedefs: dict[str, dict[str, Any]] = {} self._typedef_struct_map: dict[str, str] = {} self._typedef_enum_map: dict[str, str] = {} self._typedef_union_map: dict[str, str] = {} def ParseFile(self, FilePath: str) -> None: with open(FilePath, 'r', encoding='utf-8') as f: content: str = f.read() self.ParseContent(content) def ParseContent(self, content: str) -> None: content = _strip_comments(content) content = _strip_preprocessor_guards(content) self._ParseDefines(content) self._ParseTypedefStructs(content) self._ParseTypedefEnums(content) self._ParseTypedefUnions(content) self._ParseFuncPtrTypedefs(content) self._ParseSimpleTypedefs(content) self._ParseStandaloneStructs(content) self._ParseStandaloneEnums(content) self._ParseStandaloneUnions(content) stripped: str = self._StripBodies(content) self._ParseFunctions(stripped) self._ParseVariables(stripped) def _StripBodies(self, content: str) -> str: result: str = content while True: pos: int = result.find('{') if pos < 0: break end: int = _find_matching_brace(result, pos) if end < 0: break result = result[:pos] + result[end + 1:] return result def _ParseDefines(self, content: str) -> None: for match in _RE_DEFINE.finditer(content): Name: str = match.group(1) Value: str | None = match.group(2) if Name.startswith('_') and Name.endswith('_'): continue if Name.startswith('__'): continue self.defines.append({ 'name': Name, 'value': Value.strip() if Value else None, }) def _ParseTypedefStructs(self, content: str) -> None: pattern: str = r'typedef\s+struct\s*(\w*)\s*\{' for match in re.finditer(pattern, content): brace_start: int = content.index('{', match.start()) brace_end: int = _find_matching_brace(content, brace_start) if brace_end < 0: continue body: str = content[brace_start + 1:brace_end] rest: str = content[brace_end + 1:].lstrip() AliasMatch: re.Match[str] | None = _RE_ALIAS.match(rest) if not AliasMatch: continue AliasName: str = AliasMatch.group(1) TagName: str | None = match.group(1) if match.group(1) else None members: list[dict[str, Any]] = self._ParseStructMembers(body) self.structs[AliasName] = { 'name': AliasName, 'tag': TagName, 'members': members, } if TagName: self._typedef_struct_map[TagName] = AliasName def _ParseTypedefEnums(self, content: str) -> None: pattern: str = r'typedef\s+enum\s*(\w*)\s*\{' for match in re.finditer(pattern, content): brace_start: int = content.index('{', match.start()) brace_end: int = _find_matching_brace(content, brace_start) if brace_end < 0: continue body: str = content[brace_start + 1:brace_end] rest: str = content[brace_end + 1:].lstrip() AliasMatch: re.Match[str] | None = _RE_ALIAS.match(rest) if not AliasMatch: continue AliasName: str = AliasMatch.group(1) TagName: str | None = match.group(1) if match.group(1) else None values: list[dict[str, str | None]] = self._ParseEnumValues(body) self.enums[AliasName] = { 'name': AliasName, 'tag': TagName, 'values': values, } if TagName: self._typedef_enum_map[TagName] = AliasName def _ParseTypedefUnions(self, content: str) -> None: pattern: str = r'typedef\s+union\s*(\w*)\s*\{' for match in re.finditer(pattern, content): brace_start: int = content.index('{', match.start()) brace_end: int = _find_matching_brace(content, brace_start) if brace_end < 0: continue body: str = content[brace_start + 1:brace_end] rest: str = content[brace_end + 1:].lstrip() AliasMatch: re.Match[str] | None = _RE_ALIAS.match(rest) if not AliasMatch: continue AliasName: str = AliasMatch.group(1) TagName: str | None = match.group(1) if match.group(1) else None members: list[dict[str, Any]] = self._ParseStructMembers(body) self.unions[AliasName] = { 'name': AliasName, 'tag': TagName, 'members': members, } if TagName: self._typedef_union_map[TagName] = AliasName def _ParseFuncPtrTypedefs(self, content: str) -> None: pattern: str = r'typedef\s+([\w\s\*]+?)\s*\(\s*\*\s*(\w+)\s*\)\s*\(([^)]*)\)\s*;' for match in re.finditer(pattern, content): ReturnType: str = match.group(1).strip() Name: str = match.group(2) ParamsStr: str = match.group(3).strip() params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr) self.func_ptr_typedefs[Name] = { 'name': Name, 'return_type': ReturnType, 'params': params, } def _ParseSimpleTypedefs(self, content: str) -> None: stripped: str = self._StripBodies(content) pattern: str = r'typedef[ \t]+([\w \t\*]+?)[ \t]+(\w+)[ \t]*;' for match in re.finditer(pattern, stripped): BaseType: str = match.group(1).strip() AliasName: str = match.group(2) if AliasName in self.structs: continue if AliasName in self.enums: continue if AliasName in self.unions: continue if AliasName in self.func_ptr_typedefs: continue if BaseType.startswith('typedef'): continue self.typedefs.append({'name': AliasName, 'base': BaseType}) def _ParseStandaloneStructs(self, content: str) -> None: pattern: str = r'(? None: pattern: str = r'(? None: pattern: str = r'(? None: pattern: str = r'(?:(?:static|extern|inline)[ \t]+)*([\w][\w \t\*]*?)\b(\w+)[ \t]*\(([^)]*)\)[ \t]*;' for match in re.finditer(pattern, content): ReturnType: str = match.group(1).strip() FuncName: str = match.group(2) ParamsStr: str = match.group(3).strip() if FuncName in self.structs or FuncName in self.enums or FuncName in self.unions: continue if FuncName in self.func_ptr_typedefs: continue if FuncName in self.defines: continue if ReturnType in ('struct', 'union', 'enum', 'typedef'): continue if _RE_DIGIT_START.match(ReturnType): continue if not _RE_IDENT_START.match(FuncName): continue params: list[dict[str, Any]] = self._ParseFuncParams(ParamsStr) self.functions[FuncName] = { 'name': FuncName, 'return_type': ReturnType, 'params': params, } def _ParseVariables(self, content: str) -> None: pattern: str = r'(?:(?:static|extern|volatile|const)[ \t]+)*([\w][\w \t\*]*?)[ \t]+(\w+)[ \t]*(?:\[(\d*)\])?[ \t]*;' for match in re.finditer(pattern, content): TypeStr: str = match.group(1).strip() VarName: str = match.group(2) ArraySize: str | None = match.group(3) if VarName in self.functions or VarName in self.structs or VarName in self.enums: continue if VarName in self.unions or VarName in self.func_ptr_typedefs: continue if VarName in self.defines: continue if TypeStr.startswith('typedef'): continue if TypeStr in ('struct', 'union', 'enum', 'typedef'): continue if _RE_C_KEYWORD.match(VarName): continue if not _RE_IDENT_START.match(VarName): continue IsPtr: bool = '*' in TypeStr IsArray: bool = ArraySize is not None self.variables[VarName] = { 'name': VarName, 'type': TypeStr, 'IsPtr': IsPtr, 'is_array': IsArray, 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, } def _ParseStructMembers(self, body: str) -> list[dict[str, Any]]: members: list[dict[str, Any]] = [] for line in body.split(';'): line = line.strip() if not line: continue arr_match: re.Match[str] | None = _RE_STRUCT_ARRAY_MEMBER.match(line) if arr_match: MemberType: str = arr_match.group(1).strip() MemberName: str = arr_match.group(2) ArraySize: str = arr_match.group(3) members.append({ 'name': MemberName, 'type': MemberType, 'is_array': True, 'array_size': int(ArraySize) if ArraySize and ArraySize.isdigit() else None, }) continue ptr_match: re.Match[str] | None = _RE_STRUCT_PTR_MEMBER.match(line) if ptr_match: MemberType: str = ptr_match.group(1).strip() + ' *' MemberName: str = ptr_match.group(2) members.append({ 'name': MemberName, 'type': MemberType, 'IsPtr': True, }) continue simple_match: re.Match[str] | None = _RE_STRUCT_SIMPLE_MEMBER.match(line) if simple_match: MemberType: str = simple_match.group(1).strip() MemberName: str = simple_match.group(2) members.append({ 'name': MemberName, 'type': MemberType, }) return members def _ParseEnumValues(self, body: str) -> list[dict[str, str | None]]: values: list[dict[str, str | None]] = [] for item in body.split(','): item = item.strip() if not item: continue eq_pos: int = item.find('=') if eq_pos >= 0: Name: str = item[:eq_pos].strip() Value: str | None = item[eq_pos + 1:].strip() else: Name = item.strip() Value = None if Name and _RE_ENUM_NAME.match(Name): values.append({'name': Name, 'value': Value}) return values def _ParseFuncParams(self, params_str: str) -> list[dict[str, Any]]: params: list[dict[str, Any]] = [] if not params_str or params_str.strip() == 'void' or params_str.strip() == '': return params for param in params_str.split(','): param = param.strip() if not param: continue func_ptr_match: re.Match[str] | None = _RE_FUNC_PTR_PARAM.match(param) if func_ptr_match: RetType: str = func_ptr_match.group(1).strip() ParamName: str = func_ptr_match.group(2) or 'callback' params.append({ 'name': ParamName, 'type': RetType + ' (*)', 'is_func_ptr': True, }) continue arr_match: re.Match[str] | None = _RE_ARRAY_PARAM.match(param) if arr_match: ParamType: str = arr_match.group(1).strip() ParamName: str = arr_match.group(2) params.append({ 'name': ParamName, 'type': ParamType, 'is_array': True, }) continue tokens: list[str] = param.split() if len(tokens) >= 2: LastToken: str = tokens[-1] PtrCount: int = 0 while LastToken.startswith('*'): PtrCount += 1 LastToken = LastToken[1:] TypeTokens: list[str] = tokens[:-1] for _ in range(PtrCount): TypeTokens.append('*') ParamName: str = LastToken ParamType: str = ' '.join(TypeTokens) if not ParamName: ParamName = 'arg' ParamType = param params.append({ 'name': ParamName, 'type': ParamType, }) elif len(tokens) == 1: params.append({ 'name': 'arg', 'type': tokens[0], }) return params class PythonStubGenerator: """Python 存根文件生成器""" def __init__(self, parser: CHeaderParser) -> None: self.parser: CHeaderParser = parser self.OutputLines: list[str] = [] def generate(self, ModuleName: str | None = None) -> str: self.OutputLines = [] self._AddHeader(ModuleName) # stub 头部只放模块文档;内建标记按裸名使用,无需 import。 self._GenerateDefines() self._GenerateFuncPtrTypedefs() self._GenerateSimpleTypedefs() self._GenerateStructs() self._GenerateUnions() self._GenerateEnums() self._GenerateVariables() self._GenerateFunctions() return '\n'.join(self.OutputLines) def _AddHeader(self, ModuleName: str | None = None) -> None: self.OutputLines.append('"""') self.OutputLines.append('Auto-generated Python stub file from C header') if ModuleName: self.OutputLines.append(f'Module: {ModuleName}') self.OutputLines.append('"""') self.OutputLines.append('') def _GenerateDefines(self) -> None: if not self.parser.defines: return for define in self.parser.defines: Name: str = define['name'] Value: str | None = define['value'] if Value is not None: self.OutputLines.append(f'define {Name} = {Value}') else: # 新语法要求 define 带初值;无值宏(#define FOO)以 0 占位 self.OutputLines.append(f'define {Name} = 0') self.OutputLines.append('') def _GenerateFuncPtrTypedefs(self) -> None: if not self.parser.func_ptr_typedefs: return for Name, Info in self.parser.func_ptr_typedefs.items(): RetType: str = CTypeMapper.MapType(Info['return_type']) ParamTypes: list[str] = [] for p in Info['params']: ParamTypes.append(CTypeMapper.MapType(p['type'])) ParamStr: str = ', '.join(ParamTypes) if ParamTypes else '' self.OutputLines.append(f'typedef {Name} = callable[[{ParamStr}], {RetType}]') self.OutputLines.append('') def _GenerateSimpleTypedefs(self) -> None: if not self.parser.typedefs: return for td in self.parser.typedefs: AliasName: str = td['name'] BaseType: str = td['base'] PyType: str = CTypeMapper.MapType(BaseType) self.OutputLines.append(f'typedef {AliasName} = {PyType}') self.OutputLines.append('') def _GenerateStructs(self) -> None: if not self.parser.structs: return for StructName, StructInfo in self.parser.structs.items(): self.OutputLines.append(f'@Attribute(attr.packed)') self.OutputLines.append(f'class {StructName}(CStruct):') if StructInfo['members']: for member in StructInfo['members']: MemberName: str = member['name'] IsPtr: bool = member.get('IsPtr', False) IsArray: bool = member.get('is_array', False) ArraySize: int | None = member.get('array_size') PyType: str = CTypeMapper.MapType(member['type'], IsPtr=IsPtr) if IsArray and ArraySize is not None: self.OutputLines.append(f' {MemberName}: CArray[{PyType}, {ArraySize}]') elif IsArray: self.OutputLines.append(f' {MemberName}: CArray[{PyType}, None]') else: self.OutputLines.append(f' {MemberName}: {PyType}') else: self.OutputLines.append(' pass') self.OutputLines.append('') def _GenerateUnions(self) -> None: if not self.parser.unions: return for UnionName, UnionInfo in self.parser.unions.items(): self.OutputLines.append(f'@Attribute(attr.packed)') self.OutputLines.append(f'class {UnionName}(CUnion):') if UnionInfo['members']: for member in UnionInfo['members']: PyType: str = CTypeMapper.MapType(member['type'], IsPtr=member.get('IsPtr', False)) self.OutputLines.append(f' {member["name"]}: {PyType}') else: self.OutputLines.append(' pass') self.OutputLines.append('') def _GenerateEnums(self) -> None: if not self.parser.enums: return for EnumName, EnumInfo in self.parser.enums.items(): self.OutputLines.append(f'class __{EnumName.lower()}(CEnum):') if EnumInfo['values']: for value in EnumInfo['values']: if value['value'] is not None: self.OutputLines.append(f' {value["name"]}: int = {value["value"]}') else: self.OutputLines.append(f' {value["name"]}: int') else: self.OutputLines.append(' pass') self.OutputLines.append(f'typedef {EnumName} = __{EnumName.lower()}') self.OutputLines.append('') def _GenerateVariables(self) -> None: if not self.parser.variables: return for VarName, VarInfo in self.parser.variables.items(): PyType: str = CTypeMapper.MapType(VarInfo['type'], IsPtr=VarInfo['IsPtr']) if VarInfo['is_array']: ArraySize: int | None = VarInfo.get('array_size') SizeStr: str = str(ArraySize) if ArraySize is not None else 'None' PyType = f'CArray[{PyType}, {SizeStr}]' self.OutputLines.append(f'{VarName}: {PyType}') self.OutputLines.append('') def _GenerateFunctions(self) -> None: if not self.parser.functions: return for FuncName, FuncInfo in self.parser.functions.items(): params: list[str] = [] for param in FuncInfo['params']: if param.get('is_func_ptr'): PyType: str = CTypeMapper.MapType(param['type']) elif param.get('is_array'): PyType: str = CTypeMapper.MapType(param['type'], IsPtr=True) else: PyType: str = CTypeMapper.MapType(param['type']) params.append(f'{param["name"]}: {PyType}') ParamStr: str = ', '.join(params) if params else '' ReturnType: str = CTypeMapper.MapType(FuncInfo['return_type']) self.OutputLines.append(f'def {FuncName}({ParamStr}) -> {ReturnType}: pass') self.OutputLines.append('') def GenerateStubFromC(InputFile: str, OutputFile: str | None = None) -> str: parser: CHeaderParser = CHeaderParser() parser.ParseFile(InputFile) generator: PythonStubGenerator = PythonStubGenerator(parser) ModuleName: str = os.path.splitext(os.path.basename(InputFile))[0] content: str = generator.generate(ModuleName) if OutputFile: with open(OutputFile, 'w', encoding='utf-8') as f: f.write(content) _vlog().success(f"生成: {OutputFile}") return content if __name__ == '__main__': if len(sys.argv) >= 3: GenerateStubFromC(sys.argv[1], sys.argv[2]) elif len(sys.argv) == 2: _vlog().info(GenerateStubFromC(sys.argv[1])) else: test_code: str = ''' struct memory_block { uint64_t size; uint8_t state; uint8_t order; struct memory_block *next; struct memory_block *prev; }; typedef struct memory_block memory_block_t; enum color_format { COLOR_FORMAT_BGRA, COLOR_FORMAT_RGBA, COLOR_FORMAT_BGR, COLOR_FORMAT_RGB }; void *malloc(size_t size); void free(void *ptr); void *memcpy(void *dest, const void *src, size_t n); ''' parser: CHeaderParser = CHeaderParser() parser.ParseContent(test_code) generator: PythonStubGenerator = PythonStubGenerator(parser) _vlog().info(generator.generate("test_header"))