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
This commit is contained in:
		@@ -18,6 +18,8 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
typedef void (*FlipperOnStartHook)(void);
 | 
			
		||||
 | 
			
		||||
extern const char* FLIPPER_AUTORUN_APP_NAME;
 | 
			
		||||
 | 
			
		||||
/* Services list
 | 
			
		||||
 * Spawned on startup
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -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 =
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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
									
								
								scripts/fwsize.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								scripts/fwsize.py
									
									
									
									
									
										Normal file
									
								
							@@ -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()()
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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())
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
		Reference in New Issue
	
	Block a user