fbt: improvements (#3217)
* 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: あく <alleteam@gmail.com>
This commit is contained in:
parent
457aa5331f
commit
98d5718ec9
36
SConstruct
36
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 $)",
|
||||
)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -3,7 +3,6 @@ App(
|
||||
name="Battery Test",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="battery_test_app",
|
||||
cdefines=["APP_BATTERY_TEST"],
|
||||
requires=[
|
||||
"gui",
|
||||
"power",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -3,7 +3,6 @@ App(
|
||||
name="CCID Debug",
|
||||
apptype=FlipperAppType.DEBUG,
|
||||
entry_point="ccid_test_app",
|
||||
cdefines=["CCID_TEST"],
|
||||
requires=[
|
||||
"gui",
|
||||
],
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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}")
|
||||
|
||||
@ -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 <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))
|
||||
)
|
||||
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)
|
||||
|
||||
@ -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 <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))
|
||||
)
|
||||
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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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",
|
||||
),
|
||||
],
|
||||
|
||||
@ -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,
|
||||
),
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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}"),
|
||||
],
|
||||
),
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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}",
|
||||
|
||||
@ -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}",
|
||||
),
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user