fbt_hwtarget.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import json
  2. class HardwareTargetLoader:
  3. def __init__(self, env, target_scons_dir, target_id):
  4. self.env = env
  5. self.target_scons_dir = target_scons_dir
  6. self.target_dir = self._getTargetDir(target_id)
  7. # self.target_id = target_id
  8. self.layered_target_dirs = []
  9. self.include_paths = []
  10. self.sdk_header_paths = []
  11. self.startup_script = None
  12. self.linker_script_flash = None
  13. self.linker_script_ram = None
  14. self.linker_script_app = None
  15. self.sdk_symbols = None
  16. self.linker_dependencies = []
  17. self.excluded_sources = []
  18. self.excluded_headers = []
  19. self.excluded_modules = []
  20. self._processTargetDefinitions(target_id)
  21. def _getTargetDir(self, target_id):
  22. return self.target_scons_dir.Dir(f"f{target_id}")
  23. def _loadDescription(self, target_id):
  24. target_json_file = self._getTargetDir(target_id).File("target.json")
  25. if not target_json_file.exists():
  26. raise Exception(f"Target file {target_json_file} does not exist")
  27. with open(target_json_file.get_abspath(), "r") as f:
  28. vals = json.load(f)
  29. return vals
  30. def _processTargetDefinitions(self, target_id):
  31. self.layered_target_dirs.append(f"targets/f{target_id}")
  32. config = self._loadDescription(target_id)
  33. for path_list in ("include_paths", "sdk_header_paths"):
  34. getattr(self, path_list).extend(
  35. f"#/firmware/targets/f{target_id}/{p}"
  36. for p in config.get(path_list, [])
  37. )
  38. self.excluded_sources.extend(config.get("excluded_sources", []))
  39. self.excluded_headers.extend(config.get("excluded_headers", []))
  40. self.excluded_modules.extend(config.get("excluded_modules", []))
  41. file_attrs = (
  42. # (name, use_src_node)
  43. ("startup_script", False),
  44. ("linker_script_flash", True),
  45. ("linker_script_ram", True),
  46. ("linker_script_app", True),
  47. ("sdk_symbols", True),
  48. )
  49. for attr_name, use_src_node in file_attrs:
  50. if (val := config.get(attr_name)) and not getattr(self, attr_name):
  51. node = self.env.File(f"firmware/targets/f{target_id}/{val}")
  52. if use_src_node:
  53. node = node.srcnode()
  54. setattr(self, attr_name, node)
  55. for attr_name in ("linker_dependencies",):
  56. if (val := config.get(attr_name)) and not getattr(self, attr_name):
  57. setattr(self, attr_name, val)
  58. if inherited_target := config.get("inherit", None):
  59. self._processTargetDefinitions(inherited_target)
  60. def gatherSources(self):
  61. sources = [self.startup_script]
  62. seen_filenames = set(self.excluded_sources)
  63. # print("Layers: ", self.layered_target_dirs)
  64. for target_dir in self.layered_target_dirs:
  65. accepted_sources = list(
  66. filter(
  67. lambda f: f.name not in seen_filenames,
  68. self.env.GlobRecursive("*.c", target_dir),
  69. )
  70. )
  71. seen_filenames.update(f.name for f in accepted_sources)
  72. sources.extend(accepted_sources)
  73. # print(f"Found {len(sources)} sources: {list(f.name for f in sources)}")
  74. return sources
  75. def gatherSdkHeaders(self):
  76. sdk_headers = []
  77. seen_sdk_headers = set(self.excluded_headers)
  78. for sdk_path in self.sdk_header_paths:
  79. # dirty, but fast - exclude headers from overlayed targets by name
  80. # proper way would be to use relative paths, but names will do for now
  81. for header in self.env.GlobRecursive("*.h", sdk_path, "*_i.h"):
  82. if header.name not in seen_sdk_headers:
  83. seen_sdk_headers.add(header.name)
  84. sdk_headers.append(header)
  85. return sdk_headers
  86. def ConfigureForTarget(env, target_id):
  87. target_loader = HardwareTargetLoader(env, env.Dir("#/firmware/targets"), target_id)
  88. env.Replace(
  89. TARGET_CFG=target_loader,
  90. SDK_DEFINITION=target_loader.sdk_symbols,
  91. SKIP_MODULES=target_loader.excluded_modules,
  92. )
  93. env.Append(
  94. CPPPATH=target_loader.include_paths,
  95. SDK_HEADERS=target_loader.gatherSdkHeaders(),
  96. )
  97. def ApplyLibFlags(env):
  98. flags_to_apply = env["FW_LIB_OPTS"].get(
  99. env.get("FW_LIB_NAME"),
  100. env["FW_LIB_OPTS"]["Default"],
  101. )
  102. # print("Flags for ", env.get("FW_LIB_NAME", "Default"), flags_to_apply)
  103. env.MergeFlags(flags_to_apply)
  104. def generate(env):
  105. env.AddMethod(ConfigureForTarget)
  106. env.AddMethod(ApplyLibFlags)
  107. def exists(env):
  108. return True