[FL-3330] fbt: added hooks for build & dist environments; added FW_ORIGIN_* macro for apps & SDK (#2705)
* fbt: added hooks for build & dist environments * Moved env hooks to an optional file * Fixed var name * Added fw origin to device info * Bumped device info version * fbt: added FIRMWARE_ORIGIN option. Different implementation for FW_ORIGIN_* C macro. * api: bumped versions * fbt: added fbt_options_local.py * gitignore: cleanup Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									3de856f8d5
								
							
						
					
					
						commit
						8d2ea14f06
					
				
							
								
								
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -30,27 +30,25 @@ bindings/ | ||||
| .mxproject | ||||
| Brewfile.lock.json | ||||
| 
 | ||||
| # Visual Studio Code | ||||
| /.vscode/ | ||||
| 
 | ||||
| # Kate | ||||
| .kateproject | ||||
| .kateconfig | ||||
| 
 | ||||
| # legendary cmake's | ||||
| build | ||||
| CMakeLists.txt | ||||
| 
 | ||||
| # bundle output | ||||
| dist | ||||
| 
 | ||||
| # kde | ||||
| .directory | ||||
| 
 | ||||
| # SCons | ||||
| .sconsign.dblite | ||||
| 
 | ||||
| 
 | ||||
| # Visual Studio Code | ||||
| /.vscode | ||||
| 
 | ||||
| # bundle output | ||||
| /dist | ||||
| 
 | ||||
| # SCons build dir | ||||
| build/ | ||||
| /build | ||||
| 
 | ||||
| # Toolchain | ||||
| /toolchain | ||||
| @ -64,3 +62,5 @@ PVS-Studio.log | ||||
| *.PVS-Studio.* | ||||
| 
 | ||||
| .gdbinit | ||||
| 
 | ||||
| /fbt_options_local.py | ||||
| @ -114,6 +114,8 @@ To run cleanup (think of `make clean`) for specified targets, add the `-c` optio | ||||
| Default configuration variables are set in the configuration file: `fbt_options.py`. | ||||
| Values set in the command line have higher precedence over the configuration file. | ||||
| 
 | ||||
| You can also create a file called `fbt_options_local.py` that will be evaluated when loading default options file, enabling persisent overriding of  default options without modifying default configuration. | ||||
| 
 | ||||
| You can find out available options with `./fbt -h`. | ||||
| 
 | ||||
| ### Firmware application set | ||||
|  | ||||
| @ -1,7 +1,9 @@ | ||||
| from pathlib import Path | ||||
| import posixpath | ||||
| 
 | ||||
| # For more details on these options, run 'fbt -h' | ||||
| 
 | ||||
| FIRMWARE_ORIGIN = "Official" | ||||
| 
 | ||||
| # Default hardware target | ||||
| TARGET_HW = 7 | ||||
| @ -75,3 +77,8 @@ FIRMWARE_APPS = { | ||||
| } | ||||
| 
 | ||||
| FIRMWARE_APP_SET = "default" | ||||
| 
 | ||||
| custom_options_fn = "fbt_options_local.py" | ||||
| 
 | ||||
| if Path(custom_options_fn).exists(): | ||||
|     exec(compile(Path(custom_options_fn).read_text(), custom_options_fn, "exec")) | ||||
|  | ||||
| @ -18,6 +18,7 @@ env = ENV.Clone( | ||||
|         "fbt_apps", | ||||
|         "pvsstudio", | ||||
|         "fbt_hwtarget", | ||||
|         "fbt_envhooks", | ||||
|     ], | ||||
|     COMPILATIONDB_USE_ABSPATH=False, | ||||
|     BUILD_DIR=fw_build_meta["build_dir"], | ||||
| @ -72,6 +73,8 @@ env = ENV.Clone( | ||||
|     _APP_ICONS=None, | ||||
| ) | ||||
| 
 | ||||
| env.PreConfigureFwEnvionment() | ||||
| 
 | ||||
| if env["IS_BASE_FIRMWARE"]: | ||||
|     env.Append( | ||||
|         FIRMWARE_BUILD_CFG="firmware", | ||||
| @ -100,6 +103,13 @@ lib_targets = env.BuildModules( | ||||
|     ], | ||||
| ) | ||||
| 
 | ||||
| # Configure firmware origin definitions | ||||
| env.Append( | ||||
|     CPPDEFINES=[ | ||||
|         env.subst("FW_ORIGIN_${FIRMWARE_ORIGIN}"), | ||||
|     ] | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| # Now, env is fully set up with everything to build apps | ||||
| fwenv = env.Clone(FW_ARTIFACTS=[]) | ||||
| @ -271,5 +281,6 @@ if should_gen_cdb_and_link_dir(fwenv, BUILD_TARGETS): | ||||
| 
 | ||||
| Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", fw_artifacts) | ||||
| 
 | ||||
| env.PostConfigureFwEnvionment() | ||||
| 
 | ||||
| Return("fwenv") | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| entry,status,name,type,params | ||||
| Version,+,28.0,, | ||||
| Version,+,28.1,, | ||||
| Header,+,applications/services/bt/bt_service/bt.h,, | ||||
| Header,+,applications/services/cli/cli.h,, | ||||
| Header,+,applications/services/cli/cli_vcp.h,, | ||||
| @ -2003,6 +2003,8 @@ Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" | ||||
| Function,+,version_get,const Version*, | ||||
| Function,+,version_get_builddate,const char*,const Version* | ||||
| Function,+,version_get_dirty_flag,_Bool,const Version* | ||||
| Function,+,version_get_firmware_origin,const char*,const Version* | ||||
| Function,+,version_get_git_origin,const char*,const Version* | ||||
| Function,+,version_get_gitbranch,const char*,const Version* | ||||
| Function,+,version_get_gitbranchnum,const char*,const Version* | ||||
| Function,+,version_get_githash,const char*,const Version* | ||||
|  | ||||
| 
 | 
| @ -1,5 +1,5 @@ | ||||
| entry,status,name,type,params | ||||
| Version,+,28.0,, | ||||
| Version,+,28.1,, | ||||
| Header,+,applications/services/bt/bt_service/bt.h,, | ||||
| Header,+,applications/services/cli/cli.h,, | ||||
| Header,+,applications/services/cli/cli_vcp.h,, | ||||
| @ -2945,6 +2945,8 @@ Function,-,vdprintf,int,"int, const char*, __gnuc_va_list" | ||||
| Function,+,version_get,const Version*, | ||||
| Function,+,version_get_builddate,const char*,const Version* | ||||
| Function,+,version_get_dirty_flag,_Bool,const Version* | ||||
| Function,+,version_get_firmware_origin,const char*,const Version* | ||||
| Function,+,version_get_git_origin,const char*,const Version* | ||||
| Function,+,version_get_gitbranch,const char*,const Version* | ||||
| Function,+,version_get_gitbranchnum,const char*,const Version* | ||||
| Function,+,version_get_githash,const char*,const Version* | ||||
|  | ||||
| 
 | 
| @ -26,7 +26,7 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { | ||||
|         property_value_out(&property_context, NULL, 2, "format", "minor", "1"); | ||||
|     } else { | ||||
|         property_value_out(&property_context, NULL, 3, "device", "info", "major", "2"); | ||||
|         property_value_out(&property_context, NULL, 3, "device", "info", "minor", "1"); | ||||
|         property_value_out(&property_context, NULL, 3, "device", "info", "minor", "2"); | ||||
|     } | ||||
| 
 | ||||
|     // Model name
 | ||||
| @ -173,6 +173,24 @@ void furi_hal_info_get(PropertyValueCallback out, char sep, void* context) { | ||||
|             &property_context, "%d", 3, "firmware", "api", "major", api_version_major); | ||||
|         property_value_out( | ||||
|             &property_context, "%d", 3, "firmware", "api", "minor", api_version_minor); | ||||
| 
 | ||||
|         property_value_out( | ||||
|             &property_context, | ||||
|             NULL, | ||||
|             3, | ||||
|             "firmware", | ||||
|             "origin", | ||||
|             "fork", | ||||
|             version_get_firmware_origin(firmware_version)); | ||||
| 
 | ||||
|         property_value_out( | ||||
|             &property_context, | ||||
|             NULL, | ||||
|             3, | ||||
|             "firmware", | ||||
|             "origin", | ||||
|             "git", | ||||
|             version_get_git_origin(firmware_version)); | ||||
|     } | ||||
| 
 | ||||
|     if(furi_hal_bt_is_alive()) { | ||||
|  | ||||
| @ -78,6 +78,11 @@ extern "C" { | ||||
| #define TOSTRING(x) STRINGIFY(x) | ||||
| #endif | ||||
| 
 | ||||
| #ifndef CONCATENATE | ||||
| #define CONCATENATE(a, b) CONCATENATE_(a, b) | ||||
| #define CONCATENATE_(a, b) a##b | ||||
| #endif | ||||
| 
 | ||||
| #ifndef REVERSE_BYTES_U32 | ||||
| #define REVERSE_BYTES_U32(x)                                                        \ | ||||
|     ((((x)&0x000000FF) << 24) | (((x)&0x0000FF00) << 8) | (((x)&0x00FF0000) >> 8) | \ | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| 
 | ||||
| #define VERSION_MAGIC (0xBE40u) | ||||
| #define VERSION_MAJOR (0x1u) | ||||
| #define VERSION_MINOR (0x0u) | ||||
| #define VERSION_MINOR (0x1u) | ||||
| 
 | ||||
| struct Version { | ||||
|     // Header
 | ||||
| @ -20,6 +20,9 @@ struct Version { | ||||
|     // Payload bits and pieces
 | ||||
|     const uint8_t target; | ||||
|     const bool build_is_dirty; | ||||
|     // v 1.1
 | ||||
|     const char* firmware_origin; | ||||
|     const char* git_origin; | ||||
| }; | ||||
| 
 | ||||
| /* version of current running firmware (bootloader/flipper) */ | ||||
| @ -37,6 +40,8 @@ static const Version version = { | ||||
|     , | ||||
|     .target = TARGET, | ||||
|     .build_is_dirty = BUILD_DIRTY, | ||||
|     .firmware_origin = FIRMWARE_ORIGIN, | ||||
|     .git_origin = GIT_ORIGIN, | ||||
| }; | ||||
| 
 | ||||
| const Version* version_get(void) { | ||||
| @ -71,3 +76,11 @@ uint8_t version_get_target(const Version* v) { | ||||
| bool version_get_dirty_flag(const Version* v) { | ||||
|     return v ? v->build_is_dirty : version.build_is_dirty; | ||||
| } | ||||
| 
 | ||||
| const char* version_get_firmware_origin(const Version* v) { | ||||
|     return v ? v->firmware_origin : version.firmware_origin; | ||||
| } | ||||
| 
 | ||||
| const char* version_get_git_origin(const Version* v) { | ||||
|     return v ? v->git_origin : version.git_origin; | ||||
| } | ||||
|  | ||||
| @ -82,6 +82,17 @@ uint8_t version_get_target(const Version* v); | ||||
|  */ | ||||
| bool version_get_dirty_flag(const Version* v); | ||||
| 
 | ||||
| /** 
 | ||||
|  * Get firmware origin. "Official" for mainline firmware, fork name for forks. | ||||
|  * Set by FIRMWARE_ORIGIN fbt argument. | ||||
| */ | ||||
| const char* version_get_firmware_origin(const Version* v); | ||||
| 
 | ||||
| /** 
 | ||||
|  * Get git repo origin | ||||
| */ | ||||
| const char* version_get_git_origin(const Version* v); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -23,6 +23,10 @@ class VersionData: | ||||
|     version: str | ||||
|     target: int | ||||
|     build_is_dirty: bool | ||||
|     # Since version 1.1 | ||||
|     firmware_origin: str = "" | ||||
|     git_origin: str = "" | ||||
|     # More fields may be added in the future | ||||
|     extra: Optional[Dict[str, str]] = field(default_factory=dict) | ||||
| 
 | ||||
| 
 | ||||
| @ -52,7 +56,7 @@ class VersionLoader: | ||||
| 
 | ||||
|         # Struct version 1.0 | ||||
|         extra_data = int(self.version_ptr[5].cast(self._uint_type)) | ||||
|         return VersionData( | ||||
|         version_data = VersionData( | ||||
|             git_hash=self.version_ptr[1].cast(self._cstr_type).string(), | ||||
|             git_branch=self.version_ptr[2].cast(self._cstr_type).string(), | ||||
|             build_date=self.version_ptr[3].cast(self._cstr_type).string(), | ||||
| @ -60,6 +64,12 @@ class VersionLoader: | ||||
|             target=extra_data & 0xF, | ||||
|             build_is_dirty=bool((extra_data >> 8) & 0xF), | ||||
|         ) | ||||
|         if minor >= 1: | ||||
|             version_data.firmware_origin = ( | ||||
|                 self.version_ptr[6].cast(self._cstr_type).string() | ||||
|             ) | ||||
|             version_data.git_origin = self.version_ptr[7].cast(self._cstr_type).string() | ||||
|         return version_data | ||||
| 
 | ||||
|     def load_unversioned(self): | ||||
|         """Parse an early version of the version struct.""" | ||||
| @ -104,6 +114,10 @@ class FlipperFwVersion(gdb.Command): | ||||
|         print(f"\tGit commit:  {v.version.git_hash}") | ||||
|         print(f"\tDirty:       {v.version.build_is_dirty}") | ||||
|         print(f"\tHW Target:   {v.version.target}") | ||||
|         if v.version.firmware_origin: | ||||
|             print(f"\tOrigin:      {v.version.firmware_origin}") | ||||
|         if v.version.git_origin: | ||||
|             print(f"\tGit origin:  {v.version.git_origin}") | ||||
| 
 | ||||
| 
 | ||||
| FlipperFwVersion() | ||||
|  | ||||
							
								
								
									
										67
									
								
								scripts/fbt_tools/fbt_envhooks.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								scripts/fbt_tools/fbt_envhooks.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,67 @@ | ||||
| """ | ||||
| 
 | ||||
| To introduce changes to firmware build environment that are specific to your fork: | ||||
| 
 | ||||
|     create a file "scripts/fbt/fbt_hooks.py" | ||||
| 
 | ||||
| With it, you can define functions that will be called at specific points of | ||||
| firmware build configuration, with environment as an argument. | ||||
| 
 | ||||
| For example, you can define a function `PreConfigureFwEnvionment(env)` that | ||||
| defines that will be a part of SDK build, so applications can | ||||
| use them for conditional compilation. | ||||
| 
 | ||||
| Here is a list of all available hooks: | ||||
| 
 | ||||
|     PreConfigureFwEnvionment(env): | ||||
|         This function is called on firmware environment (incl. updater) | ||||
|         before any major configuration is done. | ||||
| 
 | ||||
|     PostConfigureFwEnvionment(env): | ||||
|         This function is called on firmware environment (incl. updater) | ||||
|         after all configuration is done. | ||||
| 
 | ||||
|     PreConfigureUfbtEnvionment(env): | ||||
|         This function is called on ufbt environment at the beginning of | ||||
|         its configuration, before dist environment is created. | ||||
| 
 | ||||
|     PostConfigureUfbtEnvionment(env): | ||||
|         This function is called on ufbt dist_env environment after all | ||||
|         configuration and target creation is done. | ||||
| """ | ||||
| 
 | ||||
| 
 | ||||
| class DefaultFbtHooks: | ||||
|     pass | ||||
| 
 | ||||
| 
 | ||||
| try: | ||||
|     from fbt import fbt_hooks | ||||
| except ImportError: | ||||
|     fbt_hooks = DefaultFbtHooks() | ||||
| 
 | ||||
| 
 | ||||
| def generate(env): | ||||
|     stub_hook = lambda env: None | ||||
|     control_hooks = [ | ||||
|         "PreConfigureFwEnvionment", | ||||
|         "PostConfigureFwEnvionment", | ||||
|         "PreConfigureUfbtEnvionment", | ||||
|         "PostConfigureUfbtEnvionment", | ||||
|     ] | ||||
| 
 | ||||
|     if ( | ||||
|         isinstance(fbt_hooks, DefaultFbtHooks) | ||||
|         and env.subst("${FIRMWARE_ORIGIN}") != "Official" | ||||
|     ): | ||||
|         # If fbt_hooks.py is not present, but we are not building official firmware, | ||||
|         # create "scripts/fbt/fbt_hooks.py" to implement changes to firmware build environment. | ||||
|         pass | ||||
| 
 | ||||
|     for hook_name in control_hooks: | ||||
|         hook_fn = getattr(fbt_hooks, hook_name, stub_hook) | ||||
|         env.AddMethod(hook_fn, hook_name) | ||||
| 
 | ||||
| 
 | ||||
| def exists(): | ||||
|     return True | ||||
| @ -19,7 +19,9 @@ def generate(env): | ||||
|         BUILDERS={ | ||||
|             "VersionBuilder": Builder( | ||||
|                 action=Action( | ||||
|                     '${PYTHON3} "${VERSION_SCRIPT}" generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', | ||||
|                     '${PYTHON3} "${VERSION_SCRIPT}" generate ' | ||||
|                     "-t ${TARGET_HW} -fw-origin ${FIRMWARE_ORIGIN} " | ||||
|                     '-o ${TARGET.dir.posix} --dir "${ROOT_DIR}"', | ||||
|                     "${VERSIONCOMSTR}", | ||||
|                 ), | ||||
|                 emitter=version_emitter, | ||||
|  | ||||
| @ -98,6 +98,7 @@ env = core_env.Clone( | ||||
|         "fbt_apps", | ||||
|         "fbt_extapps", | ||||
|         "fbt_assets", | ||||
|         "fbt_envhooks", | ||||
|         ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), | ||||
|     ], | ||||
|     FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir, | ||||
| @ -117,6 +118,8 @@ env = core_env.Clone( | ||||
| wrap_tempfile(env, "LINKCOM") | ||||
| wrap_tempfile(env, "ARCOM") | ||||
| 
 | ||||
| env.PreConfigureUfbtEnvionment() | ||||
| 
 | ||||
| # print(env.Dump()) | ||||
| 
 | ||||
| # Dist env | ||||
| @ -474,3 +477,5 @@ dist_env.PhonyTarget( | ||||
|     "env", | ||||
|     "@echo $( ${FBT_SCRIPT_DIR}/toolchain/fbtenv.sh $)", | ||||
| ) | ||||
| 
 | ||||
| dist_env.PostConfigureUfbtEnvionment() | ||||
|  | ||||
| @ -45,8 +45,23 @@ class GitVersion: | ||||
|             "GIT_BRANCH": branch, | ||||
|             "VERSION": version, | ||||
|             "BUILD_DIRTY": dirty and 1 or 0, | ||||
|             "GIT_ORIGIN": ",".join(self._get_git_origins()), | ||||
|         } | ||||
| 
 | ||||
|     def _get_git_origins(self): | ||||
|         try: | ||||
|             remotes = self._exec_git("remote -v") | ||||
|         except subprocess.CalledProcessError: | ||||
|             return set() | ||||
|         origins = set() | ||||
|         for line in remotes.split("\n"): | ||||
|             if not line: | ||||
|                 continue | ||||
|             _, destination = line.split("\t") | ||||
|             url, _ = destination.split(" ") | ||||
|             origins.add(url) | ||||
|         return origins | ||||
| 
 | ||||
|     def _exec_git(self, args): | ||||
|         cmd = ["git"] | ||||
|         cmd.extend(args.split(" ")) | ||||
| @ -74,6 +89,13 @@ class Main(App): | ||||
|             help="hardware target", | ||||
|             required=True, | ||||
|         ) | ||||
|         self.parser_generate.add_argument( | ||||
|             "-fw-origin", | ||||
|             dest="firmware_origin", | ||||
|             type=str, | ||||
|             help="firmware origin", | ||||
|             required=True, | ||||
|         ) | ||||
|         self.parser_generate.add_argument("--dir", dest="sourcedir", required=True) | ||||
|         self.parser_generate.set_defaults(func=self.generate) | ||||
| 
 | ||||
| @ -89,6 +111,7 @@ class Main(App): | ||||
|             { | ||||
|                 "BUILD_DATE": build_date.strftime("%d-%m-%Y"), | ||||
|                 "TARGET": self.args.target, | ||||
|                 "FIRMWARE_ORIGIN": self.args.firmware_origin, | ||||
|             } | ||||
|         ) | ||||
| 
 | ||||
|  | ||||
| @ -236,6 +236,13 @@ vars.AddVariables( | ||||
|         help="Don't open browser after generating error repots", | ||||
|         default=False, | ||||
|     ), | ||||
|     ( | ||||
|         "FIRMWARE_ORIGIN", | ||||
|         "Firmware origin. 'Official' if follows upstream's API structure, otherwise fork name. " | ||||
|         " This will also create a C define FW_ORIGIN_<origin> so that " | ||||
|         " app can check what version it is being built for.", | ||||
|         "Official", | ||||
|     ), | ||||
| ) | ||||
| 
 | ||||
| Return("vars") | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 hedger
						hedger