firmware.scons 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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", "openocd", "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. sources = [apps_c]
  118. # Gather sources only from app folders from current configuration
  119. for app_folder in fwenv["APPBUILD"].get_builtin_app_folders():
  120. sources += fwenv.GlobRecursive("*.c*", os.path.join("applications", app_folder))
  121. fwenv.AppendUnique(
  122. LINKFLAGS=[
  123. "-specs=nano.specs",
  124. "-specs=nosys.specs",
  125. "-Wl,--start-group",
  126. "-lstdc++",
  127. "-lsupc++",
  128. "-Wl,--end-group",
  129. "-Wl,--gc-sections",
  130. "-Wl,--undefined=uxTopUsedPriority",
  131. "-Wl,--wrap,_malloc_r",
  132. "-Wl,--wrap,_free_r",
  133. "-Wl,--wrap,_calloc_r",
  134. "-Wl,--wrap,_realloc_r",
  135. "-u",
  136. "_printf_float",
  137. "-n",
  138. ],
  139. )
  140. # Debug
  141. # print(fwenv.Dump())
  142. # Full firmware definition
  143. fwelf = fwenv["FW_ELF"] = fwenv.Program(
  144. "${FIRMWARE_BUILD_CFG}",
  145. sources,
  146. LIBS=[
  147. "flipper${TARGET_HW}",
  148. "core",
  149. "freertos",
  150. "stm32cubewb",
  151. "hwdrivers",
  152. "fatfs",
  153. "littlefs",
  154. "subghz",
  155. "flipperformat",
  156. "toolbox",
  157. "microtar",
  158. "usb_stm32",
  159. "st25rfal002",
  160. "infrared",
  161. "appframe",
  162. "assets",
  163. "misc",
  164. # 2nd round
  165. "flipperformat",
  166. "toolbox",
  167. "mbedtls",
  168. "loclass",
  169. ],
  170. )
  171. def link_elf_dir_as_latest(env, elf_target):
  172. # Ugly way to check if updater-related targets were requested
  173. elf_dir = elf_target.Dir(".")
  174. explicitly_building_updater = False
  175. # print("BUILD_TARGETS:", ','.join(BUILD_TARGETS))
  176. for build_target in BUILD_TARGETS:
  177. # print(">>> ", str(build_target))
  178. if "updater" in str(build_target):
  179. explicitly_building_updater = True
  180. latest_dir = env.Dir("#build/latest")
  181. link_this_dir = True
  182. if explicitly_building_updater:
  183. # If updater is explicitly requested, link to the latest updater
  184. # Otherwise, link to the latest firmware
  185. link_this_dir = not env["IS_BASE_FIRMWARE"]
  186. if link_this_dir:
  187. print(f"Setting {elf_dir} as latest built dir")
  188. return link_dir(latest_dir.abspath, elf_dir.abspath, env["PLATFORM"] == "win32")
  189. def link_latest_dir(env, target, source):
  190. return link_elf_dir_as_latest(env, target[0])
  191. # Make it depend on everything child builders returned
  192. Depends(fwelf, lib_targets)
  193. AddPostAction(fwelf, fwenv["APPBUILD_DUMP"])
  194. AddPostAction(fwelf, Action("@$SIZECOM"))
  195. AddPostAction(fwelf, Action(link_latest_dir, None))
  196. link_dir_command = fwenv["LINK_DIR_CMD"] = fwenv.PhonyTarget(
  197. "${FIRMWARE_BUILD_CFG}" + "_latest",
  198. Action(lambda target, source, env: link_elf_dir_as_latest(env, source[0]), None),
  199. source=fwelf,
  200. )
  201. fwhex = fwenv["FW_HEX"] = fwenv.HEXBuilder("${FIRMWARE_BUILD_CFG}")
  202. fwbin = fwenv["FW_BIN"] = fwenv.BINBuilder("${FIRMWARE_BUILD_CFG}")
  203. fwdfu = fwenv["FW_DFU"] = fwenv.DFUBuilder("${FIRMWARE_BUILD_CFG}")
  204. Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_dfu", fwdfu)
  205. fwdump = fwenv.ObjDump("${FIRMWARE_BUILD_CFG}")
  206. Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_list", fwdump)
  207. # Additional FW-related pseudotargets
  208. flash = fwenv["FW_FLASH"] = fwenv.OpenOCDFlash(
  209. "#build/oocd-${FIRMWARE_BUILD_CFG}-flash.flag",
  210. "${FIRMWARE_BUILD_CFG}",
  211. OPENOCD_COMMAND='-c "program ${SOURCE.posix} reset exit ${IMAGE_BASE_ADDRESS}"',
  212. )
  213. if fwenv["FORCE"]:
  214. fwenv.AlwaysBuild(flash)
  215. fwenv.Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_flash", flash)
  216. if fwenv["IS_BASE_FIRMWARE"]:
  217. fwenv.Alias("flash", flash)
  218. # Compile DB generation
  219. fwcdb = fwenv["FW_CDB"] = fwenv.CompilationDatabase("compile_commands.json")
  220. fwenv.Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_cdb", fwcdb)
  221. artifacts = [
  222. fwhex,
  223. fwbin,
  224. fwdfu,
  225. env["FW_VERSION_JSON"],
  226. fwcdb,
  227. ]
  228. fwenv["FW_ARTIFACTS"] = artifacts
  229. Alias(fwenv["FIRMWARE_BUILD_CFG"] + "_all", artifacts)
  230. Return("fwenv")