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. | ||||
| 
 | ||||
| import os | ||||
| from fbt.util import path_as_posix | ||||
| 
 | ||||
| DefaultEnvironment(tools=[]) | ||||
| 
 | ||||
| @ -200,9 +201,7 @@ firmware_debug = distenv.PhonyTarget( | ||||
|     source=firmware_env["FW_ELF"], | ||||
|     GDBOPTS="${GDBOPTS_BASE}", | ||||
|     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) | ||||
| 
 | ||||
| @ -212,9 +211,7 @@ distenv.PhonyTarget( | ||||
|     source=firmware_env["FW_ELF"], | ||||
|     GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}", | ||||
|     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 | ||||
|  | ||||
| @ -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. | ||||
| * **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. | ||||
| * **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 | ||||
|  | ||||
| @ -40,11 +40,11 @@ env = ENV.Clone( | ||||
|     FW_LIB_OPTS={ | ||||
|         "Default": { | ||||
|             "CCFLAGS": [ | ||||
|                 "-Os", | ||||
|                 "-Og" if ENV["LIB_DEBUG"] else "-Os", | ||||
|             ], | ||||
|             "CPPDEFINES": [ | ||||
|                 "NDEBUG", | ||||
|                 "FURI_NDEBUG", | ||||
|                 "FURI_DEBUG" if ENV["LIB_DEBUG"] else "FURI_NDEBUG", | ||||
|             ], | ||||
|             # You can add other entries named after libraries | ||||
|             # If they are present, they have precedence over Default | ||||
|  | ||||
| @ -52,6 +52,8 @@ class FlipperApplication: | ||||
|     icon: Optional[str] = None | ||||
|     order: int = 0 | ||||
|     sdk_headers: List[str] = field(default_factory=list) | ||||
|     targets: List[str] = field(default_factory=lambda: ["all"]) | ||||
| 
 | ||||
|     # .fap-specific | ||||
|     sources: List[str] = field(default_factory=lambda: ["*.c*"]) | ||||
|     fap_version: Tuple[int] = field(default_factory=lambda: (0, 1)) | ||||
| @ -135,8 +137,8 @@ class AppManager: | ||||
|             raise FlipperManifestException(f"Duplicate app declaration: {app.appid}") | ||||
|         self.known_apps[app.appid] = app | ||||
| 
 | ||||
|     def filter_apps(self, applist: List[str]): | ||||
|         return AppBuildset(self, applist) | ||||
|     def filter_apps(self, applist: List[str], hw_target: str): | ||||
|         return AppBuildset(self, applist, hw_target) | ||||
| 
 | ||||
| 
 | ||||
| class AppBuilderException(Exception): | ||||
| @ -155,11 +157,13 @@ class AppBuildset: | ||||
|         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.appnames = set(appnames) | ||||
|         self.hw_target = hw_target | ||||
|         self._orig_appnames = appnames | ||||
|         self._process_deps() | ||||
|         self._filter_by_target() | ||||
|         self._check_conflicts() | ||||
|         self._check_unsatisfied()  # unneeded? | ||||
|         self.apps = sorted( | ||||
| @ -170,6 +174,16 @@ class AppBuildset: | ||||
|     def _is_missing_dep(self, dep_name: str): | ||||
|         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): | ||||
|         while True: | ||||
|             provided = [] | ||||
|  | ||||
| @ -1,7 +1,6 @@ | ||||
| import SCons | ||||
| from SCons.Subst import quote_spaces | ||||
| from SCons.Errors import StopError | ||||
| from SCons.Node.FS import _my_normcase | ||||
| 
 | ||||
| import re | ||||
| import os | ||||
| @ -58,3 +57,9 @@ def extract_abs_dir_path(node): | ||||
|         raise StopError(f"Can't find absolute path for {node.name}") | ||||
| 
 | ||||
|     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.Action import Action | ||||
| from SCons.Warnings import warn, WarningOnByDefault | ||||
| import SCons | ||||
| from ansi.color import fg | ||||
| 
 | ||||
| from fbt.appmanifest import ( | ||||
| @ -33,14 +32,12 @@ def LoadAppManifest(env, entry): | ||||
| 
 | ||||
| 
 | ||||
| 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( | ||||
|         SDK_HEADERS=appbuild.get_sdk_headers(), | ||||
|     ) | ||||
|     env["APPBUILD_DUMP"] = env.Action( | ||||
|         DumpApplicationConfig, | ||||
|         "\tINFO\t", | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| def DumpApplicationConfig(target, source, env): | ||||
| @ -68,6 +65,10 @@ def generate(env): | ||||
|     env.AddMethod(PrepareApplicationsBuild) | ||||
|     env.SetDefault( | ||||
|         APPMGR=AppManager(), | ||||
|         APPBUILD_DUMP=env.Action( | ||||
|             DumpApplicationConfig, | ||||
|             "\tINFO\t", | ||||
|         ), | ||||
|     ) | ||||
| 
 | ||||
|     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)]}" | ||||
|         ], | ||||
|         GDBOPTS_BASE=[ | ||||
|             "-ex", | ||||
|             "set pagination off", | ||||
|             "-ex", | ||||
|             "target extended-remote ${GDBREMOTE}", | ||||
|             "-ex", | ||||
|             "set confirm off", | ||||
|             "-ex", | ||||
|             "set pagination off", | ||||
|         ], | ||||
|         GDBOPTS_BLACKMAGIC=[ | ||||
|             "-ex", | ||||
|  | ||||
| @ -14,6 +14,7 @@ import json | ||||
| 
 | ||||
| from fbt.sdk.collector import SdkCollector | ||||
| from fbt.sdk.cache import SdkCache | ||||
| from fbt.util import path_as_posix | ||||
| 
 | ||||
| 
 | ||||
| def ProcessSdkDepends(env, filename): | ||||
| @ -52,6 +53,8 @@ def prebuild_sdk_create_origin_file(target, source, env): | ||||
| 
 | ||||
| 
 | ||||
| class SdkMeta: | ||||
|     MAP_FILE_SUBST = "SDK_MAP_FILE_SUBST" | ||||
| 
 | ||||
|     def __init__(self, env, tree_builder: "SdkTreeBuilder"): | ||||
|         self.env = env | ||||
|         self.treebuilder = tree_builder | ||||
| @ -67,6 +70,7 @@ class SdkMeta: | ||||
|             "linker_libs": self.env.subst("${LIBS}"), | ||||
|             "app_ep_subst": self.env.subst("${APP_ENTRY}"), | ||||
|             "sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"), | ||||
|             "map_file_subst": self.MAP_FILE_SUBST, | ||||
|             "hardware": self.env.subst("${TARGET_HW}"), | ||||
|         } | ||||
|         with open(json_manifest_path, "wt") as f: | ||||
| @ -75,9 +79,9 @@ class SdkMeta: | ||||
|     def _wrap_scons_vars(self, vars: str): | ||||
|         expanded_vars = self.env.subst( | ||||
|             vars, | ||||
|             target=Entry("dummy"), | ||||
|             target=Entry(self.MAP_FILE_SUBST), | ||||
|         ) | ||||
|         return expanded_vars.replace("\\", "/") | ||||
|         return path_as_posix(expanded_vars) | ||||
| 
 | ||||
| 
 | ||||
| class SdkTreeBuilder: | ||||
| @ -142,13 +146,15 @@ class SdkTreeBuilder: | ||||
|         meta.save_to(self.target[0].path) | ||||
| 
 | ||||
|     def build_sdk_file_path(self, orig_path: str) -> str: | ||||
|         return posixpath.normpath( | ||||
|         return path_as_posix( | ||||
|             posixpath.normpath( | ||||
|                 posixpath.join( | ||||
|                     self.SDK_DIR_SUBST, | ||||
|                     self.target_sdk_dir_name, | ||||
|                     orig_path, | ||||
|                 ) | ||||
|         ).replace("\\", "/") | ||||
|             ) | ||||
|         ) | ||||
| 
 | ||||
|     def emitter(self, target, source, env): | ||||
|         target_folder = target[0] | ||||
|  | ||||
| @ -63,6 +63,11 @@ vars.AddVariables( | ||||
|         help="Enable debug build", | ||||
|         default=True, | ||||
|     ), | ||||
|     BoolVariable( | ||||
|         "LIB_DEBUG", | ||||
|         help="Enable debug build for libraries", | ||||
|         default=False, | ||||
|     ), | ||||
|     BoolVariable( | ||||
|         "COMPACT", | ||||
|         help="Optimize for size", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| from dataclasses import dataclass, field | ||||
| from SCons.Errors import UserError | ||||
| from SCons.Node import NodeList | ||||
| from SCons.Warnings import warn, WarningOnByDefault | ||||
| 
 | ||||
| 
 | ||||
| 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(","))) | ||||
| 
 | ||||
| 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) | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 hedger
						hedger