[FL-3162] Moved ufbt to fbt codebase (#2520)

* scripts: moved ufbt code
* ufbt: fixed tool path
* ufbt: fixed linter/formatter target descriptions
* scripts: ufbt: cleanup
* fbt: moved fap launch target to tools; ufbt fixes
* fbt: fixed missing headers from SDK
* ufbt: removed debug output
* ufbt: moved project template to main codebase
* ufbt: fixed vscode_dist
* ufbt: path naming changes
* fbt: error message for older ufbt versions
* ufbt: docs fixes
* ufbt: fixed build dir location
* fbt: fixes for extapps objcopy
* fbt: extapps: removed extra debug output; fixed formatting
* ufbt: handle launch target for multiple known apps
* ufbt: dropping wrapper; linter fixes
* ufbt: fixed boostrap path
* ufbt: renamed entrypoint
* ufbt: updated vscode config
* ufbt: moved sconsign db location
* ufbt: fixed sconsign path
* fbt: SDK builders rework
* fbt: reworked sdk packaging
* ufbt: additional checks and state processing
* ufbt: fixed sdk state file location
* dist: not packaging pycache
* dump commit json content
* Github: more workflow debug prints
* Github: fix incorrect commit meta extraction in get_env.py
* ufbt, fbt: changed SConsEnvironmentError->StopError
* fbtenv: no longer needs SCRIPT_PATH pre-set
* ufbt: fixed sdk state check
* scripts: exception fixes for storage.py
* scripts: fbtenv: added FBT_TOOLCHAIN_PATH for on Windows for compat
* ufbt: app template: creating .gitkeep for images folder
* ufbt: app template: fixed .gitkeep creation
* docs: formatting fixes for AppManifests; added link to ufbt
* fbt: added link to PyPI for old ufbt versions
* sdk: fixed dir component paths

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
hedger
2023-04-06 06:44:37 +04:00
committed by GitHub
parent 8a021ae48c
commit a91d319839
32 changed files with 1496 additions and 200 deletions

View File

@@ -1,6 +1,6 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Errors import SConsEnvironmentError
from SCons.Errors import StopError
import os
import subprocess
@@ -90,7 +90,7 @@ def proto_ver_generator(target, source, env):
source_dir=src_dir,
)
except (subprocess.CalledProcessError, EnvironmentError) as e:
raise SConsEnvironmentError("Git: describe failed")
raise StopError("Git: describe failed")
git_major, git_minor = git_describe.split(".")
version_file_data = (

View File

@@ -21,6 +21,10 @@ from fbt.sdk.cache import SdkCache
from fbt.util import extract_abs_dir_path
_FAP_META_SECTION = ".fapmeta"
_FAP_FILEASSETS_SECTION = ".fapassets"
@dataclass
class FlipperExternalAppInfo:
app: FlipperApplication
@@ -234,6 +238,8 @@ def BuildAppElf(env, app):
def prepare_app_metadata(target, source, env):
metadata_node = next(filter(lambda t: t.name.endswith(_FAP_META_SECTION), target))
sdk_cache = SdkCache(env["SDK_DEFINITION"].path, load_version_only=True)
if not sdk_cache.is_buildable():
@@ -242,8 +248,7 @@ def prepare_app_metadata(target, source, env):
)
app = env["APP"]
meta_file_name = source[0].path + ".meta"
with open(meta_file_name, "wb") as f:
with open(metadata_node.abspath, "wb") as f:
f.write(
assemble_manifest_data(
app_manifest=app,
@@ -337,24 +342,26 @@ def embed_app_metadata_emitter(target, source, env):
if app.apptype == FlipperAppType.PLUGIN:
target[0].name = target[0].name.replace(".fap", ".fal")
meta_file_name = source[0].path + ".meta"
target.append("#" + meta_file_name)
target.append(env.File(source[0].abspath + _FAP_META_SECTION))
if app.fap_file_assets:
files_section = source[0].path + ".files.section"
target.append("#" + files_section)
target.append(env.File(source[0].abspath + _FAP_FILEASSETS_SECTION))
return (target, source)
def prepare_app_files(target, source, env):
files_section_node = next(
filter(lambda t: t.name.endswith(_FAP_FILEASSETS_SECTION), target)
)
app = env["APP"]
directory = app._appdir.Dir(app.fap_file_assets)
directory = env.Dir(app._apppath).Dir(app.fap_file_assets)
if not directory.exists():
raise UserError(f"File asset directory {directory} does not exist")
bundler = FileBundler(directory.abspath)
bundler.export(source[0].path + ".files.section")
bundler.export(files_section_node.abspath)
def generate_embed_app_metadata_actions(source, target, env, for_signature):
@@ -367,15 +374,15 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature):
objcopy_str = (
"${OBJCOPY} "
"--remove-section .ARM.attributes "
"--add-section .fapmeta=${SOURCE}.meta "
"--add-section ${_FAP_META_SECTION}=${SOURCE}${_FAP_META_SECTION} "
)
if app.fap_file_assets:
actions.append(Action(prepare_app_files, "$APPFILE_COMSTR"))
objcopy_str += "--add-section .fapassets=${SOURCE}.files.section "
objcopy_str += "--add-section ${_FAP_FILEASSETS_SECTION}=${SOURCE}${_FAP_FILEASSETS_SECTION} "
objcopy_str += (
"--set-section-flags .fapmeta=contents,noload,readonly,data "
"--set-section-flags ${_FAP_META_SECTION}=contents,noload,readonly,data "
"--strip-debug --strip-unneeded "
"--add-gnu-debuglink=${SOURCE} "
"${SOURCES} ${TARGET}"
@@ -391,6 +398,51 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature):
return Action(actions)
def AddAppLaunchTarget(env, appname, launch_target_name):
deploy_sources, flipp_dist_paths, validators = [], [], []
run_script_extra_ars = ""
def _add_dist_targets(app_artifacts):
validators.append(app_artifacts.validator)
for _, ext_path in app_artifacts.dist_entries:
deploy_sources.append(app_artifacts.compact)
flipp_dist_paths.append(f"/ext/{ext_path}")
return app_artifacts
def _add_host_app_to_targets(host_app):
artifacts_app_to_run = env["EXT_APPS"].get(host_app.appid, None)
_add_dist_targets(artifacts_app_to_run)
for plugin in host_app._plugins:
_add_dist_targets(env["EXT_APPS"].get(plugin.appid, None))
artifacts_app_to_run = env.GetExtAppByIdOrPath(appname)
if artifacts_app_to_run.app.apptype == FlipperAppType.PLUGIN:
# We deploy host app instead
host_app = env["APPMGR"].get(artifacts_app_to_run.app.requires[0])
if host_app:
if host_app.apptype == FlipperAppType.EXTERNAL:
_add_host_app_to_targets(host_app)
else:
# host app is a built-in app
run_script_extra_ars = f"-a {host_app.name}"
_add_dist_targets(artifacts_app_to_run)
else:
raise UserError("Host app is unknown")
else:
_add_host_app_to_targets(artifacts_app_to_run.app)
# print(deploy_sources, flipp_dist_paths)
env.PhonyTarget(
launch_target_name,
'${PYTHON3} "${APP_RUN_SCRIPT}" ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}',
source=deploy_sources,
FLIPPER_FILE_TARGETS=flipp_dist_paths,
EXTRA_ARGS=run_script_extra_ars,
)
env.Alias(launch_target_name, validators)
def generate(env, **kw):
env.SetDefault(
EXT_APPS_WORK_DIR="${FBT_FAP_DEBUG_ELF_ROOT}",
@@ -410,10 +462,14 @@ def generate(env, **kw):
EXT_APPS={}, # appid -> FlipperExternalAppInfo
EXT_LIBS={},
_APP_ICONS=[],
_FAP_META_SECTION=_FAP_META_SECTION,
_FAP_FILEASSETS_SECTION=_FAP_FILEASSETS_SECTION,
)
env.AddMethod(BuildAppElf)
env.AddMethod(GetExtAppByIdOrPath)
env.AddMethod(AddAppLaunchTarget)
env.Append(
BUILDERS={
"FapDist": Builder(

View File

@@ -38,13 +38,13 @@ def ProcessSdkDepends(env, filename):
return depends
def prebuild_sdk_emitter(target, source, env):
def api_amalgam_emitter(target, source, env):
target.append(env.ChangeFileExtension(target[0], ".d"))
target.append(env.ChangeFileExtension(target[0], ".i.c"))
return target, source
def prebuild_sdk_create_origin_file(target, source, env):
def api_amalgam_gen_origin_header(target, source, env):
mega_file = env.subst("${TARGET}.c", target=target[0])
with open(mega_file, "wt") as sdk_c:
sdk_c.write(
@@ -87,6 +87,7 @@ class SdkMeta:
class SdkTreeBuilder:
SDK_DIR_SUBST = "SDK_ROOT_DIR"
SDK_APP_EP_SUBST = "SDK_APP_EP_SUBST"
HEADER_EXTENSIONS = [".h", ".hpp"]
def __init__(self, env, target, source) -> None:
self.env = env
@@ -111,7 +112,10 @@ class SdkTreeBuilder:
lines = LogicalLines(deps_f).readlines()
_, depends = lines[0].split(":", 1)
self.header_depends = list(
filter(lambda fname: fname.endswith(".h"), depends.split()),
filter(
lambda fname: any(map(fname.endswith, self.HEADER_EXTENSIONS)),
depends.split(),
),
)
self.header_depends.append(self.sdk_env.subst("${LINKER_SCRIPT_PATH}"))
self.header_depends.append(self.sdk_env.subst("${SDK_DEFINITION}"))
@@ -180,12 +184,12 @@ class SdkTreeBuilder:
self._generate_sdk_meta()
def deploy_sdk_tree_action(target, source, env):
def deploy_sdk_header_tree_action(target, source, env):
sdk_tree = SdkTreeBuilder(env, target, source)
return sdk_tree.deploy_action()
def deploy_sdk_tree_emitter(target, source, env):
def deploy_sdk_header_tree_emitter(target, source, env):
sdk_tree = SdkTreeBuilder(env, target, source)
return sdk_tree.emitter(target, source, env)
@@ -224,7 +228,7 @@ def _check_sdk_is_up2date(sdk_cache: SdkCache):
)
def validate_sdk_cache(source, target, env):
def validate_api_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)
@@ -237,7 +241,7 @@ def validate_sdk_cache(source, target, env):
_check_sdk_is_up2date(sdk_cache)
def generate_sdk_symbols(source, target, env):
def generate_api_table(source, target, env):
sdk_cache = SdkCache(source[0].path)
_check_sdk_is_up2date(sdk_cache)
@@ -249,11 +253,11 @@ def generate_sdk_symbols(source, target, env):
def generate(env, **kw):
if not env["VERBOSE"]:
env.SetDefault(
SDK_PREGEN_COMSTR="\tPREGEN\t${TARGET}",
SDK_COMSTR="\tSDKSRC\t${TARGET}",
SDK_AMALGAMATE_HEADER_COMSTR="\tAPIPREP\t${TARGET}",
SDK_AMALGAMATE_PP_COMSTR="\tAPIPP\t${TARGET}",
SDKSYM_UPDATER_COMSTR="\tSDKCHK\t${TARGET}",
SDKSYM_GENERATOR_COMSTR="\tSDKSYM\t${TARGET}",
SDKDEPLOY_COMSTR="\tSDKTREE\t${TARGET}",
APITABLE_GENERATOR_COMSTR="\tAPITBL\t${TARGET}",
SDKTREE_COMSTR="\tSDKTREE\t${TARGET}",
)
# Filtering out things cxxheaderparser cannot handle
@@ -274,40 +278,40 @@ def generate(env, **kw):
env.AddMethod(ProcessSdkDepends)
env.Append(
BUILDERS={
"SDKPrebuilder": Builder(
emitter=prebuild_sdk_emitter,
"ApiAmalgamator": Builder(
emitter=api_amalgam_emitter,
action=[
Action(
prebuild_sdk_create_origin_file,
"$SDK_PREGEN_COMSTR",
api_amalgam_gen_origin_header,
"$SDK_AMALGAMATE_HEADER_COMSTR",
),
Action(
"$CC -o $TARGET -E -P $CCFLAGS $_CCCOMCOM $SDK_PP_FLAGS -MMD ${TARGET}.c",
"$SDK_COMSTR",
"$SDK_AMALGAMATE_PP_COMSTR",
),
],
suffix=".i",
),
"SDKTree": Builder(
"SDKHeaderTreeExtractor": Builder(
action=Action(
deploy_sdk_tree_action,
"$SDKDEPLOY_COMSTR",
deploy_sdk_header_tree_action,
"$SDKTREE_COMSTR",
),
emitter=deploy_sdk_tree_emitter,
emitter=deploy_sdk_header_tree_emitter,
src_suffix=".d",
),
"SDKSymUpdater": Builder(
"ApiTableValidator": Builder(
action=Action(
validate_sdk_cache,
validate_api_cache,
"$SDKSYM_UPDATER_COMSTR",
),
suffix=".csv",
src_suffix=".i",
),
"SDKSymGenerator": Builder(
"ApiSymbolTable": Builder(
action=Action(
generate_sdk_symbols,
"$SDKSYM_GENERATOR_COMSTR",
generate_api_table,
"$APITABLE_GENERATOR_COMSTR",
),
suffix=".h",
src_suffix=".csv",

View File

@@ -1,4 +1,6 @@
import SCons.Warnings as Warnings
from SCons.Errors import UserError
# from SCons.Script.Main import find_deepest_user_frame
@@ -36,6 +38,11 @@ def fbt_warning(e):
def generate(env):
if env.get("UFBT_WORK_DIR"):
raise UserError(
"You're trying to use a new format SDK on a legacy ufbt version. "
"Please update ufbt to a version from PyPI: https://pypi.org/project/ufbt/"
)
Warnings._warningOut = fbt_warning