fbt fixes for mfbt pt2 (#1951)

* fbt: split sdk management code
* scripts: fixed import handling
* fbt: sdk: reformatted paths
* scrips: dist: bundling libs as a build artifact
* fbt: sdk: better path management
* typo fix
* fbt: sdk: minor path handling fixes
* toolchain: fixed windows toolchain download
* fbt: minor refactorin
* fbt: moved sdk management code to extapps.scons
* fbt: fixed sdk symbols header path; disabled -fstack-usage
* fbt: changed pathing for .py scripts
* fbt: changed SDK_HEADERS pathing; added libusb to SDK; added icon_i.h to SDK; added hw target to SDK meta
* fbt: added libusb headers to SDK
* picopass: include cleanup; api: added subghz/registry.h; api: added mbedtls to exported headers
* picopass: fixed formatting
* fbt: fixed COPRO_ASSETS_SCRIPT
* sdk: added basic infrared apis
* toolchain: added ufbt to list of legal fbtenv callers; updated error messages
* fbt: changed manifest collection & icon processing code
* fbt: simpler srcdir lookup
* toolchain: path management fixes; fbt: fixes for fap private libs paths
* scripts: toolchain: reworked download on Windows
* toolchain: v17
* scripts: added colorlog for logging
* Github: fix unit tests

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
hedger
2022-11-02 19:15:40 +04:00
committed by GitHub
parent abfa804ae0
commit ebc2b66372
42 changed files with 459 additions and 235 deletions

View File

@@ -37,6 +37,21 @@ def _get_tool_version(env, tool):
def generate(env, **kw):
if not env.get("VERBOSE", False):
env.SetDefault(
CCCOMSTR="\tCC\t${SOURCE}",
CXXCOMSTR="\tCPP\t${SOURCE}",
ASCOMSTR="\tASM\t${SOURCE}",
ARCOMSTR="\tAR\t${TARGET}",
RANLIBCOMSTR="\tRANLIB\t${TARGET}",
LINKCOMSTR="\tLINK\t${TARGET}",
INSTALLSTR="\tINSTALL\t${TARGET}",
APPSCOMSTR="\tAPPS\t${TARGET}",
VERSIONCOMSTR="\tVERSION\t${TARGET}",
STRIPCOMSTR="\tSTRIP\t${TARGET}",
OBJDUMPCOMSTR="\tOBJDUMP\t${TARGET}",
)
for orig_tool in (asm, gcc, gxx, ar, gnulink, strip, gdb, objdump):
orig_tool.generate(env)
env.SetDefault(

View File

@@ -2,7 +2,7 @@ from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Warnings import warn, WarningOnByDefault
import SCons
import os.path
from ansi.color import fg
from fbt.appmanifest import (
FlipperAppType,
@@ -16,21 +16,20 @@ from fbt.appmanifest import (
# AppBuildset env["APPBUILD"] - contains subset of apps, filtered for current config
def LoadApplicationManifests(env):
appmgr = env["APPMGR"] = AppManager()
for app_dir, _ in env["APPDIRS"]:
app_dir_node = env.Dir("#").Dir(app_dir)
def LoadAppManifest(env, entry):
try:
APP_MANIFEST_NAME = "application.fam"
manifest_glob = entry.glob(APP_MANIFEST_NAME)
if len(manifest_glob) == 0:
raise FlipperManifestException(
f"Folder {entry}: manifest {APP_MANIFEST_NAME} is missing"
)
for entry in app_dir_node.glob("*", ondisk=True, source=True):
if isinstance(entry, SCons.Node.FS.Dir) and not str(entry).startswith("."):
try:
app_manifest_file_path = os.path.join(
entry.abspath, "application.fam"
)
appmgr.load_manifest(app_manifest_file_path, entry)
env.Append(PY_LINT_SOURCES=[app_manifest_file_path])
except FlipperManifestException as e:
warn(WarningOnByDefault, str(e))
app_manifest_file_path = manifest_glob[0].rfile().abspath
env["APPMGR"].load_manifest(app_manifest_file_path, entry)
env.Append(PY_LINT_SOURCES=[app_manifest_file_path])
except FlipperManifestException as e:
warn(WarningOnByDefault, str(e))
def PrepareApplicationsBuild(env):
@@ -46,12 +45,12 @@ def PrepareApplicationsBuild(env):
def DumpApplicationConfig(target, source, env):
print(f"Loaded {len(env['APPMGR'].known_apps)} app definitions.")
print("Firmware modules configuration:")
print(fg.boldgreen("Firmware modules configuration:"))
for apptype in FlipperAppType:
app_sublist = env["APPBUILD"].get_apps_of_type(apptype)
if app_sublist:
print(
f"{apptype.value}:\n\t",
fg.green(f"{apptype.value}:\n\t"),
", ".join(app.appid for app in app_sublist),
)
@@ -65,8 +64,11 @@ def build_apps_c(target, source, env):
def generate(env):
env.AddMethod(LoadApplicationManifests)
env.AddMethod(LoadAppManifest)
env.AddMethod(PrepareApplicationsBuild)
env.SetDefault(
APPMGR=AppManager(),
)
env.Append(
BUILDERS={

View File

@@ -1,11 +1,10 @@
import SCons
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Node.FS import File
from SCons.Errors import SConsEnvironmentError
import os
import subprocess
from ansi.color import fg
def icons_emitter(target, source, env):
@@ -13,7 +12,6 @@ def icons_emitter(target, source, env):
target[0].File(env.subst("${ICON_FILE_NAME}.c")),
target[0].File(env.subst("${ICON_FILE_NAME}.h")),
]
source = env.GlobRecursive("*.*", env["ICON_SRC_DIR"])
return target, source
@@ -86,7 +84,7 @@ def proto_ver_generator(target, source, env):
)
except (subprocess.CalledProcessError, EnvironmentError) as e:
# Not great, not terrible
print("Git: fetch failed")
print(fg.boldred("Git: fetch failed"))
try:
git_describe = _invoke_git(
@@ -94,10 +92,8 @@ def proto_ver_generator(target, source, env):
source_dir=src_dir,
)
except (subprocess.CalledProcessError, EnvironmentError) as e:
print("Git: describe failed")
Exit("git error")
raise SConsEnvironmentError("Git: describe failed")
# print("describe=", git_describe)
git_major, git_minor = git_describe.split(".")
version_file_data = (
"#pragma once",
@@ -116,7 +112,7 @@ def CompileIcons(env, target_dir, source_dir, *, icon_bundle_name="assets_icons"
icons = env.IconBuilder(
target_dir,
ICON_SRC_DIR=source_dir,
source_dir,
ICON_FILE_NAME=icon_bundle_name,
)
env.Depends(icons, icons_src)
@@ -125,8 +121,8 @@ def CompileIcons(env, target_dir, source_dir, *, icon_bundle_name="assets_icons"
def generate(env):
env.SetDefault(
ASSETS_COMPILER="${ROOT_DIR.abspath}/scripts/assets.py",
NANOPB_COMPILER="${ROOT_DIR.abspath}/lib/nanopb/generator/nanopb_generator.py",
ASSETS_COMPILER="${FBT_SCRIPT_DIR}/assets.py",
NANOPB_COMPILER="${ROOT_DIR}/lib/nanopb/generator/nanopb_generator.py",
)
env.AddMethod(CompileIcons)
@@ -143,7 +139,7 @@ def generate(env):
BUILDERS={
"IconBuilder": Builder(
action=Action(
'${PYTHON3} "${ASSETS_COMPILER}" icons ${ICON_SRC_DIR} ${TARGET.dir} --filename ${ICON_FILE_NAME}',
'${PYTHON3} "${ASSETS_COMPILER}" icons ${ABSPATHGETTERFUNC(SOURCE)} ${TARGET.dir} --filename ${ICON_FILE_NAME}',
"${ICONSCOMSTR}",
),
emitter=icons_emitter,

View File

@@ -103,7 +103,7 @@ def DistCommand(env, name, source, **kw):
command = env.Command(
target,
source,
'@${PYTHON3} "${ROOT_DIR.abspath}/scripts/sconsdist.py" copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}',
'@${PYTHON3} "${DIST_SCRIPT}" copy -p ${DIST_PROJECTS} -s "${DIST_SUFFIX}" ${DIST_EXTRA}',
**kw,
)
env.Pseudo(target)
@@ -121,6 +121,9 @@ def generate(env):
env.SetDefault(
COPRO_MCU_FAMILY="STM32WB5x",
SELFUPDATE_SCRIPT="${FBT_SCRIPT_DIR}/selfupdate.py",
DIST_SCRIPT="${FBT_SCRIPT_DIR}/sconsdist.py",
COPRO_ASSETS_SCRIPT="${FBT_SCRIPT_DIR}/assets.py",
)
env.Append(
@@ -128,7 +131,7 @@ def generate(env):
"UsbInstall": Builder(
action=[
Action(
'${PYTHON3} "${ROOT_DIR.abspath}/scripts/selfupdate.py" dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}/update.fuf'
'${PYTHON3} "${SELFUPDATE_SCRIPT}" dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}/update.fuf'
),
Touch("${TARGET}"),
]
@@ -136,7 +139,7 @@ def generate(env):
"CoproBuilder": Builder(
action=Action(
[
'${PYTHON3} "${ROOT_DIR.abspath}/scripts/assets.py" '
'${PYTHON3} "${COPRO_ASSETS_SCRIPT}" '
"copro ${COPRO_CUBE_DIR} "
"${TARGET} ${COPRO_MCU_FAMILY} "
"--cube_ver=${COPRO_CUBE_VERSION} "

View File

@@ -1,15 +1,18 @@
import shutil
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Errors import UserError
import SCons.Warnings
import os
import pathlib
from fbt.elfmanifest import assemble_manifest_data
from fbt.appmanifest import FlipperApplication, FlipperManifestException
from fbt.sdk.cache import SdkCache
from fbt.util import extract_abs_dir_path
import os
import pathlib
import itertools
import shutil
from ansi.color import fg
@@ -62,7 +65,7 @@ def BuildAppElf(env, app):
lib_src_root_path = os.path.join(app_work_dir, "lib", lib_def.name)
app_env.AppendUnique(
CPPPATH=list(
app_env.Dir(lib_src_root_path).Dir(incpath).srcnode()
app_env.Dir(lib_src_root_path).Dir(incpath).srcnode().rfile().abspath
for incpath in lib_def.fap_include_paths
),
)
@@ -82,7 +85,12 @@ def BuildAppElf(env, app):
*lib_def.cflags,
],
CPPDEFINES=lib_def.cdefines,
CPPPATH=list(map(app._appdir.Dir, lib_def.cincludes)),
CPPPATH=list(
map(
lambda cpath: extract_abs_dir_path(app._appdir.Dir(cpath)),
lib_def.cincludes,
)
),
)
lib = private_lib_env.StaticLibrary(
@@ -157,7 +165,6 @@ def prepare_app_metadata(target, source, env):
app = env["APP"]
meta_file_name = source[0].path + ".meta"
with open(meta_file_name, "wb") as f:
# f.write(f"hello this is {app}")
f.write(
assemble_manifest_data(
app_manifest=app,
@@ -236,7 +243,10 @@ def fap_dist_action(target, source, env):
def generate(env, **kw):
env.SetDefault(EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR"))
env.SetDefault(
EXT_APPS_WORK_DIR=kw.get("EXT_APPS_WORK_DIR"),
APP_RUN_SCRIPT="${FBT_SCRIPT_DIR}/runfap.py",
)
if not env["VERBOSE"]:
env.SetDefault(

View File

@@ -46,7 +46,9 @@ def prebuild_sdk_emitter(target, source, env):
def prebuild_sdk_create_origin_file(target, source, env):
mega_file = env.subst("${TARGET}.c", target=target[0])
with open(mega_file, "wt") as sdk_c:
sdk_c.write("\n".join(f"#include <{h.path}>" for h in env["SDK_HEADERS"]))
sdk_c.write(
"\n".join(f"#include <{h.srcnode().path}>" for h in env["SDK_HEADERS"])
)
class SdkMeta:
@@ -62,18 +64,25 @@ class SdkMeta:
"cc_args": self._wrap_scons_vars("$CCFLAGS $_CCCOMCOM"),
"cpp_args": self._wrap_scons_vars("$CXXFLAGS $CCFLAGS $_CCCOMCOM"),
"linker_args": self._wrap_scons_vars("$LINKFLAGS"),
"linker_script": self.env.subst("${LINKER_SCRIPT_PATH}"),
"linker_libs": self.env.subst("${LIBS}"),
"app_ep_subst": self.env.subst("${APP_ENTRY}"),
"sdk_path_subst": self.env.subst("${SDK_DIR_SUBST}"),
"hardware": self.env.subst("${TARGET_HW}"),
}
with open(json_manifest_path, "wt") as f:
json.dump(meta_contents, f, indent=4)
def _wrap_scons_vars(self, vars: str):
expanded_vars = self.env.subst(vars, target=Entry("dummy"))
expanded_vars = self.env.subst(
vars,
target=Entry("dummy"),
)
return expanded_vars.replace("\\", "/")
class SdkTreeBuilder:
SDK_DIR_SUBST = "SDK_ROOT_DIR"
SDK_APP_EP_SUBST = "SDK_APP_EP_SUBST"
def __init__(self, env, target, source) -> None:
self.env = env
@@ -87,6 +96,11 @@ class SdkTreeBuilder:
self.sdk_root_dir = target[0].Dir(".")
self.sdk_deploy_dir = self.sdk_root_dir.Dir(self.target_sdk_dir_name)
self.sdk_env = self.env.Clone(
APP_ENTRY=self.SDK_APP_EP_SUBST,
SDK_DIR_SUBST=self.SDK_DIR_SUBST,
)
def _parse_sdk_depends(self):
deps_file = self.source[0]
with open(deps_file.path, "rt") as deps_f:
@@ -95,38 +109,36 @@ class SdkTreeBuilder:
self.header_depends = list(
filter(lambda fname: fname.endswith(".h"), depends.split()),
)
self.header_depends.append(self.env.subst("${LINKER_SCRIPT_PATH}"))
self.header_depends.append(self.env.subst("${SDK_DEFINITION}"))
self.header_depends.append(self.sdk_env.subst("${LINKER_SCRIPT_PATH}"))
self.header_depends.append(self.sdk_env.subst("${SDK_DEFINITION}"))
self.header_dirs = sorted(
set(map(os.path.normpath, map(os.path.dirname, self.header_depends)))
)
def _generate_sdk_meta(self):
filtered_paths = [self.target_sdk_dir_name]
filtered_paths = ["."]
full_fw_paths = list(
map(
os.path.normpath,
(self.env.Dir(inc_dir).relpath for inc_dir in self.env["CPPPATH"]),
(
self.sdk_env.Dir(inc_dir).relpath
for inc_dir in self.sdk_env["CPPPATH"]
),
)
)
sdk_dirs = ", ".join(f"'{dir}'" for dir in self.header_dirs)
filtered_paths.extend(
map(
self.build_sdk_file_path,
filter(lambda path: path in sdk_dirs, full_fw_paths),
)
filter(lambda path: path in sdk_dirs, full_fw_paths),
)
filtered_paths = list(map(self.build_sdk_file_path, filtered_paths))
sdk_env = self.env.Clone()
sdk_env.Replace(
self.sdk_env.Replace(
CPPPATH=filtered_paths,
LINKER_SCRIPT=self.env.subst("${APP_LINKER_SCRIPT}"),
ORIG_LINKER_SCRIPT_PATH=self.env["LINKER_SCRIPT_PATH"],
LINKER_SCRIPT_PATH=self.build_sdk_file_path("${ORIG_LINKER_SCRIPT_PATH}"),
)
meta = SdkMeta(sdk_env, self)
meta = SdkMeta(self.sdk_env, self)
meta.save_to(self.target[0].path)
def build_sdk_file_path(self, orig_path: str) -> str:
@@ -211,7 +223,7 @@ def validate_sdk_cache(source, target, env):
current_sdk = SdkCollector()
current_sdk.process_source_file_for_sdk(source[0].path)
for h in env["SDK_HEADERS"]:
current_sdk.add_header_to_sdk(pathlib.Path(h.path).as_posix())
current_sdk.add_header_to_sdk(pathlib.Path(h.srcnode().path).as_posix())
sdk_cache = SdkCache(target[0].path)
sdk_cache.validate_api(current_sdk.get_api())

View File

@@ -12,11 +12,14 @@ def version_emitter(target, source, env):
def generate(env):
env.SetDefault(
VERSION_SCRIPT="${FBT_SCRIPT_DIR}/version.py",
)
env.Append(
BUILDERS={
"VersionBuilder": Builder(
action=Action(
'${PYTHON3} "${ROOT_DIR.abspath}/scripts/version.py" generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir "${ROOT_DIR}"',
'${PYTHON3} "${VERSION_SCRIPT}" generate -t ${TARGET_HW} -o ${TARGET.dir.posix} --dir "${ROOT_DIR}"',
"${VERSIONCOMSTR}",
),
emitter=version_emitter,

View File

@@ -8,7 +8,8 @@ __NM_ARM_BIN = "arm-none-eabi-nm"
def generate(env):
env.SetDefault(
BIN2DFU="${ROOT_DIR.abspath}/scripts/bin2dfu.py",
BIN2DFU="${FBT_SCRIPT_DIR}/bin2dfu.py",
BIN_SIZE_SCRIPT="${FBT_SCRIPT_DIR}/fwsize.py",
OBJCOPY=__OBJCOPY_ARM_BIN, # FIXME
NM=__NM_ARM_BIN, # FIXME
)