You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何批量确定性排序带UE装饰的C++头文件代码?

批量处理UE C++头文件的实现方案

针对你需要批量整理数十万个带UE装饰的C++头文件的需求,可通过Python脚本结合Clang AST解析实现,以下是具体步骤:

核心思路

利用Clang的libclang库准确解析C语法和UE宏,提取代码元素后按规则排序重组,避免正则表达式处理C的局限性。

实现步骤

1. 环境准备

  • 安装Python 3.x
  • 安装clang-python绑定:pip install clang
  • 配置Clang库路径,指向UE自带的LibClang(路径示例:C:/Program Files/Epic Games/UE_5.3/Engine/Source/ThirdParty/SDKs/Win64/LibClang/lib)

2. 编写批量处理脚本

脚本核心功能是遍历目录、解析AST、提取并排序代码元素、重新生成文件。以下是简化版示例代码:

import clang.cindex
import os
import re

# 配置Clang环境(替换为你的UE实际路径)
clang.cindex.Config.set_library_path("C:/Program Files/Epic Games/UE_5.3/Engine/Source/ThirdParty/SDKs/Win64/LibClang/lib")
index = clang.cindex.Index.create()
UE_CORE_INCLUDE = "C:/Program Files/Epic Games/UE_5.3/Engine/Source/Runtime/Core/Public"

def process_directory(target_dir):
    """遍历目标目录下所有头文件"""
    for root, _, files in os.walk(target_dir):
        for file in files:
            if file.endswith(".h"):
                process_single_file(os.path.join(root, file))

def process_single_file(file_path):
    """处理单个头文件"""
    # 解析文件AST
    tu = index.parse(file_path, args=["-x", "c++", "-I", UE_CORE_INCLUDE])
    includes = []
    forward_decls = []
    class_collections = []

    # 遍历AST节点提取元素
    for node in tu.cursor.get_children():
        # 提取并收集#include语句
        if node.kind == clang.cindex.CursorKind.INCLUSION_DIRECTIVE:
            incl_name = node.displayname
            if incl_name.startswith("."):
                includes.append(f'#include "{incl_name}"')
            else:
                includes.append(f'#include <{incl_name}>')
        # 提取前置类型声明
        elif node.kind in [clang.cindex.CursorKind.CLASS_DECL, clang.cindex.CursorKind.STRUCT_DECL] and node.is_forward_declaration():
            forward_decls.append(f'class {node.spelling};')
        # 提取类定义
        elif node.kind in [clang.cindex.CursorKind.CLASS_DECL, clang.cindex.CursorKind.STRUCT_DECL] and not node.is_forward_declaration():
            class_info = parse_class(node, file_path)
            class_collections.append(class_info)

    # 按规则排序所有元素
    includes = sorted(list(set(includes)))
    forward_decls = sorted(list(set(forward_decls)))
    class_collections.sort(key=lambda x: x["name"])

    # 生成整理后的代码
    new_content = generate_formatted_content(includes, forward_decls, class_collections)
    
    # 写入处理后的文件(建议先生成备份文件,确认无误后再替换原文件)
    output_path = file_path.replace(".h", "_processed.h")
    with open(output_path, "w", encoding="utf-8") as f:
        f.write(new_content)

def parse_class(class_node, file_path):
    """解析单个类的详细信息"""
    class_info = {
        "name": class_node.spelling,
        "uclass_attr": "",
        "base_classes": [],
        "properties": [],
        "functions": []
    }
    # 读取原文件提取UCLASS宏(AST不保留宏原始内容,需正则匹配)
    with open(file_path, "r", encoding="utf-8") as f:
        content = f.read()
        uclass_pattern = re.compile(rf'UCLASS\(.*?\)\s*class\s+{re.escape(class_info["name"])}', re.DOTALL)
        match = uclass_pattern.search(content)
        if match:
            class_info["uclass_attr"] = match.group(0).split("class")[0].strip()
    # 提取基类
    for base in class_node.get_children():
        if base.kind == clang.cindex.CursorKind.CXX_BASE_SPECIFIER:
            class_info["base_classes"].append(base.type.spelling)
    # 提取类成员
    with open(file_path, "r", encoding="utf-8") as f:
        content = f.read()
    for member in class_node.get_children():
        # 跳过访问修饰符节点
        if member.access_specifier != clang.cindex.AccessSpecifier.INVALID:
            continue
        # 提取属性(含UPROPERTY宏)
        if member.kind == clang.cindex.CursorKind.FIELD_DECL:
            prop_pattern = re.compile(rf'UPROPERTY\(.*?\)\s*{re.escape(member.spelling)}', re.DOTALL)
            prop_match = prop_pattern.search(content)
            prop_attr = prop_match.group(0).split(member.spelling)[0].strip() if prop_match else ""
            class_info["properties"].append({
                "attr": prop_attr,
                "name": member.spelling,
                "type": member.type.spelling
            })
        # 提取函数
        elif member.kind == clang.cindex.CursorKind.CXX_METHOD:
            args = [p.type.spelling for p in member.get_arguments()]
            func_sig = f"{member.type.spelling} {member.spelling}({', '.join(args)})"
            class_info["functions"].append(func_sig)
    # 类内属性和函数排序
    class_info["properties"].sort(key=lambda x: x["name"])
    class_info["functions"].sort()
    return class_info

def generate_formatted_content(includes, forward_decls, classes):
    """生成最终整理后的代码文本"""
    content_lines = []
    # 添加排序后的include
    content_lines.extend(includes)
    content_lines.append("")
    # 添加排序后的前置声明
    content_lines.extend(forward_decls)
    content_lines.append("")
    # 添加排序后的类
    for cls in classes:
        # 构建类头部
        class_head = f'{cls["uclass_attr"]}\nclass GAME_API {cls["name"]}'
        if cls["base_classes"]:
            class_head += f' : public {", public ".join(cls["base_classes"])}'
        class_head += " {"
        content_lines.append(class_head)
        content_lines.append("    GENERATED_BODY()")
        # 添加属性
        for prop in cls["properties"]:
            if prop["attr"]:
                content_lines.append(f"    {prop['attr']}")
            content_lines.append(f"    {prop['type']} {prop['name']};")
        # 添加函数
        if cls["functions"]:
            content_lines.append("")
            for func in cls["functions"]:
                content_lines.append(f"    {func};")
        content_lines.append("};\n")
    return "\n".join(content_lines)

if __name__ == "__main__":
    # 替换为你的头文件根目录
    process_directory("D:/UE_Projects/YourProject/Source")

3. 批量处理注意事项

  • 备份原文件:务必先备份所有待处理头文件,避免脚本异常导致数据丢失
  • 路径适配:根据你的UE版本和安装路径,修改脚本中的Clang库路径和UE核心头文件路径
  • 测试验证:先选取少量测试文件运行脚本,确认输出符合要求后再批量处理
  • 宏适配优化:若遇到特殊UE宏(如USTRUCT、UFUNCTION),可扩展脚本中的正则匹配逻辑
  • 性能优化:处理数十万文件时,可添加多线程支持提升效率

内容的提问来源于stack exchange,提问作者Kirikan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 05:54:58