Procházet zdrojové kódy

fbt: support for LOADER_AUTOSTART; post-build size stats (#1594)

* fbt: restored LOADER_AUTOSTART support
* scripts: added fwsize.py wrapper for size command; fbt: changed size post-build stats to fwsize.py call
* fbt: removed size wrapper
* fbt: added stats for binary flash size in pages
* fbt: hint on build options details
* scripts: fixed fwsize.py for *nix
hedger před 3 roky
rodič
revize
e1ffb4ac4d

+ 2 - 0
applications/applications.h

@@ -18,6 +18,8 @@ typedef struct {
 
 typedef void (*FlipperOnStartHook)(void);
 
+extern const char* FLIPPER_AUTORUN_APP_NAME;
+
 /* Services list
  * Spawned on startup
  */

+ 3 - 3
applications/loader/loader.c

@@ -466,9 +466,9 @@ int32_t loader_srv(void* p) {
 
     furi_record_create(RECORD_LOADER, loader_instance);
 
-#ifdef LOADER_AUTOSTART
-    loader_start(loader_instance, LOADER_AUTOSTART, NULL);
-#endif
+    if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) {
+        loader_start(loader_instance, FLIPPER_AUTORUN_APP_NAME, NULL);
+    }
 
     while(1) {
         uint32_t flags =

+ 5 - 0
fbt_options.py

@@ -1,5 +1,7 @@
 import posixpath
 
+# For more details on these options, run 'fbt -h'
+
 
 # Default hardware target
 TARGET_HW = 7
@@ -59,6 +61,9 @@ SVD_FILE = "debug/STM32WB55_CM4.svd"
 # Look for blackmagic probe on serial ports and local network
 BLACKMAGIC = "auto"
 
+# Application to start on boot
+LOADER_AUTOSTART = ""
+
 FIRMWARE_APPS = {
     "default": [
         "crypto_start",

+ 10 - 2
firmware.scons

@@ -139,7 +139,7 @@ fwenv.AppendUnique(
 # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes
 apps_c = fwenv.ApplicationsC(
     "applications/applications.c",
-    Value(fwenv["APPS"]),
+    [Value(fwenv["APPS"]), Value(fwenv["LOADER_AUTOSTART"])],
 )
 # Adding dependency on manifest files so apps.c is rebuilt when any manifest is changed
 fwenv.Depends(apps_c, fwenv.GlobRecursive("*.fam", "#/applications"))
@@ -210,11 +210,19 @@ fwelf = fwenv["FW_ELF"] = fwenv.Program(
 Depends(fwelf, lib_targets)
 # Output extra details after building firmware
 AddPostAction(fwelf, fwenv["APPBUILD_DUMP"])
-AddPostAction(fwelf, Action("@$SIZECOM"))
+AddPostAction(
+    fwelf,
+    Action('${PYTHON3} "${ROOT_DIR}/scripts/fwsize.py" elf ${TARGET}', "Firmware size"),
+)
 
 # Produce extra firmware files
 fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}")
 fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}")
+AddPostAction(
+    fwbin,
+    Action('@${PYTHON3} "${ROOT_DIR}/scripts/fwsize.py" bin ${TARGET}'),
+)
+
 fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}")
 Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu)
 

+ 52 - 0
scripts/fwsize.py

@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+
+from flipper.app import App
+import subprocess
+import os
+import math
+
+
+class Main(App):
+    def init(self):
+        self.subparsers = self.parser.add_subparsers(help="sub-command help")
+
+        self.parser_elfsize = self.subparsers.add_parser("elf", help="Dump elf stats")
+        self.parser_elfsize.add_argument("elfname", action="store")
+        self.parser_elfsize.set_defaults(func=self.process_elf)
+
+        self.parser_binsize = self.subparsers.add_parser("bin", help="Dump bin stats")
+        self.parser_binsize.add_argument("binname", action="store")
+        self.parser_binsize.set_defaults(func=self.process_bin)
+
+    def process_elf(self):
+        all_sizes = subprocess.check_output(
+            ["arm-none-eabi-size", "-A", self.args.elfname], shell=False
+        )
+        all_sizes = all_sizes.splitlines()
+
+        sections_to_keep = (".text", ".rodata", ".data", ".bss", ".free_flash")
+        for line in all_sizes:
+            line = line.decode("utf-8")
+            parts = line.split()
+            if len(parts) != 3:
+                continue
+            section, size, _ = parts
+            if section not in sections_to_keep:
+                continue
+            print(f"{section:<11} {size:>8} ({(int(size)/1024):6.2f} K)")
+
+        return 0
+
+    def process_bin(self):
+        PAGE_SIZE = 4096
+        binsize = os.path.getsize(self.args.binname)
+        pages = math.ceil(binsize / PAGE_SIZE)
+        last_page_state = (binsize % PAGE_SIZE) * 100 / PAGE_SIZE
+        print(
+            f"{os.path.basename(self.args.binname):<11}: {pages:>4} flash pages (last page {last_page_state:.02f}% full)"
+        )
+        return 0
+
+
+if __name__ == "__main__":
+    Main()()

+ 6 - 0
site_scons/commandline.scons

@@ -174,6 +174,12 @@ vars.Add(
     default="update_default",
 )
 
+vars.Add(
+    "LOADER_AUTOSTART",
+    help="Application name to automatically run on Flipper boot",
+    default="",
+)
+
 
 vars.Add(
     "FIRMWARE_APPS",

+ 7 - 2
site_scons/fbt/appmanifest.py

@@ -200,8 +200,9 @@ class ApplicationsCGenerator:
         FlipperAppType.STARTUP: ("FlipperOnStartHook", "FLIPPER_ON_SYSTEM_START"),
     }
 
-    def __init__(self, buildset: AppBuildset):
+    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:
@@ -219,7 +220,11 @@ class ApplicationsCGenerator:
      .flags = {'|'.join(f"FlipperApplicationFlag{flag}" for flag in app.flags)} }}"""
 
     def generate(self):
-        contents = ['#include "applications.h"', "#include <assets_icons.h>"]
+        contents = [
+            '#include "applications.h"',
+            "#include <assets_icons.h>",
+            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))

+ 1 - 3
site_scons/site_tools/crosscc.py

@@ -7,7 +7,6 @@ from SCons.Tool import gnulink
 import strip
 import gdb
 import objdump
-import size
 
 from SCons.Action import _subproc
 import subprocess
@@ -38,7 +37,7 @@ def _get_tool_version(env, tool):
 
 
 def generate(env, **kw):
-    for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump, size):
+    for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump):
         orig_tool.generate(env)
     env.SetDefault(
         TOOLCHAIN_PREFIX=kw.get("toolchain_prefix"),
@@ -57,7 +56,6 @@ def generate(env, **kw):
             "GDB",
             "GDBPY",
             "OBJDUMP",
-            "SIZE",
         ],
     )
     # Call CC to check version

+ 1 - 1
site_scons/site_tools/fbt_apps.py

@@ -51,7 +51,7 @@ def DumpApplicationConfig(target, source, env):
 def build_apps_c(target, source, env):
     target_file_name = target[0].path
 
-    gen = ApplicationsCGenerator(env["APPBUILD"])
+    gen = ApplicationsCGenerator(env["APPBUILD"], env.subst("$LOADER_AUTOSTART"))
     with open(target_file_name, "w") as file:
         file.write(gen.generate())
 

+ 0 - 24
site_scons/site_tools/size.py

@@ -1,24 +0,0 @@
-from SCons.Builder import Builder
-from SCons.Action import Action
-
-
-def generate(env):
-    env.SetDefault(
-        SIZE="size",
-        SIZEFLAGS=[],
-        SIZECOM="$SIZE $SIZEFLAGS $TARGETS",
-    )
-    env.Append(
-        BUILDERS={
-            "ELFSize": Builder(
-                action=Action(
-                    "${SIZECOM}",
-                    "${SIZECOMSTR}",
-                ),
-            ),
-        }
-    )
-
-
-def exists(env):
-    return True