firmware.scons 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. Import("ENV", "fw_build_meta")
  2. import os
  3. from fbt.util import link_dir
  4. # Building initial C environment for libs
  5. env = ENV.Clone(
  6. tools=["compilation_db", "fwbin", "fbt_apps"],
  7. COMPILATIONDB_USE_ABSPATH=True,
  8. BUILD_DIR=fw_build_meta["build_dir"],
  9. IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware",
  10. FW_FLAVOR=fw_build_meta["flavor"],
  11. PLUGIN_ELF_DIR="${BUILD_DIR}",
  12. LIB_DIST_DIR="${BUILD_DIR}/lib",
  13. LINT_SOURCES=[
  14. "applications",
  15. ],
  16. LIBPATH=[
  17. "${LIB_DIST_DIR}",
  18. ],
  19. CPPPATH=[
  20. "#/core",
  21. "#/applications",
  22. "#/firmware/targets/f${TARGET_HW}/ble_glue",
  23. "#/firmware/targets/f${TARGET_HW}/fatfs",
  24. "#/firmware/targets/f${TARGET_HW}/furi_hal",
  25. "#/firmware/targets/f${TARGET_HW}/Inc",
  26. "#/firmware/targets/furi_hal_include",
  27. ],
  28. # Specific flags for building libraries - always do optimized builds
  29. FW_LIB_OPTS={
  30. "Default": {
  31. "CCFLAGS": [
  32. "-Os",
  33. ],
  34. "CPPDEFINES": [
  35. "NDEBUG",
  36. "FURI_NDEBUG",
  37. ],
  38. # You can add other entries named after libraries
  39. # If they are present, they have precedence over Default
  40. },
  41. # for furi_check to respect build type
  42. "core": {
  43. "CCFLAGS": [
  44. "-Os",
  45. ],
  46. "CPPDEFINES": [
  47. "NDEBUG",
  48. "FURI_DEBUG" if ENV["DEBUG"] else "FURI_NDEBUG",
  49. ],
  50. },
  51. },
  52. )
  53. def ApplyLibFlags(env):
  54. flags_to_apply = env["FW_LIB_OPTS"].get(
  55. env.get("FW_LIB_NAME"),
  56. env["FW_LIB_OPTS"]["Default"],
  57. )
  58. # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply)
  59. env.MergeFlags(flags_to_apply)
  60. env.AddMethod(ApplyLibFlags)
  61. Export("env")
  62. if not env["VERBOSE"]:
  63. env.SetDefault(
  64. HEXCOMSTR="\tHEX\t${TARGET}",
  65. BINCOMSTR="\tBIN\t${TARGET}",
  66. DFUCOMSTR="\tDFU\t${TARGET}",
  67. OPENOCDCOMSTR="\tFLASH\t${SOURCE}",
  68. )
  69. if fw_build_meta["type"] == "updater":
  70. env.Append(
  71. FIRMWARE_BUILD_CFG="updater",
  72. RAM_EXEC=True,
  73. CPPDEFINES=[
  74. "FURI_RAM_EXEC",
  75. ],
  76. )
  77. else:
  78. env.Append(
  79. FIRMWARE_BUILD_CFG="firmware",
  80. RAM_EXEC=False,
  81. )
  82. # print(env.Dump())
  83. # Invoke child SCopscripts to populate global `env` + build their own part of the code
  84. lib_targets = env.BuildModules(
  85. [
  86. "lib",
  87. "assets",
  88. "firmware",
  89. "core",
  90. ],
  91. )
  92. # Now, env is fully set up with everything to build apps
  93. fwenv = env.Clone()
  94. # Set up additional app-specific build flags
  95. SConscript("site_scons/firmwareopts.scons", exports={"ENV": fwenv})
  96. # Set up app configuration
  97. if env["IS_BASE_FIRMWARE"]:
  98. fwenv.Append(APPS=fwenv["FIRMWARE_APPS"].get(fwenv.subst("$FIRMWARE_APP_SET")))
  99. else:
  100. fwenv.Append(APPS=["updater"])
  101. if extra_int_apps := GetOption("extra_int_apps"):
  102. fwenv.Append(APPS=extra_int_apps.split(","))
  103. fwenv.LoadApplicationManifests()
  104. fwenv.PrepareApplicationsBuild()
  105. # Build external apps
  106. extapps = SConscript("applications/extapps.scons", exports={"ENV": fwenv})
  107. # Add preprocessor definitions for current set of apps
  108. fwenv.AppendUnique(
  109. CPPDEFINES=fwenv["APPBUILD"].get_apps_cdefs(),
  110. )
  111. # Build applications.c for selected services & apps
  112. # Depends on virtual value-only node, so it only gets rebuilt when set of apps changes
  113. apps_c = fwenv.ApplicationsC(
  114. "applications/applications.c",
  115. Value(fwenv["APPS"]),
  116. )
  117. # Adding dependency on manifest files so apps.c is rebuilt when any manifest is changed
  118. fwenv.Depends(apps_c, fwenv.GlobRecursive("*.fam", "applications"))
  119. sources = [apps_c]
  120. # Gather sources only from app folders from current configuration
  121. for app_folder in fwenv["APPBUILD"].get_builtin_app_folders():
  122. sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder))
  123. fwenv.AppendUnique(
  124. LINKFLAGS=[
  125. "-specs=nano.specs",
  126. "-specs=nosys.specs",
  127. "-Wl,--start-group",
  128. "-lstdc++",
  129. "-lsupc++",
  130. "-Wl,--end-group",
  131. "-Wl,--gc-sections",
  132. "-Wl,--undefined=uxTopUsedPriority",
  133. "-Wl,--wrap,_malloc_r",
  134. "-Wl,--wrap,_free_r",
  135. "-Wl,--wrap,_calloc_r",
  136. "-Wl,--wrap,_realloc_r",
  137. "-u",
  138. "_printf_float",
  139. "-n",
  140. ],
  141. )
  142. # Debug
  143. # print(fwenv.Dump())
  144. # Full firmware definition
  145. fwelf = fwenv["FW_ELF"] = fwenv.Program(
  146. "${FIRMWARE_BUILD_CFG}",
  147. sources,
  148. LIBS=[
  149. "flipper${TARGET_HW}",
  150. "core",
  151. "freertos",
  152. "stm32cubewb",
  153. "hwdrivers",
  154. "fatfs",
  155. "littlefs",
  156. "subghz",
  157. "flipperformat",
  158. "toolbox",
  159. "microtar",
  160. "usb_stm32",
  161. "st25rfal002",
  162. "infrared",
  163. "appframe",
  164. "assets",
  165. "misc",
  166. # 2nd round
  167. "flipperformat",
  168. "toolbox",
  169. "mbedtls",
  170. "loclass",
  171. ],
  172. )
  173. def link_elf_dir_as_latest(env, elf_target):
  174. # Ugly way to check if updater-related targets were requested
  175. elf_dir = elf_target.Dir(".")
  176. explicitly_building_updater = False
  177. # print("BUILD_TARGETS:", ','.join(BUILD_TARGETS))
  178. for build_target in BUILD_TARGETS:
  179. # print(">>> ", str(build_target))
  180. if "updater" in str(build_target):
  181. explicitly_building_updater = True
  182. latest_dir = env.Dir("#build/latest")
  183. link_this_dir = True
  184. if explicitly_building_updater:
  185. # If updater is explicitly requested, link to the latest updater
  186. # Otherwise, link to the latest firmware
  187. link_this_dir = not env["IS_BASE_FIRMWARE"]
  188. if link_this_dir:
  189. print(f"Setting {elf_dir} as latest built dir")
  190. return link_dir(latest_dir.abspath, elf_dir.abspath, env["PLATFORM"] == "win32")
  191. def link_latest_dir(env, target, source):
  192. return link_elf_dir_as_latest(env, target[0])
  193. # Make it depend on everything child builders returned
  194. Depends(fwelf, lib_targets)
  195. AddPostAction(fwelf, fwenv["APPBUILD_DUMP"])
  196. AddPostAction(fwelf, Action("@$SIZECOM"))
  197. AddPostAction(fwelf, Action(link_latest_dir, None))
  198. link_dir_command = fwenv["LINK_DIR_CMD"] = fwenv.PhonyTarget(
  199. fwenv.subst("${FIRMWARE_BUILD_CFG}_latest"),
  200. Action(lambda target, source, env: link_elf_dir_as_latest(env, source[0]), None),
  201. source=fwelf,
  202. )
  203. fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}")
  204. fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}")
  205. fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}")
  206. Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu)
  207. fwdump = fwenv.ObjDump("${FIRMWARE_BUILD_CFG}")
  208. Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_list", fwdump)
  209. # Compile DB generation
  210. fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_commands.json")
  211. fwenv.Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb)
  212. artifacts = [
  213. fwhex,
  214. fwbin,
  215. fwdfu,
  216. env["FW_VERSION_JSON"],
  217. fwcdb,
  218. ]
  219. fwenv["FW_ARTIFACTS"] = artifacts
  220. Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", artifacts)
  221. Return("fwenv")