From 309f65e40167799fb11a259b12ffa4e62338508b Mon Sep 17 00:00:00 2001 From: hedger Date: Tue, 18 Jul 2023 13:39:30 +0400 Subject: [PATCH] [FL-3437] fbt: `build` target for faps (#2888) * fbt: added build target for faps. Usage: ./fbt build APPSRC= * Updated docs & vscode config * Code cleanup --- .vscode/example/tasks.json | 20 +++++-- .../examples/example_thermo/README.md | 2 +- documentation/AppsOnSDCard.md | 3 +- scripts/fbt/appmanifest.py | 5 +- scripts/fbt_tools/fbt_extapps.py | 55 ++++++++++++------- scripts/fbt_tools/fbt_help.py | 5 +- scripts/ufbt/SConstruct | 2 + site_scons/extapps.scons | 14 ++++- 8 files changed, 73 insertions(+), 33 deletions(-) diff --git a/.vscode/example/tasks.json b/.vscode/example/tasks.json index 28e67d45..3c01506a 100644 --- a/.vscode/example/tasks.json +++ b/.vscode/example/tasks.json @@ -4,13 +4,13 @@ "version": "2.0.0", "tasks": [ { - "label": "[Release] Build", + "label": "[Release] Build Firmware", "group": "build", "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0" }, { - "label": "[Debug] Build", + "label": "[Debug] Build Firmware", "group": "build", "type": "shell", "command": "./fbt" @@ -123,17 +123,29 @@ "type": "shell", "command": "./fbt COMPACT=1 DEBUG=0 fap_dist" }, + { + "label": "[Debug] Build App", + "group": "build", + "type": "shell", + "command": "./fbt build APPSRC=${relativeFileDirname}" + }, + { + "label": "[Release] Build App", + "group": "build", + "type": "shell", + "command": "./fbt COMPACT=1 DEBUG=0 build APPSRC=${relativeFileDirname}" + }, { "label": "[Debug] Launch App on Flipper", "group": "build", "type": "shell", - "command": "./fbt launch_app APPSRC=${relativeFileDirname}" + "command": "./fbt launch APPSRC=${relativeFileDirname}" }, { "label": "[Release] Launch App on Flipper", "group": "build", "type": "shell", - "command": "./fbt COMPACT=1 DEBUG=0 launch_app APPSRC=${relativeFileDirname}" + "command": "./fbt COMPACT=1 DEBUG=0 launch APPSRC=${relativeFileDirname}" }, { "label": "[Debug] Launch App on Flipper with Serial Console", diff --git a/applications/examples/example_thermo/README.md b/applications/examples/example_thermo/README.md index 08240a1f..d298de64 100644 --- a/applications/examples/example_thermo/README.md +++ b/applications/examples/example_thermo/README.md @@ -18,7 +18,7 @@ Before launching the application, connect the sensor to Flipper's external GPIO In order to launch this demo, follow the steps below: 1. Make sure your Flipper has an SD card installed. 2. Connect your Flipper to the computer via a USB cable. -3. Run `./fbt launch_app APPSRC=example_thermo` in your terminal emulator of choice. +3. Run `./fbt launch APPSRC=example_thermo` in your terminal emulator of choice. ## Changing the data pin It is possible to use other GPIO pin as a 1-Wire data pin. In order to change it, set the `THERMO_GPIO_PIN` macro to any of the options listed below: diff --git a/documentation/AppsOnSDCard.md b/documentation/AppsOnSDCard.md index 212df5b1..051fbb84 100644 --- a/documentation/AppsOnSDCard.md +++ b/documentation/AppsOnSDCard.md @@ -13,7 +13,8 @@ FAPs are created and developed the same way as internal applications that are pa To build your application as a FAP, create a folder with your app's source code in `applications_user`, then write its code the way you'd do when creating a regular built-in application. Then configure its `application.fam` manifest, and set its _apptype_ to FlipperAppType.EXTERNAL. See [Application Manifests](./AppManifests.md#application-definition) for more details. - To build your application, run `./fbt fap_{APPID}`, where APPID is your application's ID in its manifest. -- To build your app and upload it over USB to run on Flipper, use `./fbt launch_app APPSRC=applications_user/path/to/app`. This command is configured in the default [VS Code profile](../.vscode/ReadMe.md) as a "Launch App on Flipper" build action (Ctrl+Shift+B menu). +- To build your app and upload it over USB to run on Flipper, use `./fbt launch APPSRC=applications_user/path/to/app`. This command is configured in the default [VS Code profile](../.vscode/ReadMe.md) as a "Launch App on Flipper" build action (Ctrl+Shift+B menu). +- To build an app without uploading it to Flipper, use `./fbt build APPSRC=applications_user/path/to/app`. This command is also availabe in VSCode configuration as "Build App". - To build all FAPs, run `./fbt faps` or `./fbt fap_dist`. ## FAP assets diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index 0064b359..067b4a26 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -328,10 +328,7 @@ class AppBuildset: sdk_headers.extend( [ src._appdir.File(header) - for src in [ - app, - *(plugin for plugin in app._plugins), - ] + for src in [app, *app._plugins] for header in src.sdk_headers ] ) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index a6cd831d..1766d4c4 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -3,7 +3,7 @@ import os import pathlib import shutil from dataclasses import dataclass, field -from typing import Optional +from typing import Optional, Dict, List import SCons.Warnings from ansi.color import fg @@ -400,22 +400,26 @@ 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 = "" +@dataclass +class AppDeploymentComponents: + deploy_sources: Dict[str, object] = field(default_factory=dict) + validators: List[object] = field(default_factory=list) + extra_launch_args: str = "" - def _add_dist_targets(app_artifacts): - validators.append(app_artifacts.validator) + def add_app(self, app_artifacts): 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 + self.deploy_sources[f"/ext/{ext_path}"] = app_artifacts.compact + self.validators.append(app_artifacts.validator) + + +def _gather_app_components(env, appname) -> AppDeploymentComponents: + components = AppDeploymentComponents() 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) + components.add_app(artifacts_app_to_run) for plugin in host_app._plugins: - _add_dist_targets(env["EXT_APPS"].get(plugin.appid, None)) + components.add_app(env["EXT_APPS"].get(plugin.appid, None)) artifacts_app_to_run = env.GetExtAppByIdOrPath(appname) if artifacts_app_to_run.app.apptype == FlipperAppType.PLUGIN: @@ -427,25 +431,35 @@ def AddAppLaunchTarget(env, appname, launch_target_name): FlipperAppType.EXTERNAL, FlipperAppType.MENUEXTERNAL, ]: - _add_host_app_to_targets(host_app) + components.add_app(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) + components.add_app(artifacts_app_to_run) + components.extra_launch_args = f"-a {host_app.name}" else: raise UserError("Host app is unknown") else: _add_host_app_to_targets(artifacts_app_to_run.app) + return components - # print(deploy_sources, flipp_dist_paths) - env.PhonyTarget( + +def AddAppLaunchTarget(env, appname, launch_target_name): + components = _gather_app_components(env, appname) + target = env.PhonyTarget( launch_target_name, '${PYTHON3} "${APP_RUN_SCRIPT}" -p ${FLIP_PORT} ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}', - source=deploy_sources, - FLIPPER_FILE_TARGETS=flipp_dist_paths, - EXTRA_ARGS=run_script_extra_ars, + source=components.deploy_sources.values(), + FLIPPER_FILE_TARGETS=components.deploy_sources.keys(), + EXTRA_ARGS=components.extra_launch_args, ) - env.Alias(launch_target_name, validators) + env.Alias(launch_target_name, components.validators) + return target + + +def AddAppBuildTarget(env, appname, build_target_name): + components = _gather_app_components(env, appname) + env.Alias(build_target_name, components.validators) + env.Alias(build_target_name, components.deploy_sources.values()) def generate(env, **kw): @@ -474,6 +488,7 @@ def generate(env, **kw): env.AddMethod(BuildAppElf) env.AddMethod(GetExtAppByIdOrPath) env.AddMethod(AddAppLaunchTarget) + env.AddMethod(AddAppBuildTarget) env.Append( BUILDERS={ diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index c7452af9..68fc2aaf 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -4,15 +4,16 @@ targets_help = """Configuration variables: tail_help = """ TASKS: -Building: +Firmware & apps: firmware_all, fw_dist: Build firmware; create distribution package faps, fap_dist: Build all FAP apps - fap_{APPID}, launch_app APPSRC={APPID}: + fap_{APPID}, build APPSRC={APPID}; launch APPSRC={APPID}: Build FAP app with appid={APPID}; upload & start it over USB fap_deploy: Build and upload all FAP apps over USB + Flashing & debugging: flash, flash_blackmagic, jflash: diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 703a9187..9a9e0938 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -336,8 +336,10 @@ def ambiguous_app_call(**kw): if app_to_launch: appenv.AddAppLaunchTarget(app_to_launch, "launch") + appenv.AddAppBuildTarget(app_to_launch, "build") else: dist_env.PhonyTarget("launch", Action(ambiguous_app_call, None)) + dist_env.PhonyTarget("build", Action(ambiguous_app_call, None)) # cli handler diff --git a/site_scons/extapps.scons b/site_scons/extapps.scons index 0893c455..5c6f18d6 100644 --- a/site_scons/extapps.scons +++ b/site_scons/extapps.scons @@ -114,8 +114,20 @@ extapps.resources_dist = appenv.FapDist(appenv["RESOURCES_ROOT"], []) if appsrc := appenv.subst("$APPSRC"): - appenv.AddAppLaunchTarget(appsrc, "launch_app") + launch_target = appenv.AddAppLaunchTarget(appsrc, "launch") + Alias("launch_app", launch_target) + appenv.PhonyTarget( + "launch_app", + Action( + lambda **kw: warn( + WarningOnByDefault, + "The 'launch_app' target is deprecated. Use 'launch' instead.", + ), + None, + ), + ) + appenv.AddAppBuildTarget(appsrc, "build") # SDK management