unleashed-firmware/site_scons/extapps.scons
hedger 53435579b3
[FL-3097] fbt, faploader: minimal app module implementation (#2420)
* fbt, faploader: minimal app module implementation
* faploader, libs: moved API hashtable core to flipper_application
* example: compound api
* lib: flipper_application: naming fixes, doxygen comments
* fbt: changed `requires` manifest field behavior for app extensions
* examples: refactored plugin apps; faploader: changed new API naming; fbt: changed PLUGIN app type meaning
* loader: dropped support for debug apps & plugin menus
* moved applications/plugins -> applications/external
* Restored x bit on chiplist_convert.py
* git: fixed free-dap submodule path
* pvs: updated submodule paths
* examples: example_advanced_plugins.c: removed potential memory leak on errors
* examples: example_plugins: refined requires
* fbt: not deploying app modules for debug/sample apps; extra validation for .PLUGIN-type apps
* apps: removed cdefines for external apps
* fbt: moved ext app path definition
* fbt: reworked fap_dist handling; f18: synced api_symbols.csv
* fbt: removed resources_paths for extapps
* scripts: reworked storage
* scripts: reworked runfap.py & selfupdate.py to use new api
* wip: fal runner
* fbt: moved file packaging into separate module
* scripts: storage: fixes
* scripts: storage: minor fixes for new api
* fbt: changed internal artifact storage details for external apps
* scripts: storage: additional fixes and better error reporting; examples: using APP_DATA_PATH()
* fbt, scripts: reworked launch_app to deploy plugins; moved old runfap.py to distfap.py
* fbt: extra check for plugins descriptors
* fbt: additional checks in emitter
* fbt: better info message on SDK rebuild
* scripts: removed requirements.txt
* loader: removed remnants of plugins & debug menus
* post-review fixes
2023-03-14 23:29:28 +09:00

198 lines
5.4 KiB
Plaintext

from dataclasses import dataclass, field
from os.path import dirname
from SCons.Node import NodeList
from SCons.Warnings import warn, WarningOnByDefault
from SCons.Errors import UserError
Import("ENV")
from fbt.appmanifest import FlipperAppType
appenv = ENV["APPENV"] = ENV.Clone(
tools=[
"fbt_extapps",
"fbt_assets",
"fbt_sdk",
],
RESOURCES_ROOT=ENV.Dir("#/assets/resources"),
)
appenv.Replace(
LINKER_SCRIPT_PATH=appenv["APP_LINKER_SCRIPT_PATH"],
)
appenv.AppendUnique(
CCFLAGS=[
"-ggdb3",
"-mword-relocations",
"-mlong-calls",
"-fno-common",
"-nostdlib",
"-fvisibility=hidden",
],
LINKFLAGS=[
"-Ur",
"-Wl,-Ur",
# "-Wl,--orphan-handling=error",
"-Bsymbolic",
"-nostartfiles",
"-mlong-calls",
"-fno-common",
"-nostdlib",
"-Wl,--gc-sections",
"-Wl,--no-export-dynamic",
"-fvisibility=hidden",
"-Wl,-e${APP_ENTRY}",
"-Xlinker",
"-Map=${TARGET}.map",
"-specs=nano.specs",
"-specs=nosys.specs",
],
LIBS=[
"m",
"gcc",
"stdc++",
"supc++",
],
)
@dataclass
class FlipperExtAppBuildArtifacts:
application_map: dict = field(default_factory=dict)
resources_dist: NodeList = field(default_factory=NodeList)
sdk_tree: NodeList = field(default_factory=NodeList)
apps_to_build_as_faps = [
FlipperAppType.PLUGIN,
FlipperAppType.EXTERNAL,
FlipperAppType.DEBUG,
]
known_extapps = [
app
for apptype in apps_to_build_as_faps
for app in appenv["APPBUILD"].get_apps_of_type(apptype, True)
]
# Ugly access to global option
if extra_app_list := GetOption("extra_ext_apps"):
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
incompatible_apps = []
for app in known_extapps:
if not app.supports_hardware_target(appenv.subst("f${TARGET_HW}")):
incompatible_apps.append(app)
continue
appenv.BuildAppElf(app)
extapps = FlipperExtAppBuildArtifacts()
extapps.application_map = appenv["EXT_APPS"]
if incompatible_apps:
warn(
WarningOnByDefault,
f"Skipping build of {len(incompatible_apps)} incompatible app(s): "
+ ", ".join(f"'{app.name}' (id '{app.appid}')" for app in incompatible_apps),
)
if appenv["FORCE"]:
appenv.AlwaysBuild(
list(app_artifact.compact for app_artifact in extapps.application_map.values())
)
Alias(
"faps",
list(app_artifact.validator for app_artifact in extapps.application_map.values()),
)
extapps.resources_dist = appenv.FapDist(appenv["RESOURCES_ROOT"], [])
if appsrc := appenv.subst("$APPSRC"):
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 = appenv["EXT_APPS"].get(host_app.appid, None)
_add_dist_targets(artifacts_app_to_run)
for plugin in host_app._plugins:
_add_dist_targets(appenv["EXT_APPS"].get(plugin.appid, None))
artifacts_app_to_run = appenv.GetExtAppByIdOrPath(appsrc)
if artifacts_app_to_run.app.apptype == FlipperAppType.PLUGIN:
# We deploy host app instead
host_app = appenv["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)
appenv.PhonyTarget(
"launch_app",
'${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,
)
appenv.Alias("launch_app", validators)
# SDK management
sdk_origin_path = "${BUILD_DIR}/sdk_origin"
sdk_source = appenv.SDKPrebuilder(
sdk_origin_path,
# Deps on root SDK headers and generated files
(appenv["SDK_HEADERS"], appenv["FW_ASSETS_HEADERS"]),
)
# Extra deps on headers included in deeper levels
# Available on second and subsequent builds
Depends(sdk_source, appenv.ProcessSdkDepends(f"{sdk_origin_path}.d"))
appenv["SDK_DIR"] = appenv.Dir("${BUILD_DIR}/sdk")
sdk_tree = appenv.SDKTree(appenv["SDK_DIR"], sdk_origin_path)
# AlwaysBuild(sdk_tree)
Alias("sdk_tree", sdk_tree)
extapps.sdk_tree = sdk_tree
sdk_apicheck = appenv.SDKSymUpdater(appenv["SDK_DEFINITION"], sdk_origin_path)
Precious(sdk_apicheck)
NoClean(sdk_apicheck)
AlwaysBuild(sdk_apicheck)
Alias("sdk_check", sdk_apicheck)
sdk_apisyms = appenv.SDKSymGenerator(
"${BUILD_DIR}/assets/compiled/symbols.h", appenv["SDK_DEFINITION"]
)
Alias("api_syms", sdk_apisyms)
ENV.Replace(
SDK_APISYMS=sdk_apisyms,
_APP_ICONS=appenv["_APP_ICONS"],
)
if appenv["FORCE"]:
appenv.AlwaysBuild(sdk_source, sdk_tree, sdk_apicheck, sdk_apisyms)
Return("extapps")