mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2024-12-30 08:44:34 +03:00
209 lines
6.0 KiB
Python
209 lines
6.0 KiB
Python
|
from SCons.Builder import Builder
|
||
|
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.Util import LogicalLines
|
||
|
|
||
|
import os.path
|
||
|
import posixpath
|
||
|
import pathlib
|
||
|
|
||
|
from fbt.sdk import SdkCollector, SdkCache
|
||
|
|
||
|
|
||
|
def prebuild_sdk_emitter(target, source, env):
|
||
|
target.append(env.ChangeFileExtension(target[0], ".d"))
|
||
|
return target, source
|
||
|
|
||
|
|
||
|
def prebuild_sdk_create_origin_file(target, source, env):
|
||
|
mega_file = env.subst("${TARGET}.c", target=target[0])
|
||
|
with open(mega_file, "wt") as sdk_c:
|
||
|
sdk_c.write("\n".join(f"#include <{h.path}>" for h in env["SDK_HEADERS"]))
|
||
|
|
||
|
|
||
|
class SdkTreeBuilder:
|
||
|
def __init__(self, env, target, source) -> None:
|
||
|
self.env = env
|
||
|
self.target = target
|
||
|
self.source = source
|
||
|
|
||
|
self.header_depends = []
|
||
|
self.header_dirs = []
|
||
|
|
||
|
self.target_sdk_dir = env.subst("f${TARGET_HW}_sdk")
|
||
|
self.sdk_deploy_dir = target[0].Dir(self.target_sdk_dir)
|
||
|
|
||
|
def _parse_sdk_depends(self):
|
||
|
deps_file = self.source[0]
|
||
|
with open(deps_file.path, "rt") as deps_f:
|
||
|
lines = LogicalLines(deps_f).readlines()
|
||
|
_, depends = lines[0].split(":", 1)
|
||
|
self.header_depends = list(
|
||
|
filter(lambda fname: fname.endswith(".h"), depends.split()),
|
||
|
)
|
||
|
self.header_dirs = sorted(
|
||
|
set(map(os.path.normpath, map(os.path.dirname, self.header_depends)))
|
||
|
)
|
||
|
|
||
|
def _generate_sdk_meta(self):
|
||
|
filtered_paths = [self.target_sdk_dir]
|
||
|
full_fw_paths = list(
|
||
|
map(
|
||
|
os.path.normpath,
|
||
|
(self.env.Dir(inc_dir).relpath for inc_dir in self.env["CPPPATH"]),
|
||
|
)
|
||
|
)
|
||
|
|
||
|
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, dir))
|
||
|
)
|
||
|
|
||
|
sdk_env = self.env.Clone()
|
||
|
sdk_env.Replace(CPPPATH=filtered_paths)
|
||
|
with open(self.target[0].path, "wt") as f:
|
||
|
cmdline_options = sdk_env.subst(
|
||
|
"$CCFLAGS $_CCCOMCOM", target=Entry("dummy")
|
||
|
)
|
||
|
f.write(cmdline_options.replace("\\", "/"))
|
||
|
f.write("\n")
|
||
|
|
||
|
def _create_deploy_commands(self):
|
||
|
dirs_to_create = set(
|
||
|
self.sdk_deploy_dir.Dir(dirpath) for dirpath in self.header_dirs
|
||
|
)
|
||
|
actions = [
|
||
|
Delete(self.sdk_deploy_dir),
|
||
|
Mkdir(self.sdk_deploy_dir),
|
||
|
]
|
||
|
actions += [Mkdir(d) for d in dirs_to_create]
|
||
|
|
||
|
actions += [
|
||
|
Copy(
|
||
|
self.sdk_deploy_dir.File(h).path,
|
||
|
h,
|
||
|
)
|
||
|
for h in self.header_depends
|
||
|
]
|
||
|
return actions
|
||
|
|
||
|
def generate_actions(self):
|
||
|
self._parse_sdk_depends()
|
||
|
self._generate_sdk_meta()
|
||
|
|
||
|
return self._create_deploy_commands()
|
||
|
|
||
|
|
||
|
def deploy_sdk_tree(target, source, env, for_signature):
|
||
|
if for_signature:
|
||
|
return []
|
||
|
|
||
|
sdk_tree = SdkTreeBuilder(env, target, source)
|
||
|
return sdk_tree.generate_actions()
|
||
|
|
||
|
|
||
|
def gen_sdk_data(sdk_cache: SdkCache):
|
||
|
api_def = []
|
||
|
api_def.extend(
|
||
|
(f"#include <{h.name}>" for h in sdk_cache.get_headers()),
|
||
|
)
|
||
|
|
||
|
api_def.append(f"const int elf_api_version = {sdk_cache.version.as_int()};")
|
||
|
|
||
|
api_def.append(
|
||
|
"static constexpr auto elf_api_table = sort(create_array_t<sym_entry>("
|
||
|
)
|
||
|
|
||
|
api_lines = []
|
||
|
for fun_def in sdk_cache.get_functions():
|
||
|
api_lines.append(
|
||
|
f"API_METHOD({fun_def.name}, {fun_def.returns}, ({fun_def.params}))"
|
||
|
)
|
||
|
|
||
|
for var_def in sdk_cache.get_variables():
|
||
|
api_lines.append(f"API_VARIABLE({var_def.name}, {var_def.var_type })")
|
||
|
|
||
|
api_def.append(",\n".join(api_lines))
|
||
|
|
||
|
api_def.append("));")
|
||
|
return api_def
|
||
|
|
||
|
|
||
|
def _check_sdk_is_up2date(sdk_cache: SdkCache):
|
||
|
if not sdk_cache.is_buildable():
|
||
|
raise UserError(
|
||
|
"SDK version is not finalized, please review changes and re-run operation"
|
||
|
)
|
||
|
|
||
|
|
||
|
def validate_sdk_cache(source, target, env):
|
||
|
# print(f"Generating SDK for {source[0]} to {target[0]}")
|
||
|
current_sdk = SdkCollector()
|
||
|
current_sdk.process_source_file_for_sdk(source[0].path)
|
||
|
for h in env["SDK_HEADERS"]:
|
||
|
current_sdk.add_header_to_sdk(pathlib.Path(h.path).as_posix())
|
||
|
|
||
|
sdk_cache = SdkCache(target[0].path)
|
||
|
sdk_cache.validate_api(current_sdk.get_api())
|
||
|
sdk_cache.save()
|
||
|
_check_sdk_is_up2date(sdk_cache)
|
||
|
|
||
|
|
||
|
def generate_sdk_symbols(source, target, env):
|
||
|
sdk_cache = SdkCache(source[0].path)
|
||
|
_check_sdk_is_up2date(sdk_cache)
|
||
|
|
||
|
api_def = gen_sdk_data(sdk_cache)
|
||
|
with open(target[0].path, "wt") as f:
|
||
|
f.write("\n".join(api_def))
|
||
|
|
||
|
|
||
|
def generate(env, **kw):
|
||
|
env.Append(
|
||
|
BUILDERS={
|
||
|
"SDKPrebuilder": Builder(
|
||
|
emitter=prebuild_sdk_emitter,
|
||
|
action=[
|
||
|
Action(
|
||
|
prebuild_sdk_create_origin_file,
|
||
|
"$SDK_PREGEN_COMSTR",
|
||
|
),
|
||
|
Action(
|
||
|
"$CC -o $TARGET -E -P $CCFLAGS $_CCCOMCOM $SDK_PP_FLAGS -MMD ${TARGET}.c",
|
||
|
"$SDK_COMSTR",
|
||
|
),
|
||
|
],
|
||
|
suffix=".i",
|
||
|
),
|
||
|
"SDKTree": Builder(
|
||
|
generator=deploy_sdk_tree,
|
||
|
src_suffix=".d",
|
||
|
),
|
||
|
"SDKSymUpdater": Builder(
|
||
|
action=Action(
|
||
|
validate_sdk_cache,
|
||
|
"$SDKSYM_UPDATER_COMSTR",
|
||
|
),
|
||
|
suffix=".csv",
|
||
|
src_suffix=".i",
|
||
|
),
|
||
|
"SDKSymGenerator": Builder(
|
||
|
action=Action(
|
||
|
generate_sdk_symbols,
|
||
|
"$SDKSYM_GENERATOR_COMSTR",
|
||
|
),
|
||
|
suffix=".h",
|
||
|
src_suffix=".csv",
|
||
|
),
|
||
|
}
|
||
|
)
|
||
|
|
||
|
|
||
|
def exists(env):
|
||
|
return True
|