[FL-3162] Moved ufbt to fbt codebase (#2520)
* scripts: moved ufbt code * ufbt: fixed tool path * ufbt: fixed linter/formatter target descriptions * scripts: ufbt: cleanup * fbt: moved fap launch target to tools; ufbt fixes * fbt: fixed missing headers from SDK * ufbt: removed debug output * ufbt: moved project template to main codebase * ufbt: fixed vscode_dist * ufbt: path naming changes * fbt: error message for older ufbt versions * ufbt: docs fixes * ufbt: fixed build dir location * fbt: fixes for extapps objcopy * fbt: extapps: removed extra debug output; fixed formatting * ufbt: handle launch target for multiple known apps * ufbt: dropping wrapper; linter fixes * ufbt: fixed boostrap path * ufbt: renamed entrypoint * ufbt: updated vscode config * ufbt: moved sconsign db location * ufbt: fixed sconsign path * fbt: SDK builders rework * fbt: reworked sdk packaging * ufbt: additional checks and state processing * ufbt: fixed sdk state file location * dist: not packaging pycache * dump commit json content * Github: more workflow debug prints * Github: fix incorrect commit meta extraction in get_env.py * ufbt, fbt: changed SConsEnvironmentError->StopError * fbtenv: no longer needs SCRIPT_PATH pre-set * ufbt: fixed sdk state check * scripts: exception fixes for storage.py * scripts: fbtenv: added FBT_TOOLCHAIN_PATH for on Windows for compat * ufbt: app template: creating .gitkeep for images folder * ufbt: app template: fixed .gitkeep creation * docs: formatting fixes for AppManifests; added link to ufbt * fbt: added link to PyPI for old ufbt versions * sdk: fixed dir component paths Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
393
scripts/ufbt/SConstruct
Normal file
393
scripts/ufbt/SConstruct
Normal file
@@ -0,0 +1,393 @@
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Node import FS
|
||||
from SCons.Errors import UserError
|
||||
|
||||
import os
|
||||
import multiprocessing
|
||||
import pathlib
|
||||
|
||||
SetOption("num_jobs", multiprocessing.cpu_count())
|
||||
SetOption("max_drift", 1)
|
||||
# SetOption("silent", False)
|
||||
|
||||
ufbt_state_dir = Dir(os.environ.get("UFBT_STATE_DIR", "#.ufbt"))
|
||||
ufbt_script_dir = Dir(os.environ.get("UFBT_SCRIPT_DIR"))
|
||||
|
||||
ufbt_current_sdk_dir = ufbt_state_dir.Dir("current")
|
||||
|
||||
SConsignFile(ufbt_state_dir.File(".sconsign.dblite").abspath)
|
||||
|
||||
ufbt_variables = SConscript("commandline.scons")
|
||||
|
||||
forward_os_env = {
|
||||
# Import PATH from OS env - scons doesn't do that by default
|
||||
"PATH": os.environ["PATH"],
|
||||
}
|
||||
|
||||
# Proxying environment to child processes & scripts
|
||||
variables_to_forward = [
|
||||
# CI/CD variables
|
||||
"WORKFLOW_BRANCH_OR_TAG",
|
||||
"DIST_SUFFIX",
|
||||
# Python & other tools
|
||||
"HOME",
|
||||
"APPDATA",
|
||||
"PYTHONHOME",
|
||||
"PYTHONNOUSERSITE",
|
||||
"TMP",
|
||||
"TEMP",
|
||||
# Colors for tools
|
||||
"TERM",
|
||||
]
|
||||
|
||||
if proxy_env := GetOption("proxy_env"):
|
||||
variables_to_forward.extend(proxy_env.split(","))
|
||||
|
||||
for env_value_name in variables_to_forward:
|
||||
if environ_value := os.environ.get(env_value_name, None):
|
||||
forward_os_env[env_value_name] = environ_value
|
||||
|
||||
# Core environment init - loads SDK state, sets up paths, etc.
|
||||
core_env = Environment(
|
||||
variables=ufbt_variables,
|
||||
ENV=forward_os_env,
|
||||
UFBT_STATE_DIR=ufbt_state_dir,
|
||||
UFBT_CURRENT_SDK_DIR=ufbt_current_sdk_dir,
|
||||
UFBT_SCRIPT_DIR=ufbt_script_dir,
|
||||
toolpath=[ufbt_current_sdk_dir.Dir("scripts/ufbt/site_tools")],
|
||||
tools=[
|
||||
"ufbt_state",
|
||||
("ufbt_help", {"vars": ufbt_variables}),
|
||||
],
|
||||
)
|
||||
|
||||
if "update" in BUILD_TARGETS:
|
||||
SConscript(
|
||||
"update.scons",
|
||||
exports={"core_env": core_env},
|
||||
)
|
||||
|
||||
if "purge" in BUILD_TARGETS:
|
||||
core_env.Execute(Delete(ufbt_state_dir))
|
||||
print("uFBT state purged")
|
||||
Exit(0)
|
||||
|
||||
# Now we can import stuff bundled with SDK - it was added to sys.path by ufbt_state
|
||||
|
||||
from fbt.util import (
|
||||
tempfile_arg_esc_func,
|
||||
single_quote,
|
||||
extract_abs_dir,
|
||||
extract_abs_dir_path,
|
||||
wrap_tempfile,
|
||||
path_as_posix,
|
||||
)
|
||||
from fbt.appmanifest import FlipperAppType
|
||||
from fbt.sdk.cache import SdkCache
|
||||
|
||||
# Base environment with all tools loaded from SDK
|
||||
env = core_env.Clone(
|
||||
toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")],
|
||||
tools=[
|
||||
"fbt_tweaks",
|
||||
(
|
||||
"crosscc",
|
||||
{
|
||||
"toolchain_prefix": "arm-none-eabi-",
|
||||
"versions": (" 10.3",),
|
||||
},
|
||||
),
|
||||
"fwbin",
|
||||
"python3",
|
||||
"sconsrecursiveglob",
|
||||
"sconsmodular",
|
||||
"ccache",
|
||||
"fbt_apps",
|
||||
"fbt_extapps",
|
||||
"fbt_assets",
|
||||
("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}),
|
||||
],
|
||||
FBT_FAP_DEBUG_ELF_ROOT=ufbt_state_dir.Dir("build"),
|
||||
TEMPFILE=TempFileMunge,
|
||||
MAXLINELENGTH=2048,
|
||||
PROGSUFFIX=".elf",
|
||||
TEMPFILEARGESCFUNC=tempfile_arg_esc_func,
|
||||
SINGLEQUOTEFUNC=single_quote,
|
||||
ABSPATHGETTERFUNC=extract_abs_dir_path,
|
||||
APPS=[],
|
||||
UFBT_API_VERSION=SdkCache(
|
||||
core_env.subst("$SDK_DEFINITION"), load_version_only=True
|
||||
).version,
|
||||
APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}\n\t\tTarget: ${TARGET_HW}, API: ${UFBT_API_VERSION}",
|
||||
)
|
||||
|
||||
wrap_tempfile(env, "LINKCOM")
|
||||
wrap_tempfile(env, "ARCOM")
|
||||
|
||||
# print(env.Dump())
|
||||
|
||||
# Dist env
|
||||
|
||||
dist_env = env.Clone(
|
||||
tools=[
|
||||
"fbt_dist",
|
||||
"fbt_debugopts",
|
||||
"openocd",
|
||||
"blackmagic",
|
||||
"jflash",
|
||||
"textfile",
|
||||
],
|
||||
ENV=os.environ,
|
||||
OPENOCD_OPTS=[
|
||||
"-f",
|
||||
"interface/stlink.cfg",
|
||||
"-c",
|
||||
"transport select hla_swd",
|
||||
"-f",
|
||||
"${FBT_DEBUG_DIR}/stm32wbx.cfg",
|
||||
"-c",
|
||||
"stm32wbx.cpu configure -rtos auto",
|
||||
],
|
||||
)
|
||||
|
||||
openocd_target = dist_env.OpenOCDFlash(
|
||||
dist_env["UFBT_STATE_DIR"].File("flash"),
|
||||
dist_env["FW_BIN"],
|
||||
OPENOCD_COMMAND=[
|
||||
"-c",
|
||||
"program ${SOURCE.posix} reset exit 0x08000000",
|
||||
],
|
||||
)
|
||||
dist_env.Alias("firmware_flash", openocd_target)
|
||||
dist_env.Alias("flash", openocd_target)
|
||||
if env["FORCE"]:
|
||||
env.AlwaysBuild(openocd_target)
|
||||
|
||||
firmware_debug = dist_env.PhonyTarget(
|
||||
"debug",
|
||||
"${GDBPYCOM}",
|
||||
source=dist_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE}",
|
||||
GDBREMOTE="${OPENOCD_GDB_PIPE}",
|
||||
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(dist_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
|
||||
)
|
||||
|
||||
dist_env.PhonyTarget(
|
||||
"blackmagic",
|
||||
"${GDBPYCOM}",
|
||||
source=dist_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(dist_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
|
||||
)
|
||||
|
||||
dist_env.PhonyTarget(
|
||||
"flash_blackmagic",
|
||||
"$GDB $GDBOPTS $SOURCES $GDBFLASH",
|
||||
source=dist_env["FW_ELF"],
|
||||
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
|
||||
GDBREMOTE="${BLACKMAGIC_ADDR}",
|
||||
GDBFLASH=[
|
||||
"-ex",
|
||||
"load",
|
||||
"-ex",
|
||||
"quit",
|
||||
],
|
||||
)
|
||||
|
||||
flash_usb_full = dist_env.UsbInstall(
|
||||
dist_env["UFBT_STATE_DIR"].File("usbinstall"),
|
||||
[],
|
||||
)
|
||||
dist_env.AlwaysBuild(flash_usb_full)
|
||||
dist_env.Alias("flash_usb", flash_usb_full)
|
||||
dist_env.Alias("flash_usb_full", flash_usb_full)
|
||||
|
||||
# App build environment
|
||||
|
||||
appenv = env.Clone(
|
||||
CCCOM=env["CCCOM"].replace("$CFLAGS", "$CFLAGS_APP $CFLAGS"),
|
||||
CXXCOM=env["CXXCOM"].replace("$CXXFLAGS", "$CXXFLAGS_APP $CXXFLAGS"),
|
||||
LINKCOM=env["LINKCOM"].replace("$LINKFLAGS", "$LINKFLAGS_APP $LINKFLAGS"),
|
||||
COMPILATIONDB_USE_ABSPATH=True,
|
||||
)
|
||||
|
||||
|
||||
original_app_dir = Dir(appenv.subst("$UFBT_APP_DIR"))
|
||||
app_mount_point = Dir("#/app/")
|
||||
app_mount_point.addRepository(original_app_dir)
|
||||
|
||||
appenv.LoadAppManifest(app_mount_point)
|
||||
appenv.PrepareApplicationsBuild()
|
||||
|
||||
#######################
|
||||
|
||||
apps_artifacts = appenv["EXT_APPS"]
|
||||
|
||||
apps_to_build_as_faps = [
|
||||
FlipperAppType.PLUGIN,
|
||||
FlipperAppType.EXTERNAL,
|
||||
]
|
||||
|
||||
known_extapps = [
|
||||
app
|
||||
for apptype in apps_to_build_as_faps
|
||||
for app in appenv["APPBUILD"].get_apps_of_type(apptype, True)
|
||||
]
|
||||
for app in known_extapps:
|
||||
app_artifacts = appenv.BuildAppElf(app)
|
||||
app_src_dir = extract_abs_dir(app_artifacts.app._appdir)
|
||||
app_artifacts.installer = [
|
||||
appenv.Install(app_src_dir.Dir("dist"), app_artifacts.compact),
|
||||
appenv.Install(app_src_dir.Dir("dist").Dir("debug"), app_artifacts.debug),
|
||||
]
|
||||
|
||||
if appenv["FORCE"]:
|
||||
appenv.AlwaysBuild([extapp.compact for extapp in apps_artifacts.values()])
|
||||
|
||||
# Final steps - target aliases
|
||||
|
||||
install_and_check = [
|
||||
(extapp.installer, extapp.validator) for extapp in apps_artifacts.values()
|
||||
]
|
||||
Alias(
|
||||
"faps",
|
||||
install_and_check,
|
||||
)
|
||||
Default(install_and_check)
|
||||
|
||||
# Compilation database
|
||||
|
||||
fwcdb = appenv.CompilationDatabase(
|
||||
original_app_dir.Dir(".vscode").File("compile_commands.json")
|
||||
)
|
||||
|
||||
AlwaysBuild(fwcdb)
|
||||
Precious(fwcdb)
|
||||
NoClean(fwcdb)
|
||||
if len(apps_artifacts):
|
||||
Default(fwcdb)
|
||||
|
||||
|
||||
# launch handler
|
||||
runnable_apps = appenv["APPBUILD"].get_apps_of_type(FlipperAppType.EXTERNAL, True)
|
||||
|
||||
app_to_launch = None
|
||||
if len(runnable_apps) == 1:
|
||||
app_to_launch = runnable_apps[0].appid
|
||||
elif len(runnable_apps) > 1:
|
||||
# more than 1 app - try to find one with matching id
|
||||
app_to_launch = appenv.subst("$APPID")
|
||||
|
||||
|
||||
def ambiguous_app_call(**kw):
|
||||
raise UserError(
|
||||
f"More than one app is runnable: {', '.join(app.appid for app in runnable_apps)}. Please specify an app with APPID=..."
|
||||
)
|
||||
|
||||
|
||||
if app_to_launch:
|
||||
appenv.AddAppLaunchTarget(app_to_launch, "launch")
|
||||
else:
|
||||
dist_env.PhonyTarget("launch", Action(ambiguous_app_call, None))
|
||||
|
||||
# cli handler
|
||||
|
||||
appenv.PhonyTarget(
|
||||
"cli",
|
||||
'${PYTHON3} "${FBT_SCRIPT_DIR}/serial_cli.py"',
|
||||
)
|
||||
|
||||
# Linter
|
||||
|
||||
dist_env.PhonyTarget(
|
||||
"lint",
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}",
|
||||
source=original_app_dir.File(".clang-format"),
|
||||
LINT_SOURCES=[original_app_dir],
|
||||
)
|
||||
|
||||
dist_env.PhonyTarget(
|
||||
"format",
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}",
|
||||
source=original_app_dir.File(".clang-format"),
|
||||
LINT_SOURCES=[original_app_dir],
|
||||
)
|
||||
|
||||
|
||||
# Prepare vscode environment
|
||||
def _path_as_posix(path):
|
||||
return pathlib.Path(path).as_posix()
|
||||
|
||||
|
||||
vscode_dist = []
|
||||
project_template_dir = dist_env["UFBT_SCRIPT_ROOT"].Dir("project_template")
|
||||
for template_file in project_template_dir.Dir(".vscode").glob("*"):
|
||||
vscode_dist.append(
|
||||
dist_env.Substfile(
|
||||
original_app_dir.Dir(".vscode").File(template_file.name),
|
||||
template_file,
|
||||
SUBST_DICT={
|
||||
"@UFBT_VSCODE_PATH_SEP@": os.path.pathsep,
|
||||
"@UFBT_TOOLCHAIN_ARM_TOOLCHAIN_DIR@": pathlib.Path(
|
||||
dist_env.WhereIs("arm-none-eabi-gcc")
|
||||
).parent.as_posix(),
|
||||
"@UFBT_TOOLCHAIN_GCC@": _path_as_posix(
|
||||
dist_env.WhereIs("arm-none-eabi-gcc")
|
||||
),
|
||||
"@UFBT_TOOLCHAIN_GDB_PY@": _path_as_posix(
|
||||
dist_env.WhereIs("arm-none-eabi-gdb-py")
|
||||
),
|
||||
"@UFBT_TOOLCHAIN_OPENOCD@": _path_as_posix(dist_env.WhereIs("openocd")),
|
||||
"@UFBT_APP_DIR@": _path_as_posix(original_app_dir.abspath),
|
||||
"@UFBT_ROOT_DIR@": _path_as_posix(Dir("#").abspath),
|
||||
"@UFBT_DEBUG_DIR@": dist_env["FBT_DEBUG_DIR"],
|
||||
"@UFBT_DEBUG_ELF_DIR@": _path_as_posix(
|
||||
dist_env["FBT_FAP_DEBUG_ELF_ROOT"].abspath
|
||||
),
|
||||
"@UFBT_FIRMWARE_ELF@": _path_as_posix(dist_env["FW_ELF"].abspath),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
for config_file in project_template_dir.glob(".*"):
|
||||
if isinstance(config_file, FS.Dir):
|
||||
continue
|
||||
vscode_dist.append(dist_env.Install(original_app_dir, config_file))
|
||||
|
||||
dist_env.Precious(vscode_dist)
|
||||
dist_env.NoClean(vscode_dist)
|
||||
dist_env.Alias("vscode_dist", vscode_dist)
|
||||
|
||||
|
||||
# Creating app from base template
|
||||
|
||||
dist_env.SetDefault(FBT_APPID=appenv.subst("$APPID") or "template")
|
||||
app_template_dist = []
|
||||
for template_file in project_template_dir.Dir("app_template").glob("*"):
|
||||
dist_file_name = dist_env.subst(template_file.name)
|
||||
if template_file.name.endswith(".png"):
|
||||
app_template_dist.append(
|
||||
dist_env.InstallAs(original_app_dir.File(dist_file_name), template_file)
|
||||
)
|
||||
else:
|
||||
app_template_dist.append(
|
||||
dist_env.Substfile(
|
||||
original_app_dir.File(dist_file_name),
|
||||
template_file,
|
||||
SUBST_DICT={
|
||||
"@FBT_APPID@": dist_env.subst("$FBT_APPID"),
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
AddPostAction(
|
||||
app_template_dist[-1],
|
||||
[
|
||||
Mkdir(original_app_dir.Dir("images")),
|
||||
Touch(original_app_dir.Dir("images").File(".gitkeep")),
|
||||
],
|
||||
)
|
||||
dist_env.Precious(app_template_dist)
|
||||
dist_env.NoClean(app_template_dist)
|
||||
dist_env.Alias("create", app_template_dist)
|
90
scripts/ufbt/commandline.scons
Normal file
90
scripts/ufbt/commandline.scons
Normal file
@@ -0,0 +1,90 @@
|
||||
AddOption(
|
||||
"--proxy-env",
|
||||
action="store",
|
||||
dest="proxy_env",
|
||||
default="",
|
||||
help="Comma-separated list of additional environment variables to pass to child SCons processes",
|
||||
)
|
||||
|
||||
AddOption(
|
||||
"--channel",
|
||||
action="store",
|
||||
dest="sdk_channel",
|
||||
choices=["dev", "rc", "release"],
|
||||
default="",
|
||||
help="Release channel to use for SDK",
|
||||
)
|
||||
|
||||
AddOption(
|
||||
"--branch",
|
||||
action="store",
|
||||
dest="sdk_branch",
|
||||
help="Custom main repo branch to use for SDK",
|
||||
)
|
||||
|
||||
AddOption(
|
||||
"--hw-target",
|
||||
action="store",
|
||||
dest="sdk_target",
|
||||
help="SDK Hardware target",
|
||||
)
|
||||
|
||||
vars = Variables("ufbt_options.py", ARGUMENTS)
|
||||
|
||||
vars.AddVariables(
|
||||
BoolVariable(
|
||||
"VERBOSE",
|
||||
help="Print full commands",
|
||||
default=False,
|
||||
),
|
||||
BoolVariable(
|
||||
"FORCE",
|
||||
help="Force target action (for supported targets)",
|
||||
default=False,
|
||||
),
|
||||
# These 2 are inherited from SDK
|
||||
# BoolVariable(
|
||||
# "DEBUG",
|
||||
# help="Enable debug build",
|
||||
# default=True,
|
||||
# ),
|
||||
# BoolVariable(
|
||||
# "COMPACT",
|
||||
# help="Optimize for size",
|
||||
# default=False,
|
||||
# ),
|
||||
PathVariable(
|
||||
"OTHER_ELF",
|
||||
help="Path to prebuilt ELF file to debug",
|
||||
validator=PathVariable.PathAccept,
|
||||
default="",
|
||||
),
|
||||
(
|
||||
"OPENOCD_OPTS",
|
||||
"Options to pass to OpenOCD",
|
||||
"",
|
||||
),
|
||||
(
|
||||
"BLACKMAGIC",
|
||||
"Blackmagic probe location",
|
||||
"auto",
|
||||
),
|
||||
(
|
||||
"OPENOCD_ADAPTER_SERIAL",
|
||||
"OpenOCD adapter serial number",
|
||||
"auto",
|
||||
),
|
||||
(
|
||||
"APPID",
|
||||
"Application id",
|
||||
"",
|
||||
),
|
||||
PathVariable(
|
||||
"UFBT_APP_DIR",
|
||||
help="Application dir to work with",
|
||||
validator=PathVariable.PathIsDir,
|
||||
default="",
|
||||
),
|
||||
)
|
||||
|
||||
Return("vars")
|
191
scripts/ufbt/project_template/.clang-format
Normal file
191
scripts/ufbt/project_template/.clang-format
Normal file
@@ -0,0 +1,191 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 99
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: false
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: true
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
RemoveBracesLLVM: false
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: false
|
||||
AfterForeachMacros: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: c++03
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
13
scripts/ufbt/project_template/.editorconfig
Normal file
13
scripts/ufbt/project_template/.editorconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
|
||||
[*.{cpp,h,c,py,sh}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[{Makefile,*.mk}]
|
||||
indent_size = tab
|
4
scripts/ufbt/project_template/.gitignore
vendored
Normal file
4
scripts/ufbt/project_template/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
dist/*
|
||||
.vscode
|
||||
.clang-format
|
||||
.editorconfig
|
14
scripts/ufbt/project_template/.vscode/c_cpp_properties.json
vendored
Normal file
14
scripts/ufbt/project_template/.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "main",
|
||||
"compilerPath": "@UFBT_TOOLCHAIN_GCC@",
|
||||
"intelliSenseMode": "gcc-arm",
|
||||
"compileCommands": "${workspaceFolder}/.vscode/compile_commands.json",
|
||||
"configurationProvider": "ms-vscode.cpptools",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "c++17"
|
||||
},
|
||||
],
|
||||
"version": 4
|
||||
}
|
18
scripts/ufbt/project_template/.vscode/extensions.json
vendored
Normal file
18
scripts/ufbt/project_template/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
|
||||
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"ms-python.black-formatter",
|
||||
"ms-vscode.cpptools",
|
||||
"amiralizadeh9480.cpp-helper",
|
||||
"marus25.cortex-debug",
|
||||
"zxh404.vscode-proto3",
|
||||
"augustocdias.tasks-shell-input"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
"twxs.cmake",
|
||||
"ms-vscode.cmake-tools"
|
||||
]
|
||||
}
|
98
scripts/ufbt/project_template/.vscode/launch.json
vendored
Normal file
98
scripts/ufbt/project_template/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
{
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"inputs": [
|
||||
// {
|
||||
// "id": "BLACKMAGIC",
|
||||
// "type": "command",
|
||||
// "command": "shellCommand.execute",
|
||||
// "args": {
|
||||
// "useSingleResult": true,
|
||||
// "env": {
|
||||
// "PATH": "${workspaceFolder};${env:PATH}"
|
||||
// },
|
||||
// "command": "./fbt get_blackmagic",
|
||||
// "description": "Get Blackmagic device",
|
||||
// }
|
||||
// },
|
||||
],
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach FW (ST-Link)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "@UFBT_FIRMWARE_ELF@",
|
||||
"request": "attach",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"device": "stlink",
|
||||
"svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"configFiles": [
|
||||
"interface/stlink.cfg",
|
||||
"@UFBT_DEBUG_DIR@/stm32wbx.cfg"
|
||||
],
|
||||
"postAttachCommands": [
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
],
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
{
|
||||
"name": "Attach FW (DAP)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "@UFBT_FIRMWARE_ELF@",
|
||||
"request": "attach",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "openocd",
|
||||
"device": "cmsis-dap",
|
||||
"svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"configFiles": [
|
||||
"interface/cmsis-dap.cfg",
|
||||
"@UFBT_DEBUG_DIR@/stm32wbx.cfg"
|
||||
],
|
||||
"postAttachCommands": [
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
],
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
// {
|
||||
// "name": "Attach FW (blackmagic)",
|
||||
// "cwd": "${workspaceFolder}",
|
||||
// "executable": "@UFBT_FIRMWARE_ELF@",
|
||||
// "request": "attach",
|
||||
// "type": "cortex-debug",
|
||||
// "servertype": "external",
|
||||
// "gdbTarget": "${input:BLACKMAGIC}",
|
||||
// "svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd",
|
||||
// "rtos": "FreeRTOS",
|
||||
// "postAttachCommands": [
|
||||
// "monitor swdp_scan",
|
||||
// "attach 1",
|
||||
// "set confirm off",
|
||||
// "set mem inaccessible-by-default off",
|
||||
// "source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
// "fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
// ]
|
||||
// // "showDevDebugOutput": "raw",
|
||||
// },
|
||||
{
|
||||
"name": "Attach FW (JLink)",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"executable": "@UFBT_FIRMWARE_ELF@",
|
||||
"request": "attach",
|
||||
"type": "cortex-debug",
|
||||
"servertype": "jlink",
|
||||
"interface": "swd",
|
||||
"device": "STM32WB55RG",
|
||||
"svdFile": "@UFBT_DEBUG_DIR@/STM32WB55_CM4.svd",
|
||||
"rtos": "FreeRTOS",
|
||||
"postAttachCommands": [
|
||||
"source @UFBT_DEBUG_DIR@/flipperapps.py",
|
||||
"fap-set-debug-elf-root @UFBT_DEBUG_ELF_DIR@"
|
||||
]
|
||||
// "showDevDebugOutput": "raw",
|
||||
},
|
||||
]
|
||||
}
|
20
scripts/ufbt/project_template/.vscode/settings.json
vendored
Normal file
20
scripts/ufbt/project_template/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"cortex-debug.enableTelemetry": false,
|
||||
"cortex-debug.variableUseNaturalFormat": false,
|
||||
"cortex-debug.showRTOS": true,
|
||||
"cortex-debug.armToolchainPath": "@UFBT_TOOLCHAIN_ARM_TOOLCHAIN_DIR@",
|
||||
"cortex-debug.openocdPath": "@UFBT_TOOLCHAIN_OPENOCD@",
|
||||
"cortex-debug.gdbPath": "@UFBT_TOOLCHAIN_GDB_PY@",
|
||||
"editor.formatOnSave": true,
|
||||
"files.associations": {
|
||||
"*.scons": "python",
|
||||
"SConscript": "python",
|
||||
"SConstruct": "python",
|
||||
"*.fam": "python"
|
||||
},
|
||||
"cortex-debug.registerUseNaturalFormat": false,
|
||||
"python.analysis.typeCheckingMode": "off",
|
||||
"[python]": {
|
||||
"editor.defaultFormatter": "ms-python.black-formatter"
|
||||
}
|
||||
}
|
54
scripts/ufbt/project_template/.vscode/tasks.json
vendored
Normal file
54
scripts/ufbt/project_template/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"options": {
|
||||
"env": {
|
||||
"PATH": "${workspaceFolder}@UFBT_VSCODE_PATH_SEP@${env:PATH}@UFBT_VSCODE_PATH_SEP@@UFBT_ROOT_DIR@"
|
||||
}
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Launch App on Flipper",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "ufbt launch"
|
||||
},
|
||||
{
|
||||
"label": "Build",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "ufbt"
|
||||
},
|
||||
{
|
||||
"label": "Flash FW (ST-Link)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "ufbt FORCE=1 flash"
|
||||
},
|
||||
// {
|
||||
// "label": "[NOTIMPL] Flash FW (blackmagic)",
|
||||
// "group": "build",
|
||||
// "type": "shell",
|
||||
// "command": "ufbt flash_blackmagic"
|
||||
// },
|
||||
// {
|
||||
// "label": "[NOTIMPL] Flash FW (JLink)",
|
||||
// "group": "build",
|
||||
// "type": "shell",
|
||||
// "command": "ufbt FORCE=1 jflash"
|
||||
// },
|
||||
{
|
||||
"label": "Flash FW (USB, with resources)",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "ufbt FORCE=1 flash_usb"
|
||||
},
|
||||
{
|
||||
"label": "Update uFBT SDK",
|
||||
"group": "build",
|
||||
"type": "shell",
|
||||
"command": "ufbt update"
|
||||
}
|
||||
]
|
||||
}
|
12
scripts/ufbt/project_template/app_template/${FBT_APPID}.c
Normal file
12
scripts/ufbt/project_template/app_template/${FBT_APPID}.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include <furi.h>
|
||||
|
||||
/* generated by fbt from .png files in images folder */
|
||||
#include <@FBT_APPID@_icons.h>
|
||||
|
||||
int32_t @FBT_APPID@_app(void* p) {
|
||||
UNUSED(p);
|
||||
FURI_LOG_I("TEST", "Hello world");
|
||||
FURI_LOG_I("TEST", "I'm @FBT_APPID@!");
|
||||
|
||||
return 0;
|
||||
}
|
BIN
scripts/ufbt/project_template/app_template/${FBT_APPID}.png
Normal file
BIN
scripts/ufbt/project_template/app_template/${FBT_APPID}.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 B |
17
scripts/ufbt/project_template/app_template/application.fam
Normal file
17
scripts/ufbt/project_template/app_template/application.fam
Normal file
@@ -0,0 +1,17 @@
|
||||
# For details & more options, see documentation/AppManifests.md in firmware repo
|
||||
|
||||
App(
|
||||
appid="@FBT_APPID@", # Must be unique
|
||||
name="App @FBT_APPID@", # Displayed in menus
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="@FBT_APPID@_app",
|
||||
stack_size=2 * 1024,
|
||||
fap_category="Misc",
|
||||
# Optional values
|
||||
# fap_version=(0, 1), # (major, minor)
|
||||
fap_icon="@FBT_APPID@.png", # 10x10 1-bit PNG
|
||||
# fap_description="A simple app",
|
||||
# fap_author="J. Doe",
|
||||
# fap_weburl="https://github.com/user/@FBT_APPID@",
|
||||
fap_icon_assets="images", # Image assets to compile for this application
|
||||
)
|
36
scripts/ufbt/site_init.py
Normal file
36
scripts/ufbt/site_init.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from SCons.Script import GetBuildFailures
|
||||
import SCons.Errors
|
||||
|
||||
import atexit
|
||||
from ansi.color import fg, fx
|
||||
|
||||
|
||||
def bf_to_str(bf):
|
||||
"""Convert an element of GetBuildFailures() to a string
|
||||
in a useful way."""
|
||||
|
||||
if bf is None: # unknown targets product None in list
|
||||
return "(unknown tgt)"
|
||||
elif isinstance(bf, SCons.Errors.StopError):
|
||||
return fg.yellow(str(bf))
|
||||
elif bf.node:
|
||||
return fg.yellow(str(bf.node)) + ": " + bf.errstr
|
||||
elif bf.filename:
|
||||
return fg.yellow(bf.filename) + ": " + bf.errstr
|
||||
return fg.yellow("unknown failure: ") + bf.errstr
|
||||
|
||||
|
||||
def display_build_status():
|
||||
"""Display the build status. Called by atexit.
|
||||
Here you could do all kinds of complicated things."""
|
||||
bf = GetBuildFailures()
|
||||
if bf:
|
||||
# bf is normally a list of build failures; if an element is None,
|
||||
# it's because of a target that scons doesn't know anything about.
|
||||
failures_message = "\n".join([bf_to_str(x) for x in bf if x is not None])
|
||||
print()
|
||||
print(fg.brightred(fx.bold("*" * 10 + " FBT ERRORS " + "*" * 10)))
|
||||
print(failures_message)
|
||||
|
||||
|
||||
atexit.register(display_build_status)
|
53
scripts/ufbt/site_tools/ufbt_help.py
Normal file
53
scripts/ufbt/site_tools/ufbt_help.py
Normal file
@@ -0,0 +1,53 @@
|
||||
targets_help = """Configuration variables:
|
||||
"""
|
||||
|
||||
tail_help = """
|
||||
|
||||
TASKS:
|
||||
(* - not supported yet)
|
||||
|
||||
launch:
|
||||
Upload and start application over USB
|
||||
vscode_dist:
|
||||
Configure application in current directory for development in VSCode.
|
||||
create:
|
||||
Copy application template to current directory. Set APPID=myapp to create an app with id 'myapp'.
|
||||
|
||||
Building:
|
||||
faps:
|
||||
Build all FAP apps
|
||||
fap_{APPID}, launch APPSRC={APPID}:
|
||||
Build FAP app with appid={APPID}; upload & start it over USB
|
||||
|
||||
Flashing & debugging:
|
||||
flash, flash_blackmagic, *jflash:
|
||||
Flash firmware to target using debug probe
|
||||
flash_usb, flash_usb_full:
|
||||
Install firmware using self-update package
|
||||
debug, debug_other, blackmagic:
|
||||
Start GDB
|
||||
|
||||
Other:
|
||||
cli:
|
||||
Open a Flipper CLI session over USB
|
||||
lint:
|
||||
run linter for C code
|
||||
format:
|
||||
reformat C code
|
||||
|
||||
How to create a new application:
|
||||
1. Create a new directory for your application and cd into it.
|
||||
2. Run `ufbt vscode_dist create APPID=myapp`
|
||||
3. In VSCode, open the folder and start editing.
|
||||
4. Run `ufbt launch` to build and upload your application.
|
||||
"""
|
||||
|
||||
|
||||
def generate(env, **kw):
|
||||
vars = kw["vars"]
|
||||
basic_help = vars.GenerateHelpText(env)
|
||||
env.Help(targets_help + basic_help + tail_help)
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
117
scripts/ufbt/site_tools/ufbt_state.py
Normal file
117
scripts/ufbt/site_tools/ufbt_state.py
Normal file
@@ -0,0 +1,117 @@
|
||||
from SCons.Errors import StopError
|
||||
from SCons.Warnings import warn, WarningOnByDefault
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import pathlib
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def _load_sdk_data(sdk_root):
|
||||
split_vars = {
|
||||
"cc_args",
|
||||
"cpp_args",
|
||||
"linker_args",
|
||||
"linker_libs",
|
||||
}
|
||||
subst_vars = split_vars | {
|
||||
"sdk_symbols",
|
||||
}
|
||||
sdk_data = {}
|
||||
with open(os.path.join(sdk_root, "sdk.opts")) as f:
|
||||
sdk_json_data = json.load(f)
|
||||
replacements = {
|
||||
sdk_json_data["app_ep_subst"]: "${APP_ENTRY}",
|
||||
sdk_json_data["sdk_path_subst"]: sdk_root.replace("\\", "/"),
|
||||
sdk_json_data["map_file_subst"]: "${TARGET}",
|
||||
}
|
||||
|
||||
def do_value_substs(src_value):
|
||||
if isinstance(src_value, str):
|
||||
return reduce(
|
||||
lambda acc, kv: acc.replace(*kv), replacements.items(), src_value
|
||||
)
|
||||
elif isinstance(src_value, list):
|
||||
return [do_value_substs(v) for v in src_value]
|
||||
else:
|
||||
return src_value
|
||||
|
||||
for key, value in sdk_json_data.items():
|
||||
if key in split_vars:
|
||||
value = value.split()
|
||||
if key in subst_vars:
|
||||
value = do_value_substs(value)
|
||||
sdk_data[key] = value
|
||||
|
||||
return sdk_data
|
||||
|
||||
|
||||
def _load_state_file(state_dir_node, filename: str) -> dict:
|
||||
state_path = os.path.join(state_dir_node.abspath, filename)
|
||||
if not os.path.exists(state_path):
|
||||
raise StopError(f"State file {state_path} not found")
|
||||
|
||||
with open(state_path, "r") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def generate(env, **kw):
|
||||
sdk_current_sdk_dir_node = env["UFBT_CURRENT_SDK_DIR"]
|
||||
|
||||
sdk_components_filename = kw.get("SDK_COMPONENTS", "components.json")
|
||||
ufbt_state_filename = kw.get("UFBT_STATE", "ufbt_state.json")
|
||||
|
||||
sdk_state = _load_state_file(sdk_current_sdk_dir_node, sdk_components_filename)
|
||||
ufbt_state = _load_state_file(sdk_current_sdk_dir_node, ufbt_state_filename)
|
||||
|
||||
if not (sdk_components := sdk_state.get("components", {})):
|
||||
raise StopError("SDK state file doesn't contain components data")
|
||||
|
||||
sdk_data = _load_sdk_data(
|
||||
sdk_current_sdk_dir_node.Dir(sdk_components["sdk_headers.dir"]).abspath
|
||||
)
|
||||
|
||||
if not sdk_state["meta"]["hw_target"].endswith(sdk_data["hardware"]):
|
||||
raise StopError("SDK state file doesn't match hardware target")
|
||||
|
||||
if sdk_state["meta"]["version"] != ufbt_state["version"]:
|
||||
warn(
|
||||
WarningOnByDefault,
|
||||
f"Version mismatch: SDK state vs uFBT: {sdk_state['meta']['version']} vs {ufbt_state['version']}",
|
||||
)
|
||||
|
||||
scripts_dir = sdk_current_sdk_dir_node.Dir(sdk_components["scripts.dir"])
|
||||
env.SetDefault(
|
||||
# Paths
|
||||
SDK_DEFINITION=env.File(sdk_data["sdk_symbols"]),
|
||||
FBT_DEBUG_DIR=pathlib.Path(
|
||||
sdk_current_sdk_dir_node.Dir(sdk_components["debug.dir"]).abspath
|
||||
).as_posix(),
|
||||
FBT_SCRIPT_DIR=scripts_dir,
|
||||
LIBPATH=sdk_current_sdk_dir_node.Dir(sdk_components["lib.dir"]),
|
||||
FW_ELF=sdk_current_sdk_dir_node.File(sdk_components["firmware.elf"]),
|
||||
FW_BIN=sdk_current_sdk_dir_node.File(sdk_components["full.bin"]),
|
||||
UPDATE_BUNDLE_DIR=sdk_current_sdk_dir_node.Dir(sdk_components["update.dir"]),
|
||||
SVD_FILE="${FBT_DEBUG_DIR}/STM32WB55_CM4.svd",
|
||||
# Build variables
|
||||
ROOT_DIR=env.Dir("#"),
|
||||
FIRMWARE_BUILD_CFG="firmware",
|
||||
TARGET_HW=int(sdk_data["hardware"]),
|
||||
CFLAGS_APP=sdk_data["cc_args"],
|
||||
CXXFLAGS_APP=sdk_data["cpp_args"],
|
||||
LINKFLAGS_APP=sdk_data["linker_args"],
|
||||
LIBS=sdk_data["linker_libs"],
|
||||
# ufbt state
|
||||
# UFBT_STATE_DIR=ufbt_state_dir_node,
|
||||
# UFBT_CURRENT_SDK_DIR=sdk_current_sdk_dir_node,
|
||||
UFBT_STATE=ufbt_state,
|
||||
UFBT_BOOTSTRAP_SCRIPT="${UFBT_SCRIPT_DIR}/bootstrap.py",
|
||||
UFBT_SCRIPT_ROOT=scripts_dir.Dir("ufbt"),
|
||||
)
|
||||
|
||||
sys.path.insert(0, env["FBT_SCRIPT_DIR"].abspath)
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
37
scripts/ufbt/update.scons
Normal file
37
scripts/ufbt/update.scons
Normal file
@@ -0,0 +1,37 @@
|
||||
from SCons.Errors import StopError
|
||||
|
||||
Import("core_env")
|
||||
|
||||
update_env = core_env.Clone(
|
||||
toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")],
|
||||
tools=["python3"],
|
||||
)
|
||||
print("Updating SDK...")
|
||||
ufbt_state = update_env["UFBT_STATE"]
|
||||
|
||||
update_args = [
|
||||
"--ufbt-dir",
|
||||
f'"{update_env["UFBT_STATE_DIR"]}"',
|
||||
]
|
||||
|
||||
if branch_name := GetOption("sdk_branch"):
|
||||
update_args.extend(["--branch", branch_name])
|
||||
elif channel_name := GetOption("sdk_channel"):
|
||||
update_args.extend(["--channel", channel_name])
|
||||
elif branch_name := ufbt_state.get("branch", None):
|
||||
update_args.extend(["--branch", branch_name])
|
||||
elif channel_name := ufbt_state.get("channel", None):
|
||||
update_args.extend(["--channel", channel_name])
|
||||
else:
|
||||
raise StopError("No branch or channel specified for SDK update")
|
||||
|
||||
if hw_target := GetOption("sdk_target"):
|
||||
update_args.extend(["--hw-target", hw_target])
|
||||
else:
|
||||
update_args.extend(["--hw-target", ufbt_state["hw_target"]])
|
||||
|
||||
update_env.Replace(UPDATE_ARGS=update_args)
|
||||
result = update_env.Execute(
|
||||
update_env.subst('$PYTHON3 "$UFBT_BOOTSTRAP_SCRIPT" $UPDATE_ARGS'),
|
||||
)
|
||||
Exit(result)
|
Reference in New Issue
Block a user