fbt: 'target' field for apps; lib debugging support (#1995)
* fbt: added 'target' field to application manifest * fbt: earlier pagination setup for gdb * fbt: added LIB_DEBUG flag * fbt: sdk: added SDK_MAP_FILE_SUBST
This commit is contained in:
parent
3985b456c3
commit
a959fa32bc
@ -7,6 +7,7 @@
|
|||||||
# construction of certain targets behind command-line options.
|
# construction of certain targets behind command-line options.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from fbt.util import path_as_posix
|
||||||
|
|
||||||
DefaultEnvironment(tools=[])
|
DefaultEnvironment(tools=[])
|
||||||
|
|
||||||
@ -200,9 +201,7 @@ firmware_debug = distenv.PhonyTarget(
|
|||||||
source=firmware_env["FW_ELF"],
|
source=firmware_env["FW_ELF"],
|
||||||
GDBOPTS="${GDBOPTS_BASE}",
|
GDBOPTS="${GDBOPTS_BASE}",
|
||||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||||
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace(
|
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
|
||||||
"\\", "/"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
distenv.Depends(firmware_debug, firmware_flash)
|
distenv.Depends(firmware_debug, firmware_flash)
|
||||||
|
|
||||||
@ -212,9 +211,7 @@ distenv.PhonyTarget(
|
|||||||
source=firmware_env["FW_ELF"],
|
source=firmware_env["FW_ELF"],
|
||||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||||
FBT_FAP_DEBUG_ELF_ROOT=firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT").replace(
|
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
|
||||||
"\\", "/"
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Debug alien elf
|
# Debug alien elf
|
||||||
|
@ -40,6 +40,7 @@ Only 2 parameters are mandatory: ***appid*** and ***apptype***, others are optio
|
|||||||
* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware.
|
* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware.
|
||||||
* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.*
|
* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.*
|
||||||
* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications.
|
* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications.
|
||||||
|
* **targets**: list of strings, target names, which this application is compatible with. If not specified, application is built for all targets. Default value is `["all"]`.
|
||||||
|
|
||||||
|
|
||||||
#### Parameters for external applications
|
#### Parameters for external applications
|
||||||
|
@ -40,11 +40,11 @@ env = ENV.Clone(
|
|||||||
FW_LIB_OPTS={
|
FW_LIB_OPTS={
|
||||||
"Default": {
|
"Default": {
|
||||||
"CCFLAGS": [
|
"CCFLAGS": [
|
||||||
"-Os",
|
"-Og" if ENV["LIB_DEBUG"] else "-Os",
|
||||||
],
|
],
|
||||||
"CPPDEFINES": [
|
"CPPDEFINES": [
|
||||||
"NDEBUG",
|
"NDEBUG",
|
||||||
"FURI_NDEBUG",
|
"FURI_DEBUG" if ENV["LIB_DEBUG"] else "FURI_NDEBUG",
|
||||||
],
|
],
|
||||||
# You can add other entries named after libraries
|
# You can add other entries named after libraries
|
||||||
# If they are present, they have precedence over Default
|
# If they are present, they have precedence over Default
|
||||||
|
@ -52,6 +52,8 @@ class FlipperApplication:
|
|||||||
icon: Optional[str] = None
|
icon: Optional[str] = None
|
||||||
order: int = 0
|
order: int = 0
|
||||||
sdk_headers: List[str] = field(default_factory=list)
|
sdk_headers: List[str] = field(default_factory=list)
|
||||||
|
targets: List[str] = field(default_factory=lambda: ["all"])
|
||||||
|
|
||||||
# .fap-specific
|
# .fap-specific
|
||||||
sources: List[str] = field(default_factory=lambda: ["*.c*"])
|
sources: List[str] = field(default_factory=lambda: ["*.c*"])
|
||||||
fap_version: Tuple[int] = field(default_factory=lambda: (0, 1))
|
fap_version: Tuple[int] = field(default_factory=lambda: (0, 1))
|
||||||
@ -135,8 +137,8 @@ class AppManager:
|
|||||||
raise FlipperManifestException(f"Duplicate app declaration: {app.appid}")
|
raise FlipperManifestException(f"Duplicate app declaration: {app.appid}")
|
||||||
self.known_apps[app.appid] = app
|
self.known_apps[app.appid] = app
|
||||||
|
|
||||||
def filter_apps(self, applist: List[str]):
|
def filter_apps(self, applist: List[str], hw_target: str):
|
||||||
return AppBuildset(self, applist)
|
return AppBuildset(self, applist, hw_target)
|
||||||
|
|
||||||
|
|
||||||
class AppBuilderException(Exception):
|
class AppBuilderException(Exception):
|
||||||
@ -155,11 +157,13 @@ class AppBuildset:
|
|||||||
FlipperAppType.STARTUP,
|
FlipperAppType.STARTUP,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, appmgr: AppManager, appnames: List[str]):
|
def __init__(self, appmgr: AppManager, appnames: List[str], hw_target: str):
|
||||||
self.appmgr = appmgr
|
self.appmgr = appmgr
|
||||||
self.appnames = set(appnames)
|
self.appnames = set(appnames)
|
||||||
|
self.hw_target = hw_target
|
||||||
self._orig_appnames = appnames
|
self._orig_appnames = appnames
|
||||||
self._process_deps()
|
self._process_deps()
|
||||||
|
self._filter_by_target()
|
||||||
self._check_conflicts()
|
self._check_conflicts()
|
||||||
self._check_unsatisfied() # unneeded?
|
self._check_unsatisfied() # unneeded?
|
||||||
self.apps = sorted(
|
self.apps = sorted(
|
||||||
@ -170,6 +174,16 @@ class AppBuildset:
|
|||||||
def _is_missing_dep(self, dep_name: str):
|
def _is_missing_dep(self, dep_name: str):
|
||||||
return dep_name not in self.appnames
|
return dep_name not in self.appnames
|
||||||
|
|
||||||
|
def _filter_by_target(self):
|
||||||
|
for appname in self.appnames.copy():
|
||||||
|
app = self.appmgr.get(appname)
|
||||||
|
# if app.apptype not in self.BUILTIN_APP_TYPES:
|
||||||
|
if not any(map(lambda t: t in app.targets, ["all", self.hw_target])):
|
||||||
|
print(
|
||||||
|
f"Removing {appname} due to target mismatch (building for {self.hw_target}, app supports {app.targets}"
|
||||||
|
)
|
||||||
|
self.appnames.remove(appname)
|
||||||
|
|
||||||
def _process_deps(self):
|
def _process_deps(self):
|
||||||
while True:
|
while True:
|
||||||
provided = []
|
provided = []
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import SCons
|
import SCons
|
||||||
from SCons.Subst import quote_spaces
|
from SCons.Subst import quote_spaces
|
||||||
from SCons.Errors import StopError
|
from SCons.Errors import StopError
|
||||||
from SCons.Node.FS import _my_normcase
|
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
@ -58,3 +57,9 @@ def extract_abs_dir_path(node):
|
|||||||
raise StopError(f"Can't find absolute path for {node.name}")
|
raise StopError(f"Can't find absolute path for {node.name}")
|
||||||
|
|
||||||
return abs_dir_node.abspath
|
return abs_dir_node.abspath
|
||||||
|
|
||||||
|
|
||||||
|
def path_as_posix(path):
|
||||||
|
if SCons.Platform.platform_default() == "win32":
|
||||||
|
return path.replace(os.path.sep, os.path.altsep)
|
||||||
|
return path
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from SCons.Builder import Builder
|
from SCons.Builder import Builder
|
||||||
from SCons.Action import Action
|
from SCons.Action import Action
|
||||||
from SCons.Warnings import warn, WarningOnByDefault
|
from SCons.Warnings import warn, WarningOnByDefault
|
||||||
import SCons
|
|
||||||
from ansi.color import fg
|
from ansi.color import fg
|
||||||
|
|
||||||
from fbt.appmanifest import (
|
from fbt.appmanifest import (
|
||||||
@ -33,14 +32,12 @@ def LoadAppManifest(env, entry):
|
|||||||
|
|
||||||
|
|
||||||
def PrepareApplicationsBuild(env):
|
def PrepareApplicationsBuild(env):
|
||||||
appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(env["APPS"])
|
appbuild = env["APPBUILD"] = env["APPMGR"].filter_apps(
|
||||||
|
env["APPS"], env.subst("f${TARGET_HW}")
|
||||||
|
)
|
||||||
env.Append(
|
env.Append(
|
||||||
SDK_HEADERS=appbuild.get_sdk_headers(),
|
SDK_HEADERS=appbuild.get_sdk_headers(),
|
||||||
)
|
)
|
||||||
env["APPBUILD_DUMP"] = env.Action(
|
|
||||||
DumpApplicationConfig,
|
|
||||||
"\tINFO\t",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def DumpApplicationConfig(target, source, env):
|
def DumpApplicationConfig(target, source, env):
|
||||||
@ -68,6 +65,10 @@ def generate(env):
|
|||||||
env.AddMethod(PrepareApplicationsBuild)
|
env.AddMethod(PrepareApplicationsBuild)
|
||||||
env.SetDefault(
|
env.SetDefault(
|
||||||
APPMGR=AppManager(),
|
APPMGR=AppManager(),
|
||||||
|
APPBUILD_DUMP=env.Action(
|
||||||
|
DumpApplicationConfig,
|
||||||
|
"\tINFO\t",
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
env.Append(
|
env.Append(
|
||||||
|
@ -41,12 +41,12 @@ def generate(env, **kw):
|
|||||||
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
"|openocd -c 'gdb_port pipe; log_output ${FBT_DEBUG_DIR}/openocd.log' ${[SINGLEQUOTEFUNC(OPENOCD_OPTS)]}"
|
||||||
],
|
],
|
||||||
GDBOPTS_BASE=[
|
GDBOPTS_BASE=[
|
||||||
|
"-ex",
|
||||||
|
"set pagination off",
|
||||||
"-ex",
|
"-ex",
|
||||||
"target extended-remote ${GDBREMOTE}",
|
"target extended-remote ${GDBREMOTE}",
|
||||||
"-ex",
|
"-ex",
|
||||||
"set confirm off",
|
"set confirm off",
|
||||||
"-ex",
|
|
||||||
"set pagination off",
|
|
||||||
],
|
],
|
||||||
GDBOPTS_BLACKMAGIC=[
|
GDBOPTS_BLACKMAGIC=[
|
||||||
"-ex",
|
"-ex",
|
||||||
|
@ -14,6 +14,7 @@ import json
|
|||||||
|
|
||||||
from fbt.sdk.collector import SdkCollector
|
from fbt.sdk.collector import SdkCollector
|
||||||
from fbt.sdk.cache import SdkCache
|
from fbt.sdk.cache import SdkCache
|
||||||
|
from fbt.util import path_as_posix
|
||||||
|
|
||||||
|
|
||||||
def ProcessSdkDepends(env, filename):
|
def ProcessSdkDepends(env, filename):
|
||||||
@ -52,6 +53,8 @@ def prebuild_sdk_create_origin_file(target, source, env):
|
|||||||
|
|
||||||
|
|
||||||
class SdkMeta:
|
class SdkMeta:
|
||||||
|
MAP_FILE_SUBST = "SDK_MAP_FILE_SUBST"
|
||||||
|
|
||||||
def __init__(self, env, tree_builder: "SdkTreeBuilder"):
|
def __init__(self, env, tree_builder: "SdkTreeBuilder"):
|
||||||
self.env = env
|
self.env = env
|
||||||
self.treebuilder = tree_builder
|
self.treebuilder = tree_builder
|
||||||
@ -67,6 +70,7 @@ class SdkMeta:
|
|||||||
"linker_libs": self.env.subst("${LIBS}"),
|
"linker_libs": self.env.subst("${LIBS}"),
|
||||||
"app_ep_subst": self.env.subst("${APP_ENTRY}"),
|
"app_ep_subst": self.env.subst("${APP_ENTRY}"),
|
||||||
"sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"),
|
"sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"),
|
||||||
|
"map_file_subst": self.MAP_FILE_SUBST,
|
||||||
"hardware": self.env.subst("${TARGET_HW}"),
|
"hardware": self.env.subst("${TARGET_HW}"),
|
||||||
}
|
}
|
||||||
with open(json_manifest_path, "wt") as f:
|
with open(json_manifest_path, "wt") as f:
|
||||||
@ -75,9 +79,9 @@ class SdkMeta:
|
|||||||
def _wrap_scons_vars(self, vars: str):
|
def _wrap_scons_vars(self, vars: str):
|
||||||
expanded_vars = self.env.subst(
|
expanded_vars = self.env.subst(
|
||||||
vars,
|
vars,
|
||||||
target=Entry("dummy"),
|
target=Entry(self.MAP_FILE_SUBST),
|
||||||
)
|
)
|
||||||
return expanded_vars.replace("\\", "/")
|
return path_as_posix(expanded_vars)
|
||||||
|
|
||||||
|
|
||||||
class SdkTreeBuilder:
|
class SdkTreeBuilder:
|
||||||
@ -142,13 +146,15 @@ class SdkTreeBuilder:
|
|||||||
meta.save_to(self.target[0].path)
|
meta.save_to(self.target[0].path)
|
||||||
|
|
||||||
def build_sdk_file_path(self, orig_path: str) -> str:
|
def build_sdk_file_path(self, orig_path: str) -> str:
|
||||||
return posixpath.normpath(
|
return path_as_posix(
|
||||||
posixpath.join(
|
posixpath.normpath(
|
||||||
self.SDK_DIR_SUBST,
|
posixpath.join(
|
||||||
self.target_sdk_dir_name,
|
self.SDK_DIR_SUBST,
|
||||||
orig_path,
|
self.target_sdk_dir_name,
|
||||||
|
orig_path,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
).replace("\\", "/")
|
)
|
||||||
|
|
||||||
def emitter(self, target, source, env):
|
def emitter(self, target, source, env):
|
||||||
target_folder = target[0]
|
target_folder = target[0]
|
||||||
|
@ -63,6 +63,11 @@ vars.AddVariables(
|
|||||||
help="Enable debug build",
|
help="Enable debug build",
|
||||||
default=True,
|
default=True,
|
||||||
),
|
),
|
||||||
|
BoolVariable(
|
||||||
|
"LIB_DEBUG",
|
||||||
|
help="Enable debug build for libraries",
|
||||||
|
default=False,
|
||||||
|
),
|
||||||
BoolVariable(
|
BoolVariable(
|
||||||
"COMPACT",
|
"COMPACT",
|
||||||
help="Optimize for size",
|
help="Optimize for size",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from SCons.Errors import UserError
|
|
||||||
from SCons.Node import NodeList
|
from SCons.Node import NodeList
|
||||||
|
from SCons.Warnings import warn, WarningOnByDefault
|
||||||
|
|
||||||
|
|
||||||
Import("ENV")
|
Import("ENV")
|
||||||
@ -80,6 +80,14 @@ if extra_app_list := GetOption("extra_ext_apps"):
|
|||||||
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
|
known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
|
||||||
|
|
||||||
for app in known_extapps:
|
for app in known_extapps:
|
||||||
|
if not any(map(lambda t: t in app.targets, ["all", appenv.subst("f${TARGET_HW}")])):
|
||||||
|
warn(
|
||||||
|
WarningOnByDefault,
|
||||||
|
f"Can't build '{app.name}' (id '{app.appid}'): target mismatch"
|
||||||
|
f" (building for {appenv.subst('f${TARGET_HW}')}, app supports {app.targets}",
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
appenv.BuildAppElf(app)
|
appenv.BuildAppElf(app)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user