From 7bd3bd7ea4a0d600d7e5171dcfe7574da2019526 Mon Sep 17 00:00:00 2001 From: hedger Date: Wed, 1 Nov 2023 08:21:31 +0400 Subject: [PATCH] fbt: source collection improvements (#3181) * fbt: reduced amount of redundant compilation units * fbt: added GatherSources() method which can reject source paths starting with "!" in sources list; optimized apps' source lists * docs: updated on path exclusion for `sources` * apps: examples: fixed example_advanced_plugins source list * docs: more details on `sources`; apps: narrower sources lists --- .../examples/example_plugins/application.fam | 3 +++ .../example_plugins_advanced/application.fam | 1 + applications/main/ibutton/application.fam | 1 + applications/main/infrared/application.fam | 6 +++++ applications/main/lfrfid/application.fam | 1 + applications/main/nfc/application.fam | 12 +++++++++ applications/main/subghz/application.fam | 6 +++++ documentation/AppManifests.md | 2 +- firmware.scons | 2 +- scripts/fbt_tools/fbt_extapps.py | 12 +++------ scripts/fbt_tools/sconsrecursiveglob.py | 27 ++++++++++++++++++- 11 files changed, 61 insertions(+), 12 deletions(-) diff --git a/applications/examples/example_plugins/application.fam b/applications/examples/example_plugins/application.fam index a6e3c20781e..d9a36da564b 100644 --- a/applications/examples/example_plugins/application.fam +++ b/applications/examples/example_plugins/application.fam @@ -5,6 +5,7 @@ App( entry_point="example_plugins_app", stack_size=2 * 1024, fap_category="Examples", + sources=["*.c", "!plugin*.c"], ) App( @@ -21,6 +22,7 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="example_plugin1_ep", requires=["example_plugins", "example_plugins_multi"], + sources=["plugin1.c"], ) App( @@ -28,4 +30,5 @@ App( apptype=FlipperAppType.PLUGIN, entry_point="example_plugin2_ep", requires=["example_plugins_multi"], + sources=["plugin2.c"], ) diff --git a/applications/examples/example_plugins_advanced/application.fam b/applications/examples/example_plugins_advanced/application.fam index d40c0dde295..0c7e3e3b94d 100644 --- a/applications/examples/example_plugins_advanced/application.fam +++ b/applications/examples/example_plugins_advanced/application.fam @@ -5,6 +5,7 @@ App( entry_point="example_advanced_plugins_app", stack_size=2 * 1024, fap_category="Examples", + sources=["*.c*", "!plugin*.c"], ) App( diff --git a/applications/main/ibutton/application.fam b/applications/main/ibutton/application.fam index a8faa629cea..01c02ec23d6 100644 --- a/applications/main/ibutton/application.fam +++ b/applications/main/ibutton/application.fam @@ -17,5 +17,6 @@ App( apptype=FlipperAppType.STARTUP, targets=["f7"], entry_point="ibutton_on_system_start", + sources=["ibutton_cli.c"], order=60, ) diff --git a/applications/main/infrared/application.fam b/applications/main/infrared/application.fam index 055d6c3e294..575bebbe481 100644 --- a/applications/main/infrared/application.fam +++ b/applications/main/infrared/application.fam @@ -7,6 +7,7 @@ App( icon="A_Infrared_14", stack_size=3 * 1024, order=40, + sources=["*.c", "!infrared_cli.c"], resources="resources", fap_libs=["assets"], fap_icon="icon.png", @@ -18,5 +19,10 @@ App( apptype=FlipperAppType.STARTUP, targets=["f7"], entry_point="infrared_on_system_start", + sources=[ + "infrared_cli.c", + "infrared_brute_force.c", + "infrared_signal.c", + ], order=20, ) diff --git a/applications/main/lfrfid/application.fam b/applications/main/lfrfid/application.fam index cad07fbf777..c067d786fc4 100644 --- a/applications/main/lfrfid/application.fam +++ b/applications/main/lfrfid/application.fam @@ -17,5 +17,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="lfrfid_on_system_start", + sources=["lfrfid_cli.c"], order=50, ) diff --git a/applications/main/nfc/application.fam b/applications/main/nfc/application.fam index 3c8dab2bf1f..33a2011a70e 100644 --- a/applications/main/nfc/application.fam +++ b/applications/main/nfc/application.fam @@ -8,6 +8,11 @@ App( stack_size=5 * 1024, order=30, resources="resources", + sources=[ + "*.c", + "!plugins", + "!nfc_cli.c", + ], fap_libs=["assets"], fap_icon="icon.png", fap_category="NFC", @@ -21,6 +26,7 @@ App( entry_point="all_in_one_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/all_in_one.c"], ) App( @@ -29,6 +35,7 @@ App( entry_point="opal_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/opal.c"], ) App( @@ -37,6 +44,7 @@ App( entry_point="myki_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/myki.c"], ) App( @@ -45,6 +53,7 @@ App( entry_point="troika_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/troika.c"], ) App( @@ -53,6 +62,7 @@ App( entry_point="plantain_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/plantain.c"], ) App( @@ -61,6 +71,7 @@ App( entry_point="two_cities_plugin_ep", targets=["f7"], requires=["nfc"], + sources=["plugins/supported_cards/two_cities.c"], ) App( @@ -68,5 +79,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="nfc_on_system_start", + sources=["nfc_cli.c"], order=30, ) diff --git a/applications/main/subghz/application.fam b/applications/main/subghz/application.fam index ba9b16abfd7..5f9f24dcd31 100644 --- a/applications/main/subghz/application.fam +++ b/applications/main/subghz/application.fam @@ -7,6 +7,11 @@ App( icon="A_Sub1ghz_14", stack_size=3 * 1024, order=10, + sources=[ + "*.c", + "!subghz_cli.c", + "!helpers/subghz_chat.c", + ], resources="resources", fap_libs=["assets", "hwdrivers"], fap_icon="icon.png", @@ -18,5 +23,6 @@ App( targets=["f7"], apptype=FlipperAppType.STARTUP, entry_point="subghz_on_system_start", + sources=["subghz_cli.c", "helpers/subghz_chat.c"], order=40, ) diff --git a/documentation/AppManifests.md b/documentation/AppManifests.md index 0b3217c58cc..d190a798ba8 100644 --- a/documentation/AppManifests.md +++ b/documentation/AppManifests.md @@ -47,7 +47,7 @@ Only two parameters are mandatory: **_appid_** and **_apptype_**. Others are opt The following parameters are used only for [FAPs](./AppsOnSDCard.md): -- **sources**: list of strings, file name masks used for gathering sources within the app folder. The default value of `["*.c*"]` includes C and C++ source files. Applications cannot use the `"lib"` folder for their own source code, as it is reserved for **fap_private_libs**. +- **sources**: list of strings, file name masks used for gathering sources within the app folder. The default value of `["*.c*"]` includes C and C++ source files. Applications cannot use the `"lib"` folder for their own source code, as it is reserved for **fap_private_libs**. Paths starting with `"!"` are excluded from the list of sources. They can also include wildcard characters and directory names. For example, a value of `["*.c*", "!plugins"]` will include all C and C++ source files in the app folder except those in the `plugins` (and `lib`) folders. Paths with no wildcards (`*, ?`) are treated as full literal paths for both inclusion and exclusion. - **fap_version**: string, application version. The default value is "0.1". You can also use a tuple of 2 numbers in the form of (x,y) to specify the version. It is also possible to add more dot-separated parts to the version, like patch number, but only major and minor version numbers are stored in the built .fap. - **fap_icon**: name of a `.png` file, 1-bit color depth, 10x10px, to be embedded within `.fap` file. - **fap_libs**: list of extra libraries to link the application against. Provides access to extra functions that are not exported as a part of main firmware at the expense of increased `.fap` file size and RAM consumption. diff --git a/firmware.scons b/firmware.scons index 537774254cd..eca6afc4c70 100644 --- a/firmware.scons +++ b/firmware.scons @@ -197,7 +197,7 @@ sources = [apps_c] # Gather sources only from app folders in current configuration sources.extend( itertools.chain.from_iterable( - fwenv.GlobRecursive(source_type, appdir.relpath, exclude=["lib"]) + fwenv.GatherSources([source_type, "!lib"], appdir.relpath) for appdir, source_type in fwenv["APPBUILD"].get_builtin_app_folders() ) ) diff --git a/scripts/fbt_tools/fbt_extapps.py b/scripts/fbt_tools/fbt_extapps.py index 94307539a71..b88fa792911 100644 --- a/scripts/fbt_tools/fbt_extapps.py +++ b/scripts/fbt_tools/fbt_extapps.py @@ -147,16 +147,10 @@ def _build_app(self): CPPPATH=[self.app_work_dir, self.app._appdir], ) - app_sources = list( - itertools.chain.from_iterable( - self.app_env.GlobRecursive( - source_type, - self.app_work_dir, - exclude="lib", - ) - for source_type in self.app.sources - ) + app_sources = self.app_env.GatherSources( + [self.app.sources, "!lib"], self.app_work_dir ) + if not app_sources: raise UserError(f"No source files found for {self.app.appid}") diff --git a/scripts/fbt_tools/sconsrecursiveglob.py b/scripts/fbt_tools/sconsrecursiveglob.py index e7eb8fb7297..de64c76b7b3 100644 --- a/scripts/fbt_tools/sconsrecursiveglob.py +++ b/scripts/fbt_tools/sconsrecursiveglob.py @@ -1,7 +1,9 @@ +import itertools + import SCons from fbt.util import GLOB_FILE_EXCLUSION -from SCons.Script import Flatten from SCons.Node.FS import has_glob_magic +from SCons.Script import Flatten def GlobRecursive(env, pattern, node=".", exclude=[]): @@ -23,12 +25,35 @@ def GlobRecursive(env, pattern, node=".", exclude=[]): # Otherwise, just assume that file at path exists else: results.append(node.File(pattern)) + ## Debug # print(f"Glob result for {pattern} from {node}: {results}") return results +def GatherSources(env, sources_list, node="."): + sources_list = list(set(Flatten(sources_list))) + include_sources = list(filter(lambda x: not x.startswith("!"), sources_list)) + exclude_sources = list(x[1:] for x in sources_list if x.startswith("!")) + gathered_sources = list( + itertools.chain.from_iterable( + env.GlobRecursive( + source_type, + node, + exclude=exclude_sources, + ) + for source_type in include_sources + ) + ) + ## Debug + # print( + # f"Gathered sources for {sources_list} from {node}: {list(f.path for f in gathered_sources)}" + # ) + return gathered_sources + + def generate(env): env.AddMethod(GlobRecursive) + env.AddMethod(GatherSources) def exists(env):