ufbt_state.py 3.6 KB

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