| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- from dataclasses import dataclass, field
- from os.path import dirname
- from SCons.Node import NodeList
- from SCons.Warnings import warn, WarningOnByDefault
- from SCons.Errors import UserError
- Import("ENV")
- from fbt.appmanifest import FlipperAppType
- appenv = ENV["APPENV"] = ENV.Clone(
- tools=[
- "fbt_extapps",
- "fbt_assets",
- "fbt_sdk",
- ],
- RESOURCES_ROOT=ENV.Dir("#/assets/resources"),
- )
- appenv.Replace(
- LINKER_SCRIPT_PATH=appenv["APP_LINKER_SCRIPT_PATH"],
- )
- appenv.AppendUnique(
- CCFLAGS=[
- "-ggdb3",
- "-mword-relocations",
- "-mlong-calls",
- "-fno-common",
- "-nostdlib",
- "-fvisibility=hidden",
- ],
- LINKFLAGS=[
- "-Ur",
- "-Wl,-Ur",
- # "-Wl,--orphan-handling=error",
- "-Bsymbolic",
- "-nostartfiles",
- "-mlong-calls",
- "-fno-common",
- "-nostdlib",
- "-Wl,--gc-sections",
- "-Wl,--no-export-dynamic",
- "-fvisibility=hidden",
- "-Wl,-e${APP_ENTRY}",
- "-Xlinker",
- "-Map=${TARGET}.map",
- "-specs=nano.specs",
- "-specs=nosys.specs",
- ],
- LIBS=[
- "m",
- "gcc",
- "stdc++",
- "supc++",
- ],
- )
- @dataclass
- class FlipperExtAppBuildArtifacts:
- application_map: dict = field(default_factory=dict)
- resources_dist: NodeList = field(default_factory=NodeList)
- sdk_tree: NodeList = field(default_factory=NodeList)
- apps_to_build_as_faps = [
- FlipperAppType.PLUGIN,
- FlipperAppType.EXTERNAL,
- FlipperAppType.DEBUG,
- ]
- known_extapps = [
- app
- for apptype in apps_to_build_as_faps
- for app in appenv["APPBUILD"].get_apps_of_type(apptype, True)
- ]
- # Ugly access to global option
- if extra_app_list := GetOption("extra_ext_apps"):
- known_extapps.extend(map(appenv["APPMGR"].get, extra_app_list.split(",")))
- incompatible_apps = []
- for app in known_extapps:
- if not app.supports_hardware_target(appenv.subst("f${TARGET_HW}")):
- incompatible_apps.append(app)
- continue
- appenv.BuildAppElf(app)
- extapps = FlipperExtAppBuildArtifacts()
- extapps.application_map = appenv["EXT_APPS"]
- if incompatible_apps:
- warn(
- WarningOnByDefault,
- f"Skipping build of {len(incompatible_apps)} incompatible app(s): "
- + ", ".join(f"'{app.name}' (id '{app.appid}')" for app in incompatible_apps),
- )
- if appenv["FORCE"]:
- appenv.AlwaysBuild(
- list(app_artifact.compact for app_artifact in extapps.application_map.values())
- )
- Alias(
- "faps",
- list(app_artifact.validator for app_artifact in extapps.application_map.values()),
- )
- extapps.resources_dist = appenv.FapDist(appenv["RESOURCES_ROOT"], [])
- if appsrc := appenv.subst("$APPSRC"):
- deploy_sources, flipp_dist_paths, validators = [], [], []
- run_script_extra_ars = ""
- def _add_dist_targets(app_artifacts):
- validators.append(app_artifacts.validator)
- for _, ext_path in app_artifacts.dist_entries:
- deploy_sources.append(app_artifacts.compact)
- flipp_dist_paths.append(f"/ext/{ext_path}")
- return app_artifacts
- def _add_host_app_to_targets(host_app):
- artifacts_app_to_run = appenv["EXT_APPS"].get(host_app.appid, None)
- _add_dist_targets(artifacts_app_to_run)
- for plugin in host_app._plugins:
- _add_dist_targets(appenv["EXT_APPS"].get(plugin.appid, None))
- artifacts_app_to_run = appenv.GetExtAppByIdOrPath(appsrc)
- if artifacts_app_to_run.app.apptype == FlipperAppType.PLUGIN:
- # We deploy host app instead
- host_app = appenv["APPMGR"].get(artifacts_app_to_run.app.requires[0])
- if host_app:
- if host_app.apptype == FlipperAppType.EXTERNAL:
- _add_host_app_to_targets(host_app)
- else:
- # host app is a built-in app
- run_script_extra_ars = f"-a {host_app.name}"
- _add_dist_targets(artifacts_app_to_run)
- else:
- raise UserError("Host app is unknown")
- else:
- _add_host_app_to_targets(artifacts_app_to_run.app)
- # print(deploy_sources, flipp_dist_paths)
- appenv.PhonyTarget(
- "launch_app",
- '${PYTHON3} "${APP_RUN_SCRIPT}" ${EXTRA_ARGS} -s ${SOURCES} -t ${FLIPPER_FILE_TARGETS}',
- source=deploy_sources,
- FLIPPER_FILE_TARGETS=flipp_dist_paths,
- EXTRA_ARGS=run_script_extra_ars,
- )
- appenv.Alias("launch_app", validators)
- # SDK management
- sdk_origin_path = "${BUILD_DIR}/sdk_origin"
- sdk_source = appenv.SDKPrebuilder(
- sdk_origin_path,
- # Deps on root SDK headers and generated files
- (appenv["SDK_HEADERS"], appenv["FW_ASSETS_HEADERS"]),
- )
- # Extra deps on headers included in deeper levels
- # Available on second and subsequent builds
- Depends(sdk_source, appenv.ProcessSdkDepends(f"{sdk_origin_path}.d"))
- appenv["SDK_DIR"] = appenv.Dir("${BUILD_DIR}/sdk")
- sdk_tree = appenv.SDKTree(appenv["SDK_DIR"], sdk_origin_path)
- # AlwaysBuild(sdk_tree)
- Alias("sdk_tree", sdk_tree)
- extapps.sdk_tree = sdk_tree
- sdk_apicheck = appenv.SDKSymUpdater(appenv["SDK_DEFINITION"], sdk_origin_path)
- Precious(sdk_apicheck)
- NoClean(sdk_apicheck)
- AlwaysBuild(sdk_apicheck)
- Alias("sdk_check", sdk_apicheck)
- sdk_apisyms = appenv.SDKSymGenerator(
- "${BUILD_DIR}/assets/compiled/symbols.h", appenv["SDK_DEFINITION"]
- )
- Alias("api_syms", sdk_apisyms)
- ENV.Replace(
- SDK_APISYMS=sdk_apisyms,
- _APP_ICONS=appenv["_APP_ICONS"],
- )
- if appenv["FORCE"]:
- appenv.AlwaysBuild(sdk_source, sdk_tree, sdk_apicheck, sdk_apisyms)
- Return("extapps")
|