# SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import argparse import logging from typing import Dict from typing import List from typing import Optional from typing import Tuple g1_g0_components = [ 'hal', 'cxx', 'newlib', 'freertos', 'esp_hw_support', 'heap', 'log', 'soc', 'esp_rom', 'esp_common', 'esp_system', 'xtensa', 'riscv', 'spi_flash', 'esp_mm', ] # Global expected dependency violations that apply to all targets expected_dep_violations = { 'esp_system': ['esp_timer', 'bootloader_support', 'esp_pm'], 'spi_flash': ['bootloader_support'], 'esp_hw_support': ['efuse', 'bootloader_support', 'esp_driver_gpio', 'esp_timer', 'esp_pm'], 'cxx': ['pthread'], } # Target-specific expected dependency violations target_specific_expected_dep_violations = { # 'target': { # Add target-specific violations for target here # 'component_name': ['dependency1', 'dependency2'], # }, 'esp32s2': { # ESP32-S2 uses the crypto DMA lock for encrypted writes, thus, spi_flash needs to depend on esp_security 'spi_flash': ['esp_security'], }, } def merge_expected_violations(target: Optional[str] = None) -> Dict[str, List[str]]: """ Merge global and target-specific expected dependency violations. Args: target: The target target name (e.g., 'esp32', 'esp32s3', etc.) Returns: Merged dictionary of expected dependency violations """ # Start with a deep copy of global violations merged_violations = {} for component, deps in expected_dep_violations.items(): merged_violations[component] = deps.copy() # Add target-specific violations if target is specified if target and target in target_specific_expected_dep_violations: target_violations = target_specific_expected_dep_violations[target] for component, deps in target_violations.items(): if component in merged_violations: # Extend existing list with target-specific dependencies merged_violations[component].extend(deps) else: # Add new component with its dependencies merged_violations[component] = deps.copy() return merged_violations def parse_dependencies(file_path: str, target: Optional[str] = None) -> Tuple[Dict[str, List[str]], List[str]]: new_dependency_errors = [] # Get merged expected violations for the specified target merged_expected_violations = merge_expected_violations(target) with open(file_path, 'r') as file: for line in file: line = line.strip(' ;') if line: parts = line.split(' -> ') if len(parts) >= 2: source_component = parts[0] target_component = parts[1].split()[0] # Extracting the target component logging.debug(f'Parsed dependency: {source_component} -> {target_component}') # Check that g1/g0 dependencies are either on the list of expected violations # or dependencies to other g1/g0 components if source_component in g1_g0_components and target_component not in g1_g0_components: if ( source_component in merged_expected_violations and target_component in merged_expected_violations[source_component] ): logging.debug( f'Removing dependency {target_component} from {source_component} ' f'in list of expected violations' ) merged_expected_violations[source_component].remove(target_component) else: new_dependency_errors.append(f'{source_component} -> {target_component}') # Any leftover dependencies in the merged_expected_violations are no longer true dependencies and # can be removed from the list false_dependencies = {k: v for k, v in merged_expected_violations.items() if len(v) > 0} return (false_dependencies, new_dependency_errors) if __name__ == '__main__': parser = argparse.ArgumentParser(description='Check G1 dependencies') parser.add_argument( '--component_deps_file', required=True, type=str, help='The path to the component_deps.dot file' ) parser.add_argument('--target', type=str, help='The target name (e.g., esp32, esp32s3, esp32c6, etc.)') args = parser.parse_args() (false_dependencies, new_dependency_errors) = parse_dependencies(args.component_deps_file, args.target) if new_dependency_errors: print('Found the following new dependency violations:') print(new_dependency_errors) exit(1) if false_dependencies: print('The following dependencies are list as violations, but were not found in the component_deps.dot file:') print(false_dependencies) print('Please remove them from the violation list') exit(1) print('No new dependency violations found')