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…
Reference in New Issue
Block a user