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 11import difflib 12import glob 13import itertools 14import os 15import re 16import sys 17import typing 18 19ESP_SYSTEM_INIT_FN_STR = r'ESP_SYSTEM_INIT_FN' 20ESP_SYSTEM_INIT_FN_REGEX_SIMPLE = re.compile(r'ESP_SYSTEM_INIT_FN') 21ESP_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]+)\)') 22STARTUP_ENTRIES_FILE = 'components/esp_system/system_init_fn.txt' 23 24 25class StartupEntry: 26 def __init__(self, filename: str, func: str, affinity: str, priority: int) -> None: 27 self.filename = filename 28 self.func = func 29 self.affinity = affinity 30 self.priority = priority 31 32 def __str__(self) -> str: 33 return f'{self.priority:3d}: {self.func} in {self.filename} on {self.affinity}' 34 35 36def main() -> None: 37 try: 38 idf_path = os.environ['IDF_PATH'] 39 except KeyError: 40 raise SystemExit('IDF_PATH must be set before running this script') 41 42 has_errors = False 43 startup_entries = [] # type: typing.List[StartupEntry] 44 45 # 46 # 1. Iterate over all .c and .cpp source files and find ESP_SYSTEM_INIT_FN definitions 47 # 48 source_files_iters = [] 49 for extension in ('c', 'cpp'): 50 glob_iter = glob.glob(os.path.join(idf_path, 'components', '**', f'*.{extension}'), recursive=True) 51 source_files_iters.append(glob_iter) 52 for filename in itertools.chain(*source_files_iters): 53 with open(filename, 'r') as f_obj: 54 file_contents = f_obj.read() 55 if ESP_SYSTEM_INIT_FN_STR not in file_contents: 56 continue 57 count_expected = len(ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.findall(file_contents)) 58 found = ESP_SYSTEM_INIT_FN_REGEX.findall(file_contents) 59 if len(found) != count_expected: 60 print((f'error: In {filename}, found ESP_SYSTEM_INIT_FN {count_expected} time(s), ' 61 f'but regular expression matched {len(found)} time(s)'), file=sys.stderr) 62 has_errors = True 63 64 for match in found: 65 entry = StartupEntry( 66 filename=os.path.relpath(filename, idf_path), 67 func=match[0], 68 affinity=match[1], 69 priority=int(match[2]) 70 ) 71 startup_entries.append(entry) 72 73 # 74 # 2. Sort the ESP_SYSTEM_INIT_FN functions in C source files by priority 75 # 76 startup_entries = list(sorted(startup_entries, key=lambda e: e.priority)) 77 startup_entries_lines = [str(entry) for entry in startup_entries] 78 79 # 80 # 3. Load startup entries list from STARTUP_ENTRIES_FILE, removing comments and empty lines 81 # 82 startup_entries_expected_lines = [] 83 with open(os.path.join(idf_path, STARTUP_ENTRIES_FILE), 'r') as startup_entries_expected_file: 84 for line in startup_entries_expected_file: 85 if line.startswith('#') or len(line.strip()) == 0: 86 continue 87 startup_entries_expected_lines.append(line.rstrip()) 88 89 # 90 # 4. Print the list of differences, if any 91 # 92 diff_lines = list(difflib.unified_diff(startup_entries_expected_lines, startup_entries_lines, lineterm='')) 93 if len(diff_lines) > 0: 94 print(('error: startup order doesn\'t match the reference file. ' 95 f'please update {STARTUP_ENTRIES_FILE} to match the actual startup order:'), file=sys.stderr) 96 for line in diff_lines: 97 print(f'{line}', file=sys.stderr) 98 has_errors = True 99 100 if has_errors: 101 raise SystemExit(1) 102 103 104if __name__ == '__main__': 105 main() 106