gen_defines.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. # Sphinx extension to integrate defines into the Sphinx Build
  2. #
  3. # Runs after the IDF dummy project has been built
  4. #
  5. # Then emits the new 'idf-defines-generated' event which has a dictionary of raw text define values
  6. # that other extensions can use to generate relevant data.
  7. import glob
  8. import os
  9. import pprint
  10. import subprocess
  11. import re
  12. def generate_defines(app, project_description):
  13. sdk_config_path = os.path.join(project_description["build_dir"], "config")
  14. # Parse kconfig macros to pass into doxygen
  15. #
  16. # TODO: this should use the set of "config which can't be changed" eventually,
  17. # not the header
  18. defines = get_defines(os.path.join(project_description["build_dir"],
  19. "config", "sdkconfig.h"), sdk_config_path)
  20. # Add all SOC _caps.h headers and kconfig macros to the defines
  21. #
  22. # kind of a hack, be nicer to add a component info dict in project_description.json
  23. soc_path = [p for p in project_description["build_component_paths"] if p.endswith("/soc")][0]
  24. soc_headers = glob.glob(os.path.join(soc_path, "soc", project_description["target"],
  25. "include", "soc", "*_caps.h"))
  26. assert len(soc_headers) > 0
  27. for soc_header in soc_headers:
  28. defines.update(get_defines(soc_header, sdk_config_path))
  29. # write a list of definitions to make debugging easier
  30. with open(os.path.join(app.config.build_dir, "macro-definitions.txt"), "w") as f:
  31. pprint.pprint(defines, f)
  32. print("Saved macro list to %s" % f.name)
  33. add_tags(app, defines)
  34. app.emit('idf-defines-generated', defines)
  35. def get_defines(header_path, sdk_config_path):
  36. defines = {}
  37. # Note: we run C preprocessor here without any -I arguments (except "sdkconfig.h"), so assumption is
  38. # that these headers are all self-contained and don't include any other headers
  39. # not in the same directory
  40. print("Reading macros from %s..." % (header_path))
  41. processed_output = subprocess.check_output(["xtensa-esp32-elf-gcc", "-I", sdk_config_path,
  42. "-dM", "-E", header_path]).decode()
  43. for line in processed_output.split("\n"):
  44. line = line.strip()
  45. m = re.search("#define ([^ ]+) ?(.*)", line)
  46. if m:
  47. name = m.group(1)
  48. value = m.group(2)
  49. if name.startswith("_"):
  50. continue # toolchain macro
  51. if (" " in value) or ("=" in value):
  52. value = "" # macros that expand to multiple tokens (ie function macros) cause doxygen errors, so just mark as 'defined'
  53. defines[name] = value
  54. return defines
  55. def add_tags(app, defines):
  56. # try to parse define values as ints and add to tags
  57. for name, value in defines.items():
  58. try:
  59. define_value = int(value.strip("()"))
  60. if define_value > 0:
  61. app.tags.add(name)
  62. except ValueError:
  63. continue
  64. def setup(app):
  65. app.connect('idf-info', generate_defines)
  66. app.add_event('idf-defines-generated')
  67. return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.2'}