1
mirror of https://github.com/flipperdevices/flipperzero-firmware.git synced 2025-12-13 05:19:50 +04:00

[FL-3600] Added fal_embedded parameter for PLUGIN apps (#3083)

* fbt, ufbt: added `fal_embedded` parameter for PLIGIN apps, to embed them into .fap
* fbt: fixed dependency settings for assets
* fbt: extapps: Removed unneeded casts
* fbt: extapps: code simplification
* fbt: fal_embedded: fixed dependency relations

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger
2023-09-21 15:56:00 +03:00
committed by GitHub
parent b80dfbe0c5
commit 1891d54baf
5 changed files with 93 additions and 56 deletions

View File

@@ -3,7 +3,7 @@ import os
import pathlib
import shutil
from dataclasses import dataclass, field
from typing import Optional, Dict, List
from typing import Dict, List, Optional
import SCons.Warnings
from ansi.color import fg
@@ -32,11 +32,15 @@ class FlipperExternalAppInfo:
class AppBuilder:
@staticmethod
def get_app_work_dir(env, app):
return env["EXT_APPS_WORK_DIR"].Dir(app.appid)
def __init__(self, env, app):
self.fw_env = env
self.app = app
self.ext_apps_work_dir = env.subst("$EXT_APPS_WORK_DIR")
self.app_work_dir = os.path.join(self.ext_apps_work_dir, self.app.appid)
self.ext_apps_work_dir = env["EXT_APPS_WORK_DIR"]
self.app_work_dir = self.get_app_work_dir(env, app)
self.app_alias = f"fap_{self.app.appid}"
self.externally_built_files = []
self.private_libs = []
@@ -83,9 +87,9 @@ class AppBuilder:
return
fap_icons = self.app_env.CompileIcons(
self.app_env.Dir(self.app_work_dir),
self.app_work_dir,
self.app._appdir.Dir(self.app.fap_icon_assets),
icon_bundle_name=f"{self.app.fap_icon_assets_symbol if self.app.fap_icon_assets_symbol else self.app.appid }_icons",
icon_bundle_name=f"{self.app.fap_icon_assets_symbol or self.app.appid }_icons",
)
self.app_env.Alias("_fap_icons", fap_icons)
self.fw_env.Append(_APP_ICONS=[fap_icons])
@@ -95,7 +99,7 @@ class AppBuilder:
self.private_libs.append(self._build_private_lib(lib_def))
def _build_private_lib(self, lib_def):
lib_src_root_path = os.path.join(self.app_work_dir, "lib", lib_def.name)
lib_src_root_path = self.app_work_dir.Dir("lib").Dir(lib_def.name)
self.app_env.AppendUnique(
CPPPATH=list(
self.app_env.Dir(lib_src_root_path)
@@ -119,9 +123,7 @@ class AppBuilder:
private_lib_env = self.app_env.Clone()
private_lib_env.AppendUnique(
CCFLAGS=[
*lib_def.cflags,
],
CCFLAGS=lib_def.cflags,
CPPDEFINES=lib_def.cdefines,
CPPPATH=list(
map(
@@ -132,14 +134,17 @@ class AppBuilder:
)
return private_lib_env.StaticLibrary(
os.path.join(self.app_work_dir, lib_def.name),
self.app_work_dir.File(lib_def.name),
lib_sources,
)
def _build_app(self):
if self.app.fap_file_assets:
self.app._assets_dirs = [self.app._appdir.Dir(self.app.fap_file_assets)]
self.app_env.Append(
LIBS=[*self.app.fap_libs, *self.private_libs],
CPPPATH=[self.app_env.Dir(self.app_work_dir), self.app._appdir],
CPPPATH=[self.app_work_dir, self.app._appdir],
)
app_sources = list(
@@ -155,32 +160,46 @@ class AppBuilder:
app_artifacts = FlipperExternalAppInfo(self.app)
app_artifacts.debug = self.app_env.Program(
os.path.join(self.ext_apps_work_dir, f"{self.app.appid}_d"),
self.ext_apps_work_dir.File(f"{self.app.appid}_d.elf"),
app_sources,
APP_ENTRY=self.app.entry_point,
)[0]
app_artifacts.compact = self.app_env.EmbedAppMetadata(
os.path.join(self.ext_apps_work_dir, self.app.appid),
self.ext_apps_work_dir.File(f"{self.app.appid}.fap"),
app_artifacts.debug,
APP=self.app,
)[0]
if self.app.embeds_plugins:
self.app._assets_dirs.append(self.app_work_dir.Dir("assets"))
app_artifacts.validator = self.app_env.ValidateAppImports(
app_artifacts.compact
)[0]
if self.app.apptype == FlipperAppType.PLUGIN:
for parent_app_id in self.app.requires:
fal_path = (
f"apps_data/{parent_app_id}/plugins/{app_artifacts.compact.name}"
)
deployable = True
# If it's a plugin for a non-deployable app, don't include it in the resources
if parent_app := self.app._appmanager.get(parent_app_id):
if not parent_app.is_default_deployable:
deployable = False
app_artifacts.dist_entries.append((deployable, fal_path))
if self.app.fal_embedded:
parent_app = self.app._appmanager.get(parent_app_id)
if not parent_app:
raise UserError(
f"Embedded plugin {self.app.appid} requires unknown app {parent_app_id}"
)
self.app_env.Install(
target=self.get_app_work_dir(self.app_env, parent_app)
.Dir("assets")
.Dir("plugins"),
source=app_artifacts.compact,
)
else:
fal_path = f"apps_data/{parent_app_id}/plugins/{app_artifacts.compact.name}"
deployable = True
# If it's a plugin for a non-deployable app, don't include it in the resources
if parent_app := self.app._appmanager.get(parent_app_id):
if not parent_app.is_default_deployable:
deployable = False
app_artifacts.dist_entries.append((deployable, fal_path))
else:
fap_path = f"apps/{self.app.fap_category}/{app_artifacts.compact.name}"
app_artifacts.dist_entries.append(
@@ -194,7 +213,7 @@ class AppBuilder:
# Extra things to clean up along with the app
self.app_env.Clean(
app_artifacts.debug,
[*self.externally_built_files, self.app_env.Dir(self.app_work_dir)],
[*self.externally_built_files, self.app_work_dir],
)
# Create listing of the app
@@ -219,13 +238,10 @@ class AppBuilder:
)
# Add dependencies on file assets
if self.app.fap_file_assets:
for assets_dir in self.app._assets_dirs:
self.app_env.Depends(
app_artifacts.compact,
self.app_env.GlobRecursive(
"*",
self.app._appdir.Dir(self.app.fap_file_assets),
),
(assets_dir, self.app_env.GlobRecursive("*", assets_dir)),
)
# Always run the validator for the app's binary when building the app
@@ -344,25 +360,26 @@ def embed_app_metadata_emitter(target, source, env):
if app.apptype == FlipperAppType.PLUGIN:
target[0].name = target[0].name.replace(".fap", ".fal")
target.append(env.File(source[0].abspath + _FAP_META_SECTION))
app_work_dir = AppBuilder.get_app_work_dir(env, app)
app._section_fapmeta = app_work_dir.File(_FAP_META_SECTION)
target.append(app._section_fapmeta)
if app.fap_file_assets:
target.append(env.File(source[0].abspath + _FAP_FILEASSETS_SECTION))
# At this point, we haven't added dir with embedded plugins to _assets_dirs yet
if app._assets_dirs or app.embeds_plugins:
app._section_fapfileassets = app_work_dir.File(_FAP_FILEASSETS_SECTION)
target.append(app._section_fapfileassets)
return (target, source)
def prepare_app_files(target, source, env):
def prepare_app_file_assets(target, source, env):
files_section_node = next(
filter(lambda t: t.name.endswith(_FAP_FILEASSETS_SECTION), target)
)
app = env["APP"]
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 = FileBundler(
list(env.Dir(asset_dir).abspath for asset_dir in env["APP"]._assets_dirs)
)
bundler.export(files_section_node.abspath)
@@ -376,12 +393,14 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature):
objcopy_str = (
"${OBJCOPY} "
"--remove-section .ARM.attributes "
"--add-section ${_FAP_META_SECTION}=${SOURCE}${_FAP_META_SECTION} "
"--add-section ${_FAP_META_SECTION}=${APP._section_fapmeta} "
)
if app.fap_file_assets:
actions.append(Action(prepare_app_files, "$APPFILE_COMSTR"))
objcopy_str += "--add-section ${_FAP_FILEASSETS_SECTION}=${SOURCE}${_FAP_FILEASSETS_SECTION} "
if app._section_fapfileassets:
actions.append(Action(prepare_app_file_assets, "$APPFILE_COMSTR"))
objcopy_str += (
"--add-section ${_FAP_FILEASSETS_SECTION}=${APP._section_fapfileassets} "
)
objcopy_str += (
"--set-section-flags ${_FAP_META_SECTION}=contents,noload,readonly,data "
@@ -470,7 +489,7 @@ def AddAppBuildTarget(env, appname, build_target_name):
def generate(env, **kw):
env.SetDefault(
EXT_APPS_WORK_DIR="${FBT_FAP_DEBUG_ELF_ROOT}",
EXT_APPS_WORK_DIR=env.Dir(env["FBT_FAP_DEBUG_ELF_ROOT"]),
APP_RUN_SCRIPT="${FBT_SCRIPT_DIR}/runfap.py",
)
if not env["VERBOSE"]: