check_system_init_priorities.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. #!/usr/bin/env python
  2. #
  3. # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  4. # SPDX-License-Identifier: Apache-2.0
  5. #
  6. # This file is used to check the order of execution of ESP_SYSTEM_INIT_FN functions.
  7. # It compares the priorities found in .c source files to the contents of system_init_fn.txt
  8. # In case of an inconsistency, the script prints the differences found and returns with a
  9. # non-zero exit code.
  10. import difflib
  11. import glob
  12. import itertools
  13. import os
  14. import re
  15. import sys
  16. import typing
  17. ESP_SYSTEM_INIT_FN_STR = r'ESP_SYSTEM_INIT_FN'
  18. ESP_SYSTEM_INIT_FN_REGEX_SIMPLE = re.compile(r'ESP_SYSTEM_INIT_FN')
  19. ESP_SYSTEM_INIT_FN_REGEX = re.compile(r'ESP_SYSTEM_INIT_FN\(([a-zA-Z0-9_]+)\s*,\s*([a-zA-Z\ _0-9\(\)|]+)\s*,\s*([0-9]+)\)')
  20. STARTUP_ENTRIES_FILE = 'components/esp_system/system_init_fn.txt'
  21. class StartupEntry:
  22. def __init__(self, filename: str, func: str, affinity: str, priority: int) -> None:
  23. self.filename = filename
  24. self.func = func
  25. self.affinity = affinity
  26. self.priority = priority
  27. def __str__(self) -> str:
  28. return f'{self.priority:3d}: {self.func} in {self.filename} on {self.affinity}'
  29. def main() -> None:
  30. try:
  31. idf_path = os.environ['IDF_PATH']
  32. except KeyError:
  33. raise SystemExit('IDF_PATH must be set before running this script')
  34. has_errors = False
  35. startup_entries = [] # type: typing.List[StartupEntry]
  36. #
  37. # 1. Iterate over all .c and .cpp source files and find ESP_SYSTEM_INIT_FN definitions
  38. #
  39. source_files_iters = []
  40. for extension in ('c', 'cpp'):
  41. glob_iter = glob.glob(os.path.join(idf_path, 'components', '**', f'*.{extension}'), recursive=True)
  42. source_files_iters.append(glob_iter)
  43. for filename in itertools.chain(*source_files_iters):
  44. with open(filename, 'r') as f_obj:
  45. file_contents = f_obj.read()
  46. if ESP_SYSTEM_INIT_FN_STR not in file_contents:
  47. continue
  48. count_expected = len(ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.findall(file_contents))
  49. found = ESP_SYSTEM_INIT_FN_REGEX.findall(file_contents)
  50. if len(found) != count_expected:
  51. print((f'error: In {filename}, found ESP_SYSTEM_INIT_FN {count_expected} time(s), '
  52. f'but regular expression matched {len(found)} time(s)'), file=sys.stderr)
  53. has_errors = True
  54. for match in found:
  55. entry = StartupEntry(
  56. filename=os.path.relpath(filename, idf_path),
  57. func=match[0],
  58. affinity=match[1],
  59. priority=int(match[2])
  60. )
  61. startup_entries.append(entry)
  62. #
  63. # 2. Sort the ESP_SYSTEM_INIT_FN functions in C source files by priority
  64. #
  65. startup_entries = list(sorted(startup_entries, key=lambda e: e.priority))
  66. startup_entries_lines = [str(entry) for entry in startup_entries]
  67. #
  68. # 3. Load startup entries list from STARTUP_ENTRIES_FILE, removing comments and empty lines
  69. #
  70. startup_entries_expected_lines = []
  71. with open(os.path.join(idf_path, STARTUP_ENTRIES_FILE), 'r') as startup_entries_expected_file:
  72. for line in startup_entries_expected_file:
  73. if line.startswith('#') or len(line.strip()) == 0:
  74. continue
  75. startup_entries_expected_lines.append(line.rstrip())
  76. #
  77. # 4. Print the list of differences, if any
  78. #
  79. diff_lines = list(difflib.unified_diff(startup_entries_expected_lines, startup_entries_lines, lineterm=''))
  80. if len(diff_lines) > 0:
  81. print(('error: startup order doesn\'t match the reference file. '
  82. f'please update {STARTUP_ENTRIES_FILE} to match the actual startup order:'), file=sys.stderr)
  83. for line in diff_lines:
  84. print(f'{line}', file=sys.stderr)
  85. has_errors = True
  86. if has_errors:
  87. raise SystemExit(1)
  88. if __name__ == '__main__':
  89. main()