From 98d5718ec9e39824745a2ca364f4d06a5a05c828 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 15 Nov 2023 20:27:35 +0400 Subject: [PATCH] fbt: improvements (#3217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fbt: changed cdefines & lib handling for external apps; added extra checks for app manifest fields; moved around AppsC generator * fbt: commandline fixes for spaces in paths * fbt: fixed stringification for FAP_VERSION * fbt: Removed excessive quoting for gdb * docs: update for cdefines; fbt: typo fix * fbt: enforcing at least 2 components in app version= Co-authored-by: あく --- SConstruct | 36 +++-- applications/debug/accessor/application.fam | 1 - .../debug/battery_test_app/application.fam | 1 - applications/debug/blink_test/application.fam | 1 - applications/debug/ccid_test/application.fam | 1 - applications/debug/crash_test/application.fam | 1 - .../debug/display_test/application.fam | 1 - .../debug/file_browser_test/application.fam | 1 - .../debug/keypad_test/application.fam | 1 - .../debug/locale_test/application.fam | 1 - .../debug/text_box_test/application.fam | 1 - applications/debug/uart_echo/application.fam | 1 - applications/debug/usb_mouse/application.fam | 1 - applications/debug/usb_test/application.fam | 1 - applications/debug/vibro_test/application.fam | 1 - documentation/AppManifests.md | 2 +- firmware.scons | 4 +- scripts/fbt/appmanifest.py | 129 ++++-------------- scripts/fbt_tools/fbt_apps.py | 103 +++++++++++++- scripts/fbt_tools/fbt_extapps.py | 21 ++- scripts/fbt_tools/fbt_sdk.py | 15 +- scripts/fbt_tools/fbt_version.py | 20 ++- scripts/fbt_tools/fwbin.py | 19 ++- scripts/fbt_tools/jflash.py | 13 +- scripts/fbt_tools/objdump.py | 3 +- scripts/fbt_tools/openocd.py | 1 + scripts/fbt_tools/pvsstudio.py | 24 +++- scripts/fbt_tools/strip.py | 3 +- scripts/ufbt/SConstruct | 24 +++- scripts/version.py | 2 +- site_scons/environ.scons | 4 +- 31 files changed, 271 insertions(+), 166 deletions(-) diff --git a/SConstruct b/SConstruct index 97d7e5e5e..a2c5cd9e7 100644 --- a/SConstruct +++ b/SConstruct @@ -172,17 +172,19 @@ Alias("fap_dist", fap_dist) fap_deploy = distenv.PhonyTarget( "fap_deploy", - [ + Action( [ - "${PYTHON3}", - "${FBT_SCRIPT_DIR}/storage.py", - "-p", - "${FLIP_PORT}", - "send", - "${SOURCE}", - "/ext/apps", + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/apps", + ] ] - ], + ), source=firmware_env.Dir(("${RESOURCES_ROOT}/apps")), ) Depends(fap_deploy, firmware_env["FW_RESOURCES_MANIFEST"]) @@ -261,7 +263,7 @@ distenv.PhonyTarget( distenv.PhonyTarget( "debug_other_blackmagic", "${GDBPYCOM}", - GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", + GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", GDBREMOTE="${BLACKMAGIC_ADDR}", GDBPYOPTS=debug_other_opts, ) @@ -276,13 +278,13 @@ distenv.PhonyTarget( # Linter distenv.PhonyTarget( "lint", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]], LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]], ) distenv.PhonyTarget( "format", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]], LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]], ) @@ -323,10 +325,14 @@ distenv.PhonyTarget( ) # Start Flipper CLI via PySerial's miniterm -distenv.PhonyTarget("cli", "${PYTHON3} ${FBT_SCRIPT_DIR}/serial_cli.py -p ${FLIP_PORT}") +distenv.PhonyTarget( + "cli", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]] +) # Update WiFi devboard firmware -distenv.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py") +distenv.PhonyTarget( + "devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]] +) # Find blackmagic probe @@ -361,5 +367,5 @@ distenv.Alias("vscode_dist", vscode_dist) # Configure shell with build tools distenv.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", + "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) diff --git a/applications/debug/accessor/application.fam b/applications/debug/accessor/application.fam index 6b8472711..65a6c8666 100644 --- a/applications/debug/accessor/application.fam +++ b/applications/debug/accessor/application.fam @@ -4,7 +4,6 @@ App( apptype=FlipperAppType.DEBUG, targets=["f7"], entry_point="accessor_app", - cdefines=["APP_ACCESSOR"], requires=["gui"], stack_size=4 * 1024, order=40, diff --git a/applications/debug/battery_test_app/application.fam b/applications/debug/battery_test_app/application.fam index f97d10279..5f4acd83d 100644 --- a/applications/debug/battery_test_app/application.fam +++ b/applications/debug/battery_test_app/application.fam @@ -3,7 +3,6 @@ App( name="Battery Test", apptype=FlipperAppType.DEBUG, entry_point="battery_test_app", - cdefines=["APP_BATTERY_TEST"], requires=[ "gui", "power", diff --git a/applications/debug/blink_test/application.fam b/applications/debug/blink_test/application.fam index c6a8a922a..d7d873fb9 100644 --- a/applications/debug/blink_test/application.fam +++ b/applications/debug/blink_test/application.fam @@ -3,7 +3,6 @@ App( name="Blink Test", apptype=FlipperAppType.DEBUG, entry_point="blink_test_app", - cdefines=["APP_BLINK"], requires=["gui"], stack_size=1 * 1024, order=10, diff --git a/applications/debug/ccid_test/application.fam b/applications/debug/ccid_test/application.fam index e0cbc8d85..ad9076770 100644 --- a/applications/debug/ccid_test/application.fam +++ b/applications/debug/ccid_test/application.fam @@ -3,7 +3,6 @@ App( name="CCID Debug", apptype=FlipperAppType.DEBUG, entry_point="ccid_test_app", - cdefines=["CCID_TEST"], requires=[ "gui", ], diff --git a/applications/debug/crash_test/application.fam b/applications/debug/crash_test/application.fam index 55f62f86d..357efe667 100644 --- a/applications/debug/crash_test/application.fam +++ b/applications/debug/crash_test/application.fam @@ -3,7 +3,6 @@ App( name="Crash Test", apptype=FlipperAppType.DEBUG, entry_point="crash_test_app", - cdefines=["APP_CRASH_TEST"], requires=["gui"], stack_size=1 * 1024, fap_category="Debug", diff --git a/applications/debug/display_test/application.fam b/applications/debug/display_test/application.fam index e8a00d2ae..6a2d9c20c 100644 --- a/applications/debug/display_test/application.fam +++ b/applications/debug/display_test/application.fam @@ -3,7 +3,6 @@ App( name="Display Test", apptype=FlipperAppType.DEBUG, entry_point="display_test_app", - cdefines=["APP_DISPLAY_TEST"], requires=["gui"], fap_libs=["misc"], stack_size=1 * 1024, diff --git a/applications/debug/file_browser_test/application.fam b/applications/debug/file_browser_test/application.fam index 4a401a649..bb08ad2c5 100644 --- a/applications/debug/file_browser_test/application.fam +++ b/applications/debug/file_browser_test/application.fam @@ -3,7 +3,6 @@ App( name="File Browser Test", apptype=FlipperAppType.DEBUG, entry_point="file_browser_app", - cdefines=["APP_FILE_BROWSER_TEST"], requires=["gui"], stack_size=2 * 1024, order=150, diff --git a/applications/debug/keypad_test/application.fam b/applications/debug/keypad_test/application.fam index 6859af26f..90851950b 100644 --- a/applications/debug/keypad_test/application.fam +++ b/applications/debug/keypad_test/application.fam @@ -3,7 +3,6 @@ App( name="Keypad Test", apptype=FlipperAppType.DEBUG, entry_point="keypad_test_app", - cdefines=["APP_KEYPAD_TEST"], requires=["gui"], stack_size=1 * 1024, order=30, diff --git a/applications/debug/locale_test/application.fam b/applications/debug/locale_test/application.fam index e46eeff51..d341122f9 100644 --- a/applications/debug/locale_test/application.fam +++ b/applications/debug/locale_test/application.fam @@ -3,7 +3,6 @@ App( name="Locale Test", apptype=FlipperAppType.DEBUG, entry_point="locale_test_app", - cdefines=["APP_LOCALE"], requires=["gui", "locale"], stack_size=2 * 1024, order=70, diff --git a/applications/debug/text_box_test/application.fam b/applications/debug/text_box_test/application.fam index 3e54df9cc..823c21d06 100644 --- a/applications/debug/text_box_test/application.fam +++ b/applications/debug/text_box_test/application.fam @@ -3,7 +3,6 @@ App( name="Text Box Test", apptype=FlipperAppType.DEBUG, entry_point="text_box_test_app", - cdefines=["APP_TEXT_BOX_TEST"], requires=["gui"], stack_size=1 * 1024, order=140, diff --git a/applications/debug/uart_echo/application.fam b/applications/debug/uart_echo/application.fam index 8863a1a94..7b030bcfa 100644 --- a/applications/debug/uart_echo/application.fam +++ b/applications/debug/uart_echo/application.fam @@ -3,7 +3,6 @@ App( name="UART Echo", apptype=FlipperAppType.DEBUG, entry_point="uart_echo_app", - cdefines=["APP_UART_ECHO"], requires=["gui"], stack_size=2 * 1024, order=70, diff --git a/applications/debug/usb_mouse/application.fam b/applications/debug/usb_mouse/application.fam index 5c4340045..7747613d5 100644 --- a/applications/debug/usb_mouse/application.fam +++ b/applications/debug/usb_mouse/application.fam @@ -3,7 +3,6 @@ App( name="USB Mouse Demo", apptype=FlipperAppType.DEBUG, entry_point="usb_mouse_app", - cdefines=["APP_USB_MOUSE"], requires=["gui"], stack_size=1 * 1024, order=60, diff --git a/applications/debug/usb_test/application.fam b/applications/debug/usb_test/application.fam index 27395c34d..463bb4a26 100644 --- a/applications/debug/usb_test/application.fam +++ b/applications/debug/usb_test/application.fam @@ -3,7 +3,6 @@ App( name="USB Test", apptype=FlipperAppType.DEBUG, entry_point="usb_test_app", - cdefines=["APP_USB_TEST"], requires=["gui"], stack_size=1 * 1024, order=50, diff --git a/applications/debug/vibro_test/application.fam b/applications/debug/vibro_test/application.fam index f7115cc96..c35a7223f 100644 --- a/applications/debug/vibro_test/application.fam +++ b/applications/debug/vibro_test/application.fam @@ -3,7 +3,6 @@ App( name="Vibro Test", apptype=FlipperAppType.DEBUG, entry_point="vibro_test_app", - cdefines=["APP_VIBRO_TEST"], requires=["gui"], stack_size=1 * 1024, order=20, diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index d190a798b..9afdccb0e 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -32,7 +32,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt - **name**: name displayed in menus. - **entry_point**: C function to be used as the application's entry point. Note that C++ function names are mangled, so you need to wrap them in `extern "C"` to use them as entry points. - **flags**: internal flags for system apps. Do not use. -- **cdefines**: C preprocessor definitions to declare globally for other apps when the current application is included in the active build configuration. +- **cdefines**: C preprocessor definitions to declare globally for other apps when the current application is included in the active build configuration. **For external applications**: specified definitions are used when building the application itself. - **requires**: list of application IDs to include in the build configuration when the current application is referenced in the list of applications to build. - **conflicts**: list of application IDs with which the current application conflicts. If any of them is found in the constructed application list, **`fbt`** will abort the firmware build process. - **provides**: functionally identical to **_requires_** field. diff --git a/firmware.scons b/firmware.scons index eca6afc4c..004def9a9 100644 --- a/firmware.scons +++ b/firmware.scons @@ -219,7 +219,7 @@ AddPostAction(fwelf, fwenv["APPBUILD_DUMP"]) AddPostAction( fwelf, Action( - '${PYTHON3} "${BIN_SIZE_SCRIPT}" elf ${TARGET}', + [["${PYTHON3}", "${BIN_SIZE_SCRIPT}", "elf", "${TARGET}"]], "Firmware size", ), ) @@ -229,7 +229,7 @@ fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}") fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}") AddPostAction( fwbin, - Action('@${PYTHON3} "${BIN_SIZE_SCRIPT}" bin ${TARGET}'), + Action([["@${PYTHON3}", "${BIN_SIZE_SCRIPT}", "bin", "${TARGET}"]]), ) fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}") diff --git a/scripts/fbt/appmanifest.py b/scripts/fbt/appmanifest.py index bef4eb02b..d32869b10 100644 --- a/scripts/fbt/appmanifest.py +++ b/scripts/fbt/appmanifest.py @@ -33,6 +33,8 @@ class FlipperAppType(Enum): @dataclass class FlipperApplication: APP_ID_REGEX: ClassVar[re.Pattern] = re.compile(r"^[a-z0-9_]+$") + PRIVATE_FIELD_PREFIX: ClassVar[str] = "_" + APP_MANIFEST_DEFAULT_NAME: ClassVar[str] = "application.fam" @dataclass class ExternallyBuiltFile: @@ -48,8 +50,6 @@ class FlipperApplication: cdefines: List[str] = field(default_factory=list) cincludes: List[str] = field(default_factory=list) - PRIVATE_FIELD_PREFIX = "_" - appid: str apptype: FlipperAppType name: Optional[str] = "" @@ -117,8 +117,10 @@ class FlipperApplication: self.fap_version = tuple(int(v) for v in self.fap_version.split(".")) except ValueError: raise FlipperManifestException( - f"Invalid version string '{self.fap_version}'. Must be in the form 'major.minor'" + f"Invalid version '{self.fap_version}'. Must be in the form 'major.minor'" ) + if len(self.fap_version) < 2: + raise ValueError("Not enough version components") class AppManager: @@ -155,11 +157,20 @@ class AppManager: raise FlipperManifestException( f"App {kw.get('appid')} cannot have fal_embedded set" ) - # Harmless - cdefines for external apps are meaningless - # if apptype == FlipperAppType.EXTERNAL and kw.get("cdefines"): - # raise FlipperManifestException( - # f"External app {kw.get('appid')} must not have 'cdefines' in manifest" - # ) + + if apptype in AppBuildset.dist_app_types: + # For distributing .fap's resources, there's "fap_file_assets" + for app_property in ("resources",): + if kw.get(app_property): + raise FlipperManifestException( + f"App {kw.get('appid')} of type {apptype} cannot have '{app_property}' in manifest" + ) + else: + for app_property in ("fap_extbuild", "fap_private_libs", "fap_icon_assets"): + if kw.get(app_property): + raise FlipperManifestException( + f"App {kw.get('appid')} of type {apptype} must not have '{app_property}' in manifest" + ) def load_manifest(self, app_manifest_path: str, app_dir_node: object): if not os.path.exists(app_manifest_path): @@ -241,12 +252,21 @@ class AppBuildset: FlipperAppType.STARTUP, ) EXTERNAL_APP_TYPES_MAP = { + # AppType -> bool: true if always deploy, false if obey app set FlipperAppType.EXTERNAL: True, FlipperAppType.PLUGIN: True, FlipperAppType.DEBUG: True, FlipperAppType.MENUEXTERNAL: False, } + @classmethod + @property + def dist_app_types(cls): + """Applications that are installed on SD card""" + return list( + entry[0] for entry in cls.EXTERNAL_APP_TYPES_MAP.items() if entry[1] + ) + @staticmethod def print_writer(message): print(message) @@ -432,96 +452,3 @@ class AppBuildset: for source_type in app.sources ) ) - - -class ApplicationsCGenerator: - APP_TYPE_MAP = { - FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), - FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), - FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), - FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), - FlipperAppType.SETTINGS: ( - "FlipperInternalApplication", - "FLIPPER_SETTINGS_APPS", - ), - FlipperAppType.STARTUP: ( - "FlipperInternalOnStartHook", - "FLIPPER_ON_SYSTEM_START", - ), - } - - APP_EXTERNAL_TYPE = ( - "FlipperExternalApplication", - "FLIPPER_EXTERNAL_APPS", - ) - - def __init__(self, buildset: AppBuildset, autorun_app: str = ""): - self.buildset = buildset - self.autorun = autorun_app - - def get_app_ep_forward(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return f"extern void {app.entry_point}();" - return f"extern int32_t {app.entry_point}(void* p);" - - def get_app_descr(self, app: FlipperApplication): - if app.apptype == FlipperAppType.STARTUP: - return app.entry_point - return f""" - {{.app = {app.entry_point}, - .name = "{app.name}", - .appid = "{app.appid}", - .stack_size = {app.stack_size}, - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" - - def get_external_app_descr(self, app: FlipperApplication): - app_path = "/ext/apps" - if app.fap_category: - app_path += f"/{app.fap_category}" - app_path += f"/{app.appid}.fap" - return f""" - {{ - .name = "{app.name}", - .icon = {f"&{app.icon}" if app.icon else "NULL"}, - .path = "{app_path}" }}""" - - def generate(self): - contents = [ - '#include "applications.h"', - "#include ", - f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', - ] - for apptype in self.APP_TYPE_MAP: - contents.extend( - map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) - ) - entry_type, entry_block = self.APP_TYPE_MAP[apptype] - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append( - ",\n".join( - map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) - ) - ) - contents.append("};") - contents.append( - f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" - ) - - archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) - if archive_app: - contents.extend( - [ - self.get_app_ep_forward(archive_app[0]), - f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", - ] - ) - - entry_type, entry_block = self.APP_EXTERNAL_TYPE - external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) - contents.append(f"const {entry_type} {entry_block}[] = {{") - contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) - contents.append("};") - contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") - - return "\n".join(contents) diff --git a/scripts/fbt_tools/fbt_apps.py b/scripts/fbt_tools/fbt_apps.py index edce194f0..dadf6dc0c 100644 --- a/scripts/fbt_tools/fbt_apps.py +++ b/scripts/fbt_tools/fbt_apps.py @@ -1,25 +1,118 @@ from ansi.color import fg from fbt.appmanifest import ( - ApplicationsCGenerator, AppManager, + AppBuildset, + FlipperApplication, FlipperAppType, FlipperManifestException, ) from SCons.Action import Action from SCons.Builder import Builder from SCons.Errors import StopError -from SCons.Warnings import WarningOnByDefault, warn from SCons.Script import GetOption +from SCons.Warnings import WarningOnByDefault, warn # Adding objects for application management to env # AppManager env["APPMGR"] - loads all manifests; manages list of known apps # AppBuildset env["APPBUILD"] - contains subset of apps, filtered for current config +class ApplicationsCGenerator: + APP_TYPE_MAP = { + FlipperAppType.SERVICE: ("FlipperInternalApplication", "FLIPPER_SERVICES"), + FlipperAppType.SYSTEM: ("FlipperInternalApplication", "FLIPPER_SYSTEM_APPS"), + FlipperAppType.APP: ("FlipperInternalApplication", "FLIPPER_APPS"), + FlipperAppType.DEBUG: ("FlipperInternalApplication", "FLIPPER_DEBUG_APPS"), + FlipperAppType.SETTINGS: ( + "FlipperInternalApplication", + "FLIPPER_SETTINGS_APPS", + ), + FlipperAppType.STARTUP: ( + "FlipperInternalOnStartHook", + "FLIPPER_ON_SYSTEM_START", + ), + } + + APP_EXTERNAL_TYPE = ( + "FlipperExternalApplication", + "FLIPPER_EXTERNAL_APPS", + ) + + def __init__(self, buildset: AppBuildset, autorun_app: str = ""): + self.buildset = buildset + self.autorun = autorun_app + + def get_app_ep_forward(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return f"extern void {app.entry_point}();" + return f"extern int32_t {app.entry_point}(void* p);" + + def get_app_descr(self, app: FlipperApplication): + if app.apptype == FlipperAppType.STARTUP: + return app.entry_point + return f""" + {{.app = {app.entry_point}, + .name = "{app.name}", + .appid = "{app.appid}", + .stack_size = {app.stack_size}, + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .flags = {'|'.join(f"FlipperInternalApplicationFlag{flag}" for flag in app.flags)} }}""" + + def get_external_app_descr(self, app: FlipperApplication): + app_path = "/ext/apps" + if app.fap_category: + app_path += f"/{app.fap_category}" + app_path += f"/{app.appid}.fap" + return f""" + {{ + .name = "{app.name}", + .icon = {f"&{app.icon}" if app.icon else "NULL"}, + .path = "{app_path}" }}""" + + def generate(self): + contents = [ + '#include "applications.h"', + "#include ", + f'const char* FLIPPER_AUTORUN_APP_NAME = "{self.autorun}";', + ] + for apptype in self.APP_TYPE_MAP: + contents.extend( + map(self.get_app_ep_forward, self.buildset.get_apps_of_type(apptype)) + ) + entry_type, entry_block = self.APP_TYPE_MAP[apptype] + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append( + ",\n".join( + map(self.get_app_descr, self.buildset.get_apps_of_type(apptype)) + ) + ) + contents.append("};") + contents.append( + f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});" + ) + + archive_app = self.buildset.get_apps_of_type(FlipperAppType.ARCHIVE) + if archive_app: + contents.extend( + [ + self.get_app_ep_forward(archive_app[0]), + f"const FlipperInternalApplication FLIPPER_ARCHIVE = {self.get_app_descr(archive_app[0])};", + ] + ) + + entry_type, entry_block = self.APP_EXTERNAL_TYPE + external_apps = self.buildset.get_apps_of_type(FlipperAppType.MENUEXTERNAL) + contents.append(f"const {entry_type} {entry_block}[] = {{") + contents.append(",\n".join(map(self.get_external_app_descr, external_apps))) + contents.append("};") + contents.append(f"const size_t {entry_block}_COUNT = COUNT_OF({entry_block});") + + return "\n".join(contents) + + def LoadAppManifest(env, entry): try: - APP_MANIFEST_NAME = "application.fam" - manifest_glob = entry.glob(APP_MANIFEST_NAME) + manifest_glob = entry.glob(FlipperApplication.APP_MANIFEST_DEFAULT_NAME) if len(manifest_glob) == 0: try: disk_node = next(filter(lambda d: d.exists(), entry.get_all_rdirs())) @@ -27,7 +120,7 @@ def LoadAppManifest(env, entry): disk_node = entry raise FlipperManifestException( - f"App folder '{disk_node.abspath}': missing manifest ({APP_MANIFEST_NAME})" + f"App folder '{disk_node.abspath}': missing manifest ({FlipperApplication.APP_MANIFEST_DEFAULT_NAME})" ) app_manifest_file_path = manifest_glob[0].rfile().abspath diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index b88fa7929..a7914c4f8 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -58,7 +58,8 @@ class AppBuilder: ) self.app_env.Append( CPPDEFINES=[ - ("FAP_VERSION", f'"{".".join(map(str, self.app.fap_version))}"') + ("FAP_VERSION", f'\\"{".".join(map(str, self.app.fap_version))}\\"'), + *self.app.cdefines, ], ) self.app_env.VariantDir(self.app_work_dir, self.app._appdir, duplicate=False) @@ -143,8 +144,8 @@ class AppBuilder: 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_work_dir, self.app._appdir], + LIBS=[*self.app.fap_libs, *self.private_libs, *self.app.fap_libs], + CPPPATH=[self.app_env.Dir(self.app_work_dir), self.app._appdir], ) app_sources = self.app_env.GatherSources( @@ -472,7 +473,19 @@ 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}', + [ + [ + "${PYTHON3}", + "${APP_RUN_SCRIPT}", + "-p", + "${FLIP_PORT}", + "${EXTRA_ARGS}", + "-s", + "${SOURCES}", + "-t", + "${FLIPPER_FILE_TARGETS}", + ] + ], source=components.deploy_sources.values(), FLIPPER_FILE_TARGETS=components.deploy_sources.keys(), EXTRA_ARGS=components.extra_launch_args, diff --git a/scripts/fbt_tools/fbt_sdk.py b/scripts/fbt_tools/fbt_sdk.py index 6350f14b8..17acc8cf1 100644 --- a/scripts/fbt_tools/fbt_sdk.py +++ b/scripts/fbt_tools/fbt_sdk.py @@ -285,7 +285,20 @@ def generate(env, **kw): "$SDK_AMALGAMATE_HEADER_COMSTR", ), Action( - "$CC -o $TARGET -E -P $CCFLAGS $_CCCOMCOM $SDK_PP_FLAGS -MMD ${TARGET}.c", + [ + [ + "$CC", + "-o", + "$TARGET", + "-E", + "-P", + "$CCFLAGS", + "$_CCCOMCOM", + "$SDK_PP_FLAGS", + "-MMD", + "${TARGET}.c", + ] + ], "$SDK_AMALGAMATE_PP_COMSTR", ), ], diff --git a/scripts/fbt_tools/fbt_version.py b/scripts/fbt_tools/fbt_version.py index f1a782523..e64167b3d 100644 --- a/scripts/fbt_tools/fbt_version.py +++ b/scripts/fbt_tools/fbt_version.py @@ -19,10 +19,22 @@ def generate(env): BUILDERS={ "VersionBuilder": Builder( action=Action( - '${PYTHON3} "${VERSION_SCRIPT}" generate ' - "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " - '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', - "${VERSIONCOMSTR}", + [ + [ + "${PYTHON3}", + "${VERSION_SCRIPT}", + "generate", + "-t", + "${TARGET_HW}", + "--fw-origin", + "${FIRMWARE_ORIGIN}", + "-o", + "${TARGET.dir.posix}", + "--dir", + "${ROOT_DIR}", + "${VERSIONCOMSTR}", + ] + ] ), emitter=_version_emitter, ), diff --git a/scripts/fbt_tools/fwbin.py b/scripts/fbt_tools/fwbin.py index 06a435b6d..860f83b1b 100644 --- a/scripts/fbt_tools/fwbin.py +++ b/scripts/fbt_tools/fwbin.py @@ -25,7 +25,7 @@ def generate(env): BUILDERS={ "HEXBuilder": Builder( action=Action( - '${OBJCOPY} -O ihex "${SOURCE}" "${TARGET}"', + [["${OBJCOPY}", "-O", "ihex", "${SOURCE}", "${TARGET}"]], "${HEXCOMSTR}", ), suffix=".hex", @@ -33,7 +33,7 @@ def generate(env): ), "BINBuilder": Builder( action=Action( - '${OBJCOPY} -O binary -S "${SOURCE}" "${TARGET}"', + [["${OBJCOPY}", "-O", "binary", "-S", "${SOURCE}", "${TARGET}"]], "${BINCOMSTR}", ), suffix=".bin", @@ -41,7 +41,20 @@ def generate(env): ), "DFUBuilder": Builder( action=Action( - '${PYTHON3} "${BIN2DFU}" -i "${SOURCE}" -o "${TARGET}" -a ${IMAGE_BASE_ADDRESS} -l "Flipper Zero F${TARGET_HW}"', + [ + [ + "${PYTHON3}", + "${BIN2DFU}", + "-i", + "${SOURCE}", + "-o", + "${TARGET}", + "-a", + "${IMAGE_BASE_ADDRESS}", + "-l", + "Flipper Zero F${TARGET_HW}", + ] + ], "${DFUCOMSTR}", ), suffix=".dfu", diff --git a/scripts/fbt_tools/jflash.py b/scripts/fbt_tools/jflash.py index aea7279b6..5eb9f2c19 100644 --- a/scripts/fbt_tools/jflash.py +++ b/scripts/fbt_tools/jflash.py @@ -1,5 +1,6 @@ from SCons.Builder import Builder from SCons.Defaults import Touch +from SCons.Action import Action def generate(env): @@ -9,13 +10,21 @@ def generate(env): "-auto", "-exit", ], - JFLASHCOM="${JFLASH} -openprj${JFLASHPROJECT} -open${SOURCE},${JFLASHADDR} ${JFLASHFLAGS}", ) env.Append( BUILDERS={ "JFlash": Builder( action=[ - "${JFLASHCOM}", + Action( + [ + [ + "${JFLASH}", + "-openprj${JFLASHPROJECT}", + "-open${SOURCE},${JFLASHADDR}", + "${JFLASHFLAGS}", + ] + ] + ), Touch("${TARGET}"), ], ), diff --git a/scripts/fbt_tools/objdump.py b/scripts/fbt_tools/objdump.py index 31f817648..e3dbc6d87 100644 --- a/scripts/fbt_tools/objdump.py +++ b/scripts/fbt_tools/objdump.py @@ -6,13 +6,12 @@ def generate(env): env.SetDefault( OBJDUMP="objdump", OBJDUMPFLAGS=[], - OBJDUMPCOM="$OBJDUMP $OBJDUMPFLAGS -S $SOURCES > $TARGET", ) env.Append( BUILDERS={ "ObjDump": Builder( action=Action( - "${OBJDUMPCOM}", + [["$OBJDUMP", "$OBJDUMPFLAGS", "-S", "$SOURCES", ">", "$TARGET"]], "${OBJDUMPCOMSTR}", ), suffix=".lst", diff --git a/scripts/fbt_tools/openocd.py b/scripts/fbt_tools/openocd.py index 157d798f4..596f5f8a6 100644 --- a/scripts/fbt_tools/openocd.py +++ b/scripts/fbt_tools/openocd.py @@ -5,6 +5,7 @@ from SCons.Defaults import Touch __OPENOCD_BIN = "openocd" +# TODO: FL-3663: rework argument passing to lists _oocd_action = Action( "${OPENOCD} ${OPENOCD_OPTS} ${OPENOCD_COMMAND}", "${OPENOCDCOMSTR}", diff --git a/scripts/fbt_tools/pvsstudio.py b/scripts/fbt_tools/pvsstudio.py index f43db126e..ecf9d4b06 100644 --- a/scripts/fbt_tools/pvsstudio.py +++ b/scripts/fbt_tools/pvsstudio.py @@ -79,7 +79,17 @@ def generate(env): BUILDERS={ "PVSCheck": Builder( action=Action( - '${PVSCHECKBIN} analyze ${PVSOPTIONS} -f "${SOURCE}" -o "${TARGET}"', + [ + [ + "${PVSCHECKBIN}", + "analyze", + "${PVSOPTIONS}", + "-f", + "${SOURCE}", + "-o", + "${TARGET}", + ] + ], "${PVSCHECKCOMSTR}", ), suffix=".log", @@ -92,7 +102,17 @@ def generate(env): # PlogConverter.exe and plog-converter have different behavior Mkdir("${TARGET.dir}") if env["PLATFORM"] == "win32" else None, Action(_set_browser_action, None), - '${PVSCONVBIN} ${PVSCONVOPTIONS} "${SOURCE}" -o "${REPORT_DIR}"', + Action( + [ + [ + "${PVSCONVBIN}", + "${PVSCONVOPTIONS}", + "${SOURCE}", + "-o", + "${REPORT_DIR}", + ] + ] + ), ], "${PVSCONVCOMSTR}", ), diff --git a/scripts/fbt_tools/strip.py b/scripts/fbt_tools/strip.py index ee14fc185..39f3a620c 100644 --- a/scripts/fbt_tools/strip.py +++ b/scripts/fbt_tools/strip.py @@ -6,13 +6,12 @@ def generate(env): env.SetDefault( STRIP="strip", STRIPFLAGS=[], - STRIPCOM="$STRIP $STRIPFLAGS $SOURCES -o $TARGET", ) env.Append( BUILDERS={ "ELFStripper": Builder( action=Action( - "${STRIPCOM}", + [["$STRIP", "$STRIPFLAGS", "$SOURCES", "-o", "$TARGET"]], "${STRIPCOMSTR}", ), suffix=".elf", diff --git a/scripts/ufbt/SConstruct b/scripts/ufbt/SConstruct index 98e6b638f..46d663578 100644 --- a/scripts/ufbt/SConstruct +++ b/scripts/ufbt/SConstruct @@ -325,24 +325,26 @@ else: appenv.PhonyTarget( "cli", - '${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py" -p ${FLIP_PORT}', + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/serial_cli.py", "-p", "${FLIP_PORT}"]], ) # Update WiFi devboard firmware -dist_env.PhonyTarget("devboard_flash", "${PYTHON3} ${FBT_SCRIPT_DIR}/wifi_board.py") +dist_env.PhonyTarget( + "devboard_flash", [["${PYTHON3}", "${FBT_SCRIPT_DIR}/wifi_board.py"]] +) # Linter dist_env.PhonyTarget( "lint", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "check", "${LINT_SOURCES}"]], source=original_app_dir.File(".clang-format"), LINT_SOURCES=[original_app_dir], ) dist_env.PhonyTarget( "format", - "${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}", + [["${PYTHON3}", "${FBT_SCRIPT_DIR}/lint.py", "format", "${LINT_SOURCES}"]], source=original_app_dir.File(".clang-format"), LINT_SOURCES=[original_app_dir], ) @@ -455,7 +457,17 @@ if dolphin_src_dir.exists(): ) dist_env.PhonyTarget( "dolphin_ext", - '${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py -p ${FLIP_PORT} send "${SOURCE}" /ext/dolphin', + [ + [ + "${PYTHON3}", + "${FBT_SCRIPT_DIR}/storage.py", + "-p", + "${FLIP_PORT}", + "send", + "${SOURCE}", + "/ext/dolphin", + ] + ], source=ufbt_build_dir.Dir("dolphin"), ) else: @@ -467,7 +479,7 @@ else: dist_env.PhonyTarget( "env", - "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", + "@echo $( ${FBT_SCRIPT_DIR.abspath}/toolchain/fbtenv.sh $)", ) dist_env.PostConfigureUfbtEnvionment() diff --git a/scripts/version.py b/scripts/version.py index 4b1c739bc..98b1b7e85 100755 --- a/scripts/version.py +++ b/scripts/version.py @@ -101,7 +101,7 @@ class Main(App): required=True, ) self.parser_generate.add_argument( - "-fw-origin", + "--fw-origin", dest="firmware_origin", type=str, help="firmware origin", diff --git a/site_scons/environ.scons b/site_scons/environ.scons index b638b1018..74762cb15 100644 --- a/site_scons/environ.scons +++ b/site_scons/environ.scons @@ -27,6 +27,8 @@ variables_to_forward = [ "PYTHONNOUSERSITE", "TMP", "TEMP", + # ccache + "CCACHE_DISABLE", # Colors for tools "TERM", ] @@ -62,7 +64,7 @@ coreenv = VAR_ENV.Clone( # Setting up temp file parameters - to overcome command line length limits TEMPFILEARGESCFUNC=tempfile_arg_esc_func, ROOT_DIR=Dir("#"), - FBT_SCRIPT_DIR="${ROOT_DIR}/scripts", + FBT_SCRIPT_DIR=Dir("#/scripts"), ) # If DIST_SUFFIX is set in environment, is has precedence (set by CI)