import os import re import sys import json from collections import defaultdict from typing import Dict, Set, List, Tuple # ================= 配置区域 ================= IGNORE_DIRS = {'library', 'main', 'build', 'bin', '.git', 'cmake'} TARGET_FILE = 'CMakeLists.txt' OUTPUT_MD = 'Mermaid.md' OUTPUT_HTML = 'Mermaid.html' # =========================================== def find_cmake_files(root_path: str) -> Dict[str, str]: valid_modules = {} print(f"🔍 开始扫描目录: {root_path} ...") for dirpath, dirnames, filenames in os.walk(root_path): current_dir_name = os.path.basename(dirpath) if dirpath == root_path: continue if current_dir_name in IGNORE_DIRS: continue cmake_count = filenames.count(TARGET_FILE) if cmake_count == 1: valid_modules[dirpath] = current_dir_name elif cmake_count > 1: print(f"⚠️ 跳过异常目录 (存在多个 {TARGET_FILE}): {dirpath}") print(f"✅ 找到 {len(valid_modules)} 个有效模块。\n") return valid_modules def parse_dependencies(modules: Dict[str, str]) -> Dict[str, Set[str]]: dependencies = defaultdict(set) module_names = set(modules.values()) tll_pattern = re.compile(r'target_link_libraries\s*\(\s*[\w\d_]+\s*(?:PUBLIC|PRIVATE|INTERFACE)?\s*(.*?)\)', re.IGNORECASE | re.DOTALL) lib_name_pattern = re.compile(r'[\w\d_\-\.]+') print("📝 正在分析依赖关系...") for path, mod_name in modules.items(): file_path = os.path.join(path, TARGET_FILE) try: with open(file_path, 'r', encoding='utf-8', errors='ignore') as f: content = f.read() matches = tll_pattern.findall(content) for match_group in matches: libs = lib_name_pattern.findall(match_group) for lib in libs: if lib in module_names and lib != mod_name: dependencies[mod_name].add(lib) except Exception as e: print(f"❌ 读取文件失败 {file_path}: {e}") return dependencies def generate_mermaid_content(dependencies: Dict[str, Set[str]], all_modules: Set[str]) -> str: graph_lines = ["graph TD"] nodes_in_edges = set() edges = [] for src, targets in dependencies.items(): nodes_in_edges.add(src) for tgt in targets: nodes_in_edges.add(tgt) edges.append(f" {src} --> {tgt}") if edges: graph_lines.extend(edges) isolated_nodes = all_modules - nodes_in_edges if isolated_nodes: for node in sorted(isolated_nodes): graph_lines.append(f" {node}") mermaid_graph_code = "\n".join(graph_lines) header = "# CMake 模块依赖图\n\n以下是自动生成的模块依赖关系图:\n\n" block_start = "```mermaid\n" block_end = "\n```\n" footer = f"\n> 提示:已生成离线交互图表 `{OUTPUT_HTML}`。\n" return header + block_start + mermaid_graph_code + block_end + footer def generate_offline_html(dependencies: Dict[str, Set[str]], all_modules: Set[str]): nodes_list = sorted(list(all_modules)) edges_list = [] # 统计每个节点的入度和出度,用于 Tooltip 显示 in_degree = defaultdict(int) out_degree = defaultdict(int) for src, targets in dependencies.items(): out_degree[src] = len(targets) for tgt in targets: in_degree[tgt] += 1 edges_list.append({"source": src, "target": tgt}) # 构建包含统计信息的节点数据 nodes_data = [] for name in nodes_list: nodes_data.append({ "id": name, "in": in_degree.get(name, 0), "out": out_degree.get(name, 0) }) data_json = json.dumps({ "nodes": nodes_data, "edges": edges_list }) html_template = """
💡 点击节点查看对外依赖