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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 hedger
						hedger