# CodeGen与反射系统

反射系统主要参考：

<https://github.com/AustinBrunkHorst/CPP-Reflection>

<https://github.com/BoomingTech/Piccolo>

核心是做codegen，codegen的内容除了有反射，还有序列化反序列化、py脚本api的注册。

## 使用

反射有别于ue的保守式标记，我们可以标记 WhiteListFields，一些示例：

```cpp
REFLECTION_TYPE(BaseTest)
CLASS(BaseTest, Fields)
{
    REFLECTION_BODY(BaseTest);

public:
    int               m_int;
    std::vector<int>  m_int_vector;
};

REFLECTION_TYPE(Test1)
CLASS(Test1 : public BaseTest, WhiteListFields)
{
    REFLECTION_BODY(Test1);

public:
    PROPERTY(Enable)
    char m_char;
};

REFLECTION_TYPE(Test2)
CLASS(Test2 : public BaseTest, , Fields)
{
    REFLECTION_BODY(Test2);

public:
    std::vector<BaseTest> m_test_base_array;
};
```

```cpp
REFLECTION_TYPE(SoundComponent)
CLASS(SoundComponent : public ComponentBase, Fields)
{
    REFLECTION_COMPONENT_BODY(SoundComponent);
public:
    SoundComponent() = default;
    SoundComponent(const SoundComponent&) = default;
    SoundComponent(const std::string& path)
        : Path(path)
    {}

    std::string Path = "None";
    bool Play;

    PROPERTY(Disable)
    FMOD::Sound* Sound;
    PROPERTY(Disable)
    FMOD::Channel* Channel = nullptr;
};
REGISTER_COMPONENT_TYPE(SoundComponent)
```

可以用 PROPERTY(Disable) 标注无需加入codegen流程的变量；当然与之对应的用 WhiteListFields 标记的时候也可以用 PROPERTY(Enable) 单独把一个变量加入流程中。

## 原理分析

1. cmake编译HEngineParser，生成 HEngineParser.exe
2. cmake阶段收集引擎头文件。核心位于 Cmake/HEngineParser.cmake 中，用 configure\_file 指令把这些头文件路径写入到一个json中。这个json最终输出在 Engine\Binaries\Win64\Programs\HEngineParser\precompile.json\
   （需要注意的是，我们需要额外加入一些头文件，例如ThirdParty/glm/glm/glm.hpp，否则libclang不知道这是一个类型）\
   我们需要定义 CPP\_CODE\_GEN 才行。例如 cmake -B build -DCPP\_CODE\_GEN=ON
3. 这个json作为参数传给 HEngineParser，HEngineParser使用libclang去解析这些头文件，获取到相应的信息，再用mustache去根据这些信息做codegen。这些信息主要指的是被我们的反射宏包裹的类型。
