fbt_hwtarget.py 4.7 KB

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