fbt: fixes for ufbt compat (#1940)
* fbt: split sdk management code * scripts: fixed import handling * fbt: sdk: reformatted paths * scrips: dist: bundling libs as a build artifact * fbt: sdk: better path management * typo fix * fbt: sdk: minor path handling fixes * toolchain: fixed windows toolchain download Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									9cd0592aaf
								
							
						
					
					
						commit
						4b921803cb
					
				| @ -178,23 +178,6 @@ sources.extend( | ||||
|     ) | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| fwenv.AppendUnique( | ||||
|     LINKFLAGS=[ | ||||
|         "-specs=nano.specs", | ||||
|         "-specs=nosys.specs", | ||||
|         "-Wl,--gc-sections", | ||||
|         "-Wl,--undefined=uxTopUsedPriority", | ||||
|         "-Wl,--wrap,_malloc_r", | ||||
|         "-Wl,--wrap,_free_r", | ||||
|         "-Wl,--wrap,_calloc_r", | ||||
|         "-Wl,--wrap,_realloc_r", | ||||
|         "-n", | ||||
|         "-Xlinker", | ||||
|         "-Map=${TARGET}.map", | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| # Debug | ||||
| # print(fwenv.Dump()) | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										44
									
								
								scripts/fbt/sdk/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								scripts/fbt/sdk/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | ||||
| from typing import Set, ClassVar | ||||
| from dataclasses import dataclass, field | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class ApiEntryFunction: | ||||
|     name: str | ||||
|     returns: str | ||||
|     params: str | ||||
| 
 | ||||
|     csv_type: ClassVar[str] = "Function" | ||||
| 
 | ||||
|     def dictify(self): | ||||
|         return dict(name=self.name, type=self.returns, params=self.params) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class ApiEntryVariable: | ||||
|     name: str | ||||
|     var_type: str | ||||
| 
 | ||||
|     csv_type: ClassVar[str] = "Variable" | ||||
| 
 | ||||
|     def dictify(self): | ||||
|         return dict(name=self.name, type=self.var_type, params=None) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class ApiHeader: | ||||
|     name: str | ||||
| 
 | ||||
|     csv_type: ClassVar[str] = "Header" | ||||
| 
 | ||||
|     def dictify(self): | ||||
|         return dict(name=self.name, type=None, params=None) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass | ||||
| class ApiEntries: | ||||
|     # These are sets, to avoid creating duplicates when we have multiple | ||||
|     # declarations with same signature | ||||
|     functions: Set[ApiEntryFunction] = field(default_factory=set) | ||||
|     variables: Set[ApiEntryVariable] = field(default_factory=set) | ||||
|     headers: Set[ApiHeader] = field(default_factory=set) | ||||
| @ -4,284 +4,18 @@ import csv | ||||
| import operator | ||||
| 
 | ||||
| from enum import Enum, auto | ||||
| from typing import List, Set, ClassVar, Any | ||||
| from dataclasses import dataclass, field | ||||
| from typing import Set, ClassVar, Any | ||||
| from dataclasses import dataclass | ||||
| 
 | ||||
| from ansi.color import fg | ||||
| 
 | ||||
| from cxxheaderparser.parser import CxxParser | ||||
| 
 | ||||
| 
 | ||||
| # 'Fixing' complaints about typedefs | ||||
| CxxParser._fundamentals.discard("wchar_t") | ||||
| 
 | ||||
| from cxxheaderparser.types import ( | ||||
|     EnumDecl, | ||||
|     Field, | ||||
|     ForwardDecl, | ||||
|     FriendDecl, | ||||
|     Function, | ||||
|     Method, | ||||
|     Typedef, | ||||
|     UsingAlias, | ||||
|     UsingDecl, | ||||
|     Variable, | ||||
|     Pointer, | ||||
|     Type, | ||||
|     PQName, | ||||
|     NameSpecifier, | ||||
|     FundamentalSpecifier, | ||||
|     Parameter, | ||||
|     Array, | ||||
|     Value, | ||||
|     Token, | ||||
|     FunctionType, | ||||
| from . import ( | ||||
|     ApiEntries, | ||||
|     ApiEntryFunction, | ||||
|     ApiEntryVariable, | ||||
|     ApiHeader, | ||||
| ) | ||||
| 
 | ||||
| from cxxheaderparser.parserstate import ( | ||||
|     State, | ||||
|     EmptyBlockState, | ||||
|     ClassBlockState, | ||||
|     ExternBlockState, | ||||
|     NamespaceBlockState, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class ApiEntryFunction: | ||||
|     name: str | ||||
|     returns: str | ||||
|     params: str | ||||
| 
 | ||||
|     csv_type: ClassVar[str] = "Function" | ||||
| 
 | ||||
|     def dictify(self): | ||||
|         return dict(name=self.name, type=self.returns, params=self.params) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class ApiEntryVariable: | ||||
|     name: str | ||||
|     var_type: str | ||||
| 
 | ||||
|     csv_type: ClassVar[str] = "Variable" | ||||
| 
 | ||||
|     def dictify(self): | ||||
|         return dict(name=self.name, type=self.var_type, params=None) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class ApiHeader: | ||||
|     name: str | ||||
| 
 | ||||
|     csv_type: ClassVar[str] = "Header" | ||||
| 
 | ||||
|     def dictify(self): | ||||
|         return dict(name=self.name, type=None, params=None) | ||||
| 
 | ||||
| 
 | ||||
| @dataclass | ||||
| class ApiEntries: | ||||
|     # These are sets, to avoid creating duplicates when we have multiple | ||||
|     # declarations with same signature | ||||
|     functions: Set[ApiEntryFunction] = field(default_factory=set) | ||||
|     variables: Set[ApiEntryVariable] = field(default_factory=set) | ||||
|     headers: Set[ApiHeader] = field(default_factory=set) | ||||
| 
 | ||||
| 
 | ||||
| class SymbolManager: | ||||
|     def __init__(self): | ||||
|         self.api = ApiEntries() | ||||
|         self.name_hashes = set() | ||||
| 
 | ||||
|     # Calculate hash of name and raise exception if it already is in the set | ||||
|     def _name_check(self, name: str): | ||||
|         name_hash = gnu_sym_hash(name) | ||||
|         if name_hash in self.name_hashes: | ||||
|             raise Exception(f"Hash collision on {name}") | ||||
|         self.name_hashes.add(name_hash) | ||||
| 
 | ||||
|     def add_function(self, function_def: ApiEntryFunction): | ||||
|         if function_def in self.api.functions: | ||||
|             return | ||||
|         self._name_check(function_def.name) | ||||
|         self.api.functions.add(function_def) | ||||
| 
 | ||||
|     def add_variable(self, variable_def: ApiEntryVariable): | ||||
|         if variable_def in self.api.variables: | ||||
|             return | ||||
|         self._name_check(variable_def.name) | ||||
|         self.api.variables.add(variable_def) | ||||
| 
 | ||||
|     def add_header(self, header: str): | ||||
|         self.api.headers.add(ApiHeader(header)) | ||||
| 
 | ||||
| 
 | ||||
| def gnu_sym_hash(name: str): | ||||
|     h = 0x1505 | ||||
|     for c in name: | ||||
|         h = (h << 5) + h + ord(c) | ||||
|     return str(hex(h))[-8:] | ||||
| 
 | ||||
| 
 | ||||
| class SdkCollector: | ||||
|     def __init__(self): | ||||
|         self.symbol_manager = SymbolManager() | ||||
| 
 | ||||
|     def add_header_to_sdk(self, header: str): | ||||
|         self.symbol_manager.add_header(header) | ||||
| 
 | ||||
|     def process_source_file_for_sdk(self, file_path: str): | ||||
|         visitor = SdkCxxVisitor(self.symbol_manager) | ||||
|         with open(file_path, "rt") as f: | ||||
|             content = f.read() | ||||
|         parser = CxxParser(file_path, content, visitor, None) | ||||
|         parser.parse() | ||||
| 
 | ||||
|     def get_api(self): | ||||
|         return self.symbol_manager.api | ||||
| 
 | ||||
| 
 | ||||
| def stringify_array_dimension(size_descr): | ||||
|     if not size_descr: | ||||
|         return "" | ||||
|     return stringify_descr(size_descr) | ||||
| 
 | ||||
| 
 | ||||
| def stringify_array_descr(type_descr): | ||||
|     assert isinstance(type_descr, Array) | ||||
|     return ( | ||||
|         stringify_descr(type_descr.array_of), | ||||
|         stringify_array_dimension(type_descr.size), | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def stringify_descr(type_descr): | ||||
|     if isinstance(type_descr, (NameSpecifier, FundamentalSpecifier)): | ||||
|         return type_descr.name | ||||
|     elif isinstance(type_descr, PQName): | ||||
|         return "::".join(map(stringify_descr, type_descr.segments)) | ||||
|     elif isinstance(type_descr, Pointer): | ||||
|         # Hack | ||||
|         if isinstance(type_descr.ptr_to, FunctionType): | ||||
|             return stringify_descr(type_descr.ptr_to) | ||||
|         return f"{stringify_descr(type_descr.ptr_to)}*" | ||||
|     elif isinstance(type_descr, Type): | ||||
|         return ( | ||||
|             f"{'const ' if type_descr.const else ''}" | ||||
|             f"{'volatile ' if type_descr.volatile else ''}" | ||||
|             f"{stringify_descr(type_descr.typename)}" | ||||
|         ) | ||||
|     elif isinstance(type_descr, Parameter): | ||||
|         return stringify_descr(type_descr.type) | ||||
|     elif isinstance(type_descr, Array): | ||||
|         # Hack for 2d arrays | ||||
|         if isinstance(type_descr.array_of, Array): | ||||
|             argtype, dimension = stringify_array_descr(type_descr.array_of) | ||||
|             return ( | ||||
|                 f"{argtype}[{stringify_array_dimension(type_descr.size)}][{dimension}]" | ||||
|             ) | ||||
|         return f"{stringify_descr(type_descr.array_of)}[{stringify_array_dimension(type_descr.size)}]" | ||||
|     elif isinstance(type_descr, Value): | ||||
|         return " ".join(map(stringify_descr, type_descr.tokens)) | ||||
|     elif isinstance(type_descr, FunctionType): | ||||
|         return f"{stringify_descr(type_descr.return_type)} (*)({', '.join(map(stringify_descr, type_descr.parameters))})" | ||||
|     elif isinstance(type_descr, Token): | ||||
|         return type_descr.value | ||||
|     elif type_descr is None: | ||||
|         return "" | ||||
|     else: | ||||
|         raise Exception("unsupported type_descr: %s" % type_descr) | ||||
| 
 | ||||
| 
 | ||||
| class SdkCxxVisitor: | ||||
|     def __init__(self, symbol_manager: SymbolManager): | ||||
|         self.api = symbol_manager | ||||
| 
 | ||||
|     def on_variable(self, state: State, v: Variable) -> None: | ||||
|         if not v.extern: | ||||
|             return | ||||
| 
 | ||||
|         self.api.add_variable( | ||||
|             ApiEntryVariable( | ||||
|                 stringify_descr(v.name), | ||||
|                 stringify_descr(v.type), | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|     def on_function(self, state: State, fn: Function) -> None: | ||||
|         if fn.inline or fn.has_body: | ||||
|             return | ||||
| 
 | ||||
|         self.api.add_function( | ||||
|             ApiEntryFunction( | ||||
|                 stringify_descr(fn.name), | ||||
|                 stringify_descr(fn.return_type), | ||||
|                 ", ".join(map(stringify_descr, fn.parameters)) | ||||
|                 + (", ..." if fn.vararg else ""), | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|     def on_define(self, state: State, content: str) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_pragma(self, state: State, content: str) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_include(self, state: State, filename: str) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_empty_block_start(self, state: EmptyBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_empty_block_end(self, state: EmptyBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_extern_block_start(self, state: ExternBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_extern_block_end(self, state: ExternBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_namespace_start(self, state: NamespaceBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_namespace_end(self, state: NamespaceBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_typedef(self, state: State, typedef: Typedef) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_using_namespace(self, state: State, namespace: List[str]) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_using_alias(self, state: State, using: UsingAlias) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_using_declaration(self, state: State, using: UsingDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_enum(self, state: State, enum: EnumDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_start(self, state: ClassBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_field(self, state: State, f: Field) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_method(self, state: ClassBlockState, method: Method) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_friend(self, state: ClassBlockState, friend: FriendDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_end(self, state: ClassBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| @dataclass(frozen=True) | ||||
| class SdkVersion: | ||||
							
								
								
									
										238
									
								
								scripts/fbt/sdk/collector.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										238
									
								
								scripts/fbt/sdk/collector.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,238 @@ | ||||
| from typing import List | ||||
| 
 | ||||
| from cxxheaderparser.parser import CxxParser | ||||
| from . import ( | ||||
|     ApiEntries, | ||||
|     ApiEntryFunction, | ||||
|     ApiEntryVariable, | ||||
|     ApiHeader, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| # 'Fixing' complaints about typedefs | ||||
| CxxParser._fundamentals.discard("wchar_t") | ||||
| 
 | ||||
| from cxxheaderparser.types import ( | ||||
|     EnumDecl, | ||||
|     Field, | ||||
|     ForwardDecl, | ||||
|     FriendDecl, | ||||
|     Function, | ||||
|     Method, | ||||
|     Typedef, | ||||
|     UsingAlias, | ||||
|     UsingDecl, | ||||
|     Variable, | ||||
|     Pointer, | ||||
|     Type, | ||||
|     PQName, | ||||
|     NameSpecifier, | ||||
|     FundamentalSpecifier, | ||||
|     Parameter, | ||||
|     Array, | ||||
|     Value, | ||||
|     Token, | ||||
|     FunctionType, | ||||
| ) | ||||
| 
 | ||||
| from cxxheaderparser.parserstate import ( | ||||
|     State, | ||||
|     EmptyBlockState, | ||||
|     ClassBlockState, | ||||
|     ExternBlockState, | ||||
|     NamespaceBlockState, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| class SymbolManager: | ||||
|     def __init__(self): | ||||
|         self.api = ApiEntries() | ||||
|         self.name_hashes = set() | ||||
| 
 | ||||
|     # Calculate hash of name and raise exception if it already is in the set | ||||
|     def _name_check(self, name: str): | ||||
|         name_hash = gnu_sym_hash(name) | ||||
|         if name_hash in self.name_hashes: | ||||
|             raise Exception(f"Hash collision on {name}") | ||||
|         self.name_hashes.add(name_hash) | ||||
| 
 | ||||
|     def add_function(self, function_def: ApiEntryFunction): | ||||
|         if function_def in self.api.functions: | ||||
|             return | ||||
|         self._name_check(function_def.name) | ||||
|         self.api.functions.add(function_def) | ||||
| 
 | ||||
|     def add_variable(self, variable_def: ApiEntryVariable): | ||||
|         if variable_def in self.api.variables: | ||||
|             return | ||||
|         self._name_check(variable_def.name) | ||||
|         self.api.variables.add(variable_def) | ||||
| 
 | ||||
|     def add_header(self, header: str): | ||||
|         self.api.headers.add(ApiHeader(header)) | ||||
| 
 | ||||
| 
 | ||||
| def gnu_sym_hash(name: str): | ||||
|     h = 0x1505 | ||||
|     for c in name: | ||||
|         h = (h << 5) + h + ord(c) | ||||
|     return str(hex(h))[-8:] | ||||
| 
 | ||||
| 
 | ||||
| class SdkCollector: | ||||
|     def __init__(self): | ||||
|         self.symbol_manager = SymbolManager() | ||||
| 
 | ||||
|     def add_header_to_sdk(self, header: str): | ||||
|         self.symbol_manager.add_header(header) | ||||
| 
 | ||||
|     def process_source_file_for_sdk(self, file_path: str): | ||||
|         visitor = SdkCxxVisitor(self.symbol_manager) | ||||
|         with open(file_path, "rt") as f: | ||||
|             content = f.read() | ||||
|         parser = CxxParser(file_path, content, visitor, None) | ||||
|         parser.parse() | ||||
| 
 | ||||
|     def get_api(self): | ||||
|         return self.symbol_manager.api | ||||
| 
 | ||||
| 
 | ||||
| def stringify_array_dimension(size_descr): | ||||
|     if not size_descr: | ||||
|         return "" | ||||
|     return stringify_descr(size_descr) | ||||
| 
 | ||||
| 
 | ||||
| def stringify_array_descr(type_descr): | ||||
|     assert isinstance(type_descr, Array) | ||||
|     return ( | ||||
|         stringify_descr(type_descr.array_of), | ||||
|         stringify_array_dimension(type_descr.size), | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def stringify_descr(type_descr): | ||||
|     if isinstance(type_descr, (NameSpecifier, FundamentalSpecifier)): | ||||
|         return type_descr.name | ||||
|     elif isinstance(type_descr, PQName): | ||||
|         return "::".join(map(stringify_descr, type_descr.segments)) | ||||
|     elif isinstance(type_descr, Pointer): | ||||
|         # Hack | ||||
|         if isinstance(type_descr.ptr_to, FunctionType): | ||||
|             return stringify_descr(type_descr.ptr_to) | ||||
|         return f"{stringify_descr(type_descr.ptr_to)}*" | ||||
|     elif isinstance(type_descr, Type): | ||||
|         return ( | ||||
|             f"{'const ' if type_descr.const else ''}" | ||||
|             f"{'volatile ' if type_descr.volatile else ''}" | ||||
|             f"{stringify_descr(type_descr.typename)}" | ||||
|         ) | ||||
|     elif isinstance(type_descr, Parameter): | ||||
|         return stringify_descr(type_descr.type) | ||||
|     elif isinstance(type_descr, Array): | ||||
|         # Hack for 2d arrays | ||||
|         if isinstance(type_descr.array_of, Array): | ||||
|             argtype, dimension = stringify_array_descr(type_descr.array_of) | ||||
|             return ( | ||||
|                 f"{argtype}[{stringify_array_dimension(type_descr.size)}][{dimension}]" | ||||
|             ) | ||||
|         return f"{stringify_descr(type_descr.array_of)}[{stringify_array_dimension(type_descr.size)}]" | ||||
|     elif isinstance(type_descr, Value): | ||||
|         return " ".join(map(stringify_descr, type_descr.tokens)) | ||||
|     elif isinstance(type_descr, FunctionType): | ||||
|         return f"{stringify_descr(type_descr.return_type)} (*)({', '.join(map(stringify_descr, type_descr.parameters))})" | ||||
|     elif isinstance(type_descr, Token): | ||||
|         return type_descr.value | ||||
|     elif type_descr is None: | ||||
|         return "" | ||||
|     else: | ||||
|         raise Exception("unsupported type_descr: %s" % type_descr) | ||||
| 
 | ||||
| 
 | ||||
| class SdkCxxVisitor: | ||||
|     def __init__(self, symbol_manager: SymbolManager): | ||||
|         self.api = symbol_manager | ||||
| 
 | ||||
|     def on_variable(self, state: State, v: Variable) -> None: | ||||
|         if not v.extern: | ||||
|             return | ||||
| 
 | ||||
|         self.api.add_variable( | ||||
|             ApiEntryVariable( | ||||
|                 stringify_descr(v.name), | ||||
|                 stringify_descr(v.type), | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|     def on_function(self, state: State, fn: Function) -> None: | ||||
|         if fn.inline or fn.has_body: | ||||
|             return | ||||
| 
 | ||||
|         self.api.add_function( | ||||
|             ApiEntryFunction( | ||||
|                 stringify_descr(fn.name), | ||||
|                 stringify_descr(fn.return_type), | ||||
|                 ", ".join(map(stringify_descr, fn.parameters)) | ||||
|                 + (", ..." if fn.vararg else ""), | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|     def on_define(self, state: State, content: str) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_pragma(self, state: State, content: str) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_include(self, state: State, filename: str) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_empty_block_start(self, state: EmptyBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_empty_block_end(self, state: EmptyBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_extern_block_start(self, state: ExternBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_extern_block_end(self, state: ExternBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_namespace_start(self, state: NamespaceBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_namespace_end(self, state: NamespaceBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_forward_decl(self, state: State, fdecl: ForwardDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_typedef(self, state: State, typedef: Typedef) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_using_namespace(self, state: State, namespace: List[str]) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_using_alias(self, state: State, using: UsingAlias) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_using_declaration(self, state: State, using: UsingDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_enum(self, state: State, enum: EnumDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_start(self, state: ClassBlockState) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_field(self, state: State, f: Field) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_method(self, state: ClassBlockState, method: Method) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_friend(self, state: ClassBlockState, friend: FriendDecl) -> None: | ||||
|         pass | ||||
| 
 | ||||
|     def on_class_end(self, state: ClassBlockState) -> None: | ||||
|         pass | ||||
| @ -8,7 +8,7 @@ import os | ||||
| import pathlib | ||||
| from fbt.elfmanifest import assemble_manifest_data | ||||
| from fbt.appmanifest import FlipperApplication, FlipperManifestException | ||||
| from fbt.sdk import SdkCache | ||||
| from fbt.sdk.cache import SdkCache | ||||
| import itertools | ||||
| from ansi.color import fg | ||||
| 
 | ||||
|  | ||||
| @ -4,7 +4,7 @@ from SCons.Action import Action | ||||
| from SCons.Errors import UserError | ||||
| 
 | ||||
| # from SCons.Scanner import C | ||||
| from SCons.Script import Mkdir, Copy, Delete, Entry | ||||
| from SCons.Script import Entry | ||||
| from SCons.Util import LogicalLines | ||||
| 
 | ||||
| import os.path | ||||
| @ -12,7 +12,8 @@ import posixpath | ||||
| import pathlib | ||||
| import json | ||||
| 
 | ||||
| from fbt.sdk import SdkCollector, SdkCache | ||||
| from fbt.sdk.collector import SdkCollector | ||||
| from fbt.sdk.cache import SdkCache | ||||
| 
 | ||||
| 
 | ||||
| def ProcessSdkDepends(env, filename): | ||||
| @ -49,15 +50,19 @@ def prebuild_sdk_create_origin_file(target, source, env): | ||||
| 
 | ||||
| 
 | ||||
| class SdkMeta: | ||||
|     def __init__(self, env): | ||||
|     def __init__(self, env, tree_builder: "SdkTreeBuilder"): | ||||
|         self.env = env | ||||
|         self.treebuilder = tree_builder | ||||
| 
 | ||||
|     def save_to(self, json_manifest_path: str): | ||||
|         meta_contents = { | ||||
|             "sdk_symbols": self.env["SDK_DEFINITION"].name, | ||||
|             "sdk_symbols": self.treebuilder.build_sdk_file_path( | ||||
|                 self.env["SDK_DEFINITION"].path | ||||
|             ), | ||||
|             "cc_args": self._wrap_scons_vars("$CCFLAGS $_CCCOMCOM"), | ||||
|             "cpp_args": self._wrap_scons_vars("$CXXFLAGS $CCFLAGS $_CCCOMCOM"), | ||||
|             "linker_args": self._wrap_scons_vars("$LINKFLAGS"), | ||||
|             "linker_script": self.env.subst("${LINKER_SCRIPT_PATH}"), | ||||
|         } | ||||
|         with open(json_manifest_path, "wt") as f: | ||||
|             json.dump(meta_contents, f, indent=4) | ||||
| @ -68,6 +73,8 @@ class SdkMeta: | ||||
| 
 | ||||
| 
 | ||||
| class SdkTreeBuilder: | ||||
|     SDK_DIR_SUBST = "SDK_ROOT_DIR" | ||||
| 
 | ||||
|     def __init__(self, env, target, source) -> None: | ||||
|         self.env = env | ||||
|         self.target = target | ||||
| @ -88,6 +95,8 @@ class SdkTreeBuilder: | ||||
|             self.header_depends = list( | ||||
|                 filter(lambda fname: fname.endswith(".h"), depends.split()), | ||||
|             ) | ||||
|             self.header_depends.append(self.env.subst("${LINKER_SCRIPT_PATH}")) | ||||
|             self.header_depends.append(self.env.subst("${SDK_DEFINITION}")) | ||||
|             self.header_dirs = sorted( | ||||
|                 set(map(os.path.normpath, map(os.path.dirname, self.header_depends))) | ||||
|             ) | ||||
| @ -102,17 +111,33 @@ class SdkTreeBuilder: | ||||
|         ) | ||||
| 
 | ||||
|         sdk_dirs = ", ".join(f"'{dir}'" for dir in self.header_dirs) | ||||
|         for dir in full_fw_paths: | ||||
|             if dir in sdk_dirs: | ||||
|                 filtered_paths.append( | ||||
|                     posixpath.normpath(posixpath.join(self.target_sdk_dir_name, dir)) | ||||
|                 ) | ||||
|         filtered_paths.extend( | ||||
|             map( | ||||
|                 self.build_sdk_file_path, | ||||
|                 filter(lambda path: path in sdk_dirs, full_fw_paths), | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|         sdk_env = self.env.Clone() | ||||
|         sdk_env.Replace(CPPPATH=filtered_paths) | ||||
|         meta = SdkMeta(sdk_env) | ||||
|         sdk_env.Replace( | ||||
|             CPPPATH=filtered_paths, | ||||
|             LINKER_SCRIPT=self.env.subst("${APP_LINKER_SCRIPT}"), | ||||
|             ORIG_LINKER_SCRIPT_PATH=self.env["LINKER_SCRIPT_PATH"], | ||||
|             LINKER_SCRIPT_PATH=self.build_sdk_file_path("${ORIG_LINKER_SCRIPT_PATH}"), | ||||
|         ) | ||||
| 
 | ||||
|         meta = SdkMeta(sdk_env, self) | ||||
|         meta.save_to(self.target[0].path) | ||||
| 
 | ||||
|     def build_sdk_file_path(self, orig_path: str) -> str: | ||||
|         return posixpath.normpath( | ||||
|             posixpath.join( | ||||
|                 self.SDK_DIR_SUBST, | ||||
|                 self.target_sdk_dir_name, | ||||
|                 orig_path, | ||||
|             ) | ||||
|         ).replace("\\", "/") | ||||
| 
 | ||||
|     def emitter(self, target, source, env): | ||||
|         target_folder = target[0] | ||||
|         target = [target_folder.File("sdk.opts")] | ||||
| @ -128,8 +153,6 @@ class SdkTreeBuilder: | ||||
|         for sdkdir in dirs_to_create: | ||||
|             os.makedirs(sdkdir, exist_ok=True) | ||||
| 
 | ||||
|         shutil.copy2(self.env["SDK_DEFINITION"].path, self.sdk_root_dir.path) | ||||
| 
 | ||||
|         for header in self.header_depends: | ||||
|             shutil.copy2(header, self.sdk_deploy_dir.File(header).path) | ||||
| 
 | ||||
|  | ||||
| @ -48,48 +48,52 @@ class Main(App): | ||||
|         ) | ||||
|         self.parser_copy.set_defaults(func=self.copy) | ||||
| 
 | ||||
|     def get_project_filename(self, project, filetype): | ||||
|     def get_project_file_name(self, project: ProjectDir, filetype: str) -> str: | ||||
|         #  Temporary fix | ||||
|         project_name = project.project | ||||
|         if project_name == "firmware": | ||||
|             if filetype == "zip": | ||||
|                 project_name = "sdk" | ||||
|             elif filetype != "elf": | ||||
|                 project_name = "full" | ||||
|         if project_name == "firmware" and filetype != "elf": | ||||
|             project_name = "full" | ||||
| 
 | ||||
|         return f"{self.DIST_FILE_PREFIX}{self.target}-{project_name}-{self.args.suffix}.{filetype}" | ||||
|         return self.get_dist_file_name(project_name, filetype) | ||||
| 
 | ||||
|     def get_dist_filepath(self, filename): | ||||
|     def get_dist_file_name(self, dist_artifact_type: str, filetype: str) -> str: | ||||
|         return f"{self.DIST_FILE_PREFIX}{self.target}-{dist_artifact_type}-{self.args.suffix}.{filetype}" | ||||
| 
 | ||||
|     def get_dist_file_path(self, filename: str) -> str: | ||||
|         return join(self.output_dir_path, filename) | ||||
| 
 | ||||
|     def copy_single_project(self, project): | ||||
|     def copy_single_project(self, project: ProjectDir) -> None: | ||||
|         obj_directory = join("build", project.dir) | ||||
| 
 | ||||
|         for filetype in ("elf", "bin", "dfu", "json"): | ||||
|             if exists(src_file := join(obj_directory, f"{project.project}.{filetype}")): | ||||
|                 shutil.copyfile( | ||||
|                     src_file, | ||||
|                     self.get_dist_filepath( | ||||
|                         self.get_project_filename(project, filetype) | ||||
|                     self.get_dist_file_path( | ||||
|                         self.get_project_file_name(project, filetype) | ||||
|                     ), | ||||
|                 ) | ||||
|             if exists(sdk_folder := join(obj_directory, "sdk")): | ||||
|                 with zipfile.ZipFile( | ||||
|                     self.get_dist_filepath(self.get_project_filename(project, "zip")), | ||||
|                     "w", | ||||
|                     zipfile.ZIP_DEFLATED, | ||||
|                 ) as zf: | ||||
|                     for root, dirs, files in walk(sdk_folder): | ||||
|                         for file in files: | ||||
|                             zf.write( | ||||
|                                 join(root, file), | ||||
|                                 relpath( | ||||
|                                     join(root, file), | ||||
|                                     sdk_folder, | ||||
|                                 ), | ||||
|                             ) | ||||
|         for foldertype in ("sdk", "lib"): | ||||
|             if exists(sdk_folder := join(obj_directory, foldertype)): | ||||
|                 self.package_zip(foldertype, sdk_folder) | ||||
| 
 | ||||
|     def copy(self): | ||||
|     def package_zip(self, foldertype, sdk_folder): | ||||
|         with zipfile.ZipFile( | ||||
|             self.get_dist_file_path(self.get_dist_file_name(foldertype, "zip")), | ||||
|             "w", | ||||
|             zipfile.ZIP_DEFLATED, | ||||
|         ) as zf: | ||||
|             for root, _, files in walk(sdk_folder): | ||||
|                 for file in files: | ||||
|                     zf.write( | ||||
|                         join(root, file), | ||||
|                         relpath( | ||||
|                             join(root, file), | ||||
|                             sdk_folder, | ||||
|                         ), | ||||
|                     ) | ||||
| 
 | ||||
|     def copy(self) -> int: | ||||
|         self.projects = dict( | ||||
|             map( | ||||
|                 lambda pd: (pd.project, pd), | ||||
| @ -144,12 +148,12 @@ class Main(App): | ||||
|                 "-t", | ||||
|                 self.target, | ||||
|                 "--dfu", | ||||
|                 self.get_dist_filepath( | ||||
|                     self.get_project_filename(self.projects["firmware"], "dfu") | ||||
|                 self.get_dist_file_path( | ||||
|                     self.get_project_file_name(self.projects["firmware"], "dfu") | ||||
|                 ), | ||||
|                 "--stage", | ||||
|                 self.get_dist_filepath( | ||||
|                     self.get_project_filename(self.projects["updater"], "bin") | ||||
|                 self.get_dist_file_path( | ||||
|                     self.get_project_file_name(self.projects["updater"], "bin") | ||||
|                 ), | ||||
|             ] | ||||
|             if self.args.resources: | ||||
|  | ||||
| @ -23,12 +23,12 @@ if (!(Test-Path -LiteralPath "$repo_root\toolchain")) { | ||||
|     New-Item "$repo_root\toolchain" -ItemType Directory | ||||
| } | ||||
| 
 | ||||
| Write-Host -NoNewline "Unziping Windows toolchain.." | ||||
| Write-Host -NoNewline "Extracting Windows toolchain.." | ||||
| Add-Type -Assembly "System.IO.Compression.Filesystem" | ||||
| [System.IO.Compression.ZipFile]::ExtractToDirectory("$toolchain_zip", "$repo_root\") | ||||
| [System.IO.Compression.ZipFile]::ExtractToDirectory("$repo_root\$toolchain_zip", "$repo_root\") | ||||
| Move-Item -Path "$repo_root\$toolchain_dir" -Destination "$repo_root\toolchain\x86_64-windows" | ||||
| Write-Host "done!" | ||||
| 
 | ||||
| Write-Host -NoNewline "Clearing temporary files.." | ||||
| Write-Host -NoNewline "Cleaning up temporary files.." | ||||
| Remove-Item -LiteralPath "$repo_root\$toolchain_zip" -Force | ||||
| Write-Host "done!" | ||||
|  | ||||
| @ -21,7 +21,7 @@ appenv = ENV.Clone( | ||||
| ) | ||||
| 
 | ||||
| appenv.Replace( | ||||
|     LINKER_SCRIPT="application_ext", | ||||
|     LINKER_SCRIPT=appenv.subst("$APP_LINKER_SCRIPT"), | ||||
| ) | ||||
| 
 | ||||
| appenv.AppendUnique( | ||||
|  | ||||
| @ -32,12 +32,27 @@ else: | ||||
|         ], | ||||
|     ) | ||||
| 
 | ||||
| ENV.Append( | ||||
| ENV.AppendUnique( | ||||
|     LINKFLAGS=[ | ||||
|         "-Tfirmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", | ||||
|         "-specs=nano.specs", | ||||
|         "-specs=nosys.specs", | ||||
|         "-Wl,--gc-sections", | ||||
|         "-Wl,--undefined=uxTopUsedPriority", | ||||
|         "-Wl,--wrap,_malloc_r", | ||||
|         "-Wl,--wrap,_free_r", | ||||
|         "-Wl,--wrap,_calloc_r", | ||||
|         "-Wl,--wrap,_realloc_r", | ||||
|         "-n", | ||||
|         "-Xlinker", | ||||
|         "-Map=${TARGET}.map", | ||||
|         "-T${LINKER_SCRIPT_PATH}", | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| ENV.SetDefault( | ||||
|     LINKER_SCRIPT_PATH="firmware/targets/f${TARGET_HW}/${LINKER_SCRIPT}.ld", | ||||
| ) | ||||
| 
 | ||||
| if ENV["FIRMWARE_BUILD_CFG"] == "updater": | ||||
|     ENV.Append( | ||||
|         IMAGE_BASE_ADDRESS="0x20000000", | ||||
| @ -47,4 +62,5 @@ else: | ||||
|     ENV.Append( | ||||
|         IMAGE_BASE_ADDRESS="0x8000000", | ||||
|         LINKER_SCRIPT="stm32wb55xx_flash", | ||||
|         APP_LINKER_SCRIPT="application_ext", | ||||
|     ) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 hedger
						hedger