ufbt_state.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. from SCons.Errors import StopError
  2. from SCons.Warnings import warn, WarningOnByDefault
  3. import json
  4. import os
  5. import sys
  6. import pathlib
  7. from functools import reduce
  8. def _load_sdk_data(sdk_root):
  9. split_vars = {
  10. "cc_args",
  11. "cpp_args",
  12. "linker_args",
  13. "linker_libs",
  14. }
  15. subst_vars = split_vars | {
  16. "sdk_symbols",
  17. }
  18. sdk_data = {}
  19. with open(os.path.join(sdk_root, "sdk.opts")) as f:
  20. sdk_json_data = json.load(f)
  21. replacements = {
  22. sdk_json_data["app_ep_subst"]: "${APP_ENTRY}",
  23. sdk_json_data["sdk_path_subst"]: sdk_root.replace("\\", "/"),
  24. sdk_json_data["map_file_subst"]: "${TARGET}",
  25. }
  26. def do_value_substs(src_value):
  27. if isinstance(src_value, str):
  28. return reduce(
  29. lambda acc, kv: acc.replace(*kv), replacements.items(), src_value
  30. )
  31. elif isinstance(src_value, list):
  32. return [do_value_substs(v) for v in src_value]
  33. else:
  34. return src_value
  35. for key, value in sdk_json_data.items():
  36. if key in split_vars:
  37. value = value.split()
  38. if key in subst_vars:
  39. value = do_value_substs(value)
  40. sdk_data[key] = value
  41. return sdk_data
  42. def _load_state_file(state_dir_node, filename: str) -> dict:
  43. state_path = os.path.join(state_dir_node.abspath, filename)
  44. if not os.path.exists(state_path):
  45. raise StopError(f"State file {state_path} not found")
  46. with open(state_path, "r") as f:
  47. return json.load(f)
  48. def generate(env, **kw):
  49. sdk_current_sdk_dir_node = env["UFBT_CURRENT_SDK_DIR"]
  50. sdk_components_filename = kw.get("SDK_COMPONENTS", "components.json")
  51. ufbt_state_filename = kw.get("UFBT_STATE", "ufbt_state.json")
  52. sdk_state = _load_state_file(sdk_current_sdk_dir_node, sdk_components_filename)
  53. ufbt_state = _load_state_file(sdk_current_sdk_dir_node, ufbt_state_filename)
  54. if not (sdk_components := sdk_state.get("components", {})):
  55. raise StopError("SDK state file doesn't contain components data")
  56. sdk_data = _load_sdk_data(
  57. sdk_current_sdk_dir_node.Dir(sdk_components["sdk_headers.dir"]).abspath
  58. )
  59. if not sdk_state["meta"]["hw_target"].endswith(sdk_data["hardware"]):
  60. raise StopError("SDK state file doesn't match hardware target")
  61. scripts_dir = sdk_current_sdk_dir_node.Dir(sdk_components["scripts.dir"])
  62. env.SetDefault(
  63. # Paths
  64. SDK_DEFINITION=env.File(sdk_data["sdk_symbols"]),
  65. FBT_DEBUG_DIR=pathlib.Path(
  66. sdk_current_sdk_dir_node.Dir(sdk_components["debug.dir"]).abspath
  67. ).as_posix(),
  68. FBT_SCRIPT_DIR=scripts_dir,
  69. LIBPATH=sdk_current_sdk_dir_node.Dir(sdk_components["lib.dir"]),
  70. FW_ELF=sdk_current_sdk_dir_node.File(sdk_components["firmware.elf"]),
  71. FW_BIN=sdk_current_sdk_dir_node.File(sdk_components["full.bin"]),
  72. UPDATE_BUNDLE_DIR=sdk_current_sdk_dir_node.Dir(sdk_components["update.dir"]),
  73. SVD_FILE="${FBT_DEBUG_DIR}/STM32WB55_CM4.svd",
  74. # Build variables
  75. ROOT_DIR=env.Dir("#"),
  76. FIRMWARE_BUILD_CFG="firmware",
  77. TARGET_HW=int(sdk_data["hardware"]),
  78. CFLAGS_APP=sdk_data["cc_args"],
  79. CXXFLAGS_APP=sdk_data["cpp_args"],
  80. LINKFLAGS_APP=sdk_data["linker_args"],
  81. LIBS=sdk_data["linker_libs"],
  82. # ufbt state
  83. # UFBT_STATE_DIR=ufbt_state_dir_node,
  84. # UFBT_CURRENT_SDK_DIR=sdk_current_sdk_dir_node,
  85. UFBT_STATE=ufbt_state,
  86. UFBT_BOOTSTRAP_SCRIPT="${UFBT_SCRIPT_DIR}/bootstrap.py",
  87. UFBT_SCRIPT_ROOT=scripts_dir.Dir("ufbt"),
  88. )
  89. sys.path.insert(0, env["FBT_SCRIPT_DIR"].abspath)
  90. def exists(env):
  91. return True