首页 > 其他分享 >Game Engine MetaData Creation With Clang

Game Engine MetaData Creation With Clang

时间:2022-08-22 12:44:06浏览次数:49  
标签:Engine childType Creation Clang cursor Game CXCursor clang 类型

A Little Context to Start

我的hobby引擎使用一个系统,任何类或者结构体可以有metadata,但是这不是严格必须的。
除此之外,每个metadata开启的类型,并不要求去有一个虚函数表。让我们考虑一个简单的类型,
它位于一个名为ChildType.h的头文件中。

//ChildType.h

class childType : public parentType
{
  DECLARE_TYPE( childType, parentType );
  void RedactedFunction( float secretSauce );
  float unsavedValue; /// +NotSaved
  double * ptrToDbl;
  ValueType_t someValues[3];
};

通过使用DECLARE_TYPE宏的美德,它清晰地表示这个类型目的是开启metadata,但是它不能很好地知道这个数据来自于哪里。

//ChildTypeClass.cpp

MemberMetadata const childType::TypeMemberInfo[] = {
  {“unsavedValue”, eDT_Float,       eDT_None,    eDF_NotSaved, offsetof(childType, unsavedValue), 1, NULL },
  {“ptrToDbl”,     eDT_Pointer,     eDT_Float64, eDF_None,     offsetof(childType, ptrToDbl),     1, NULL },
  {“someValues”,   eDT_StaticArray, eDT_Struct,  eDF_None,     offsetof(childType, someValues),   3, ValueStructClass }
};
IMPLEMENT_TYPE( childType, parentType );

DECLARE_TYPE宏添加了MemberMetadata结构体地类静态数组。

Enter Clang

Clang是一个C语言家族前端,对于LLVM。Clang是一个C++对于LLVM编译器。

libClang提供了一个相对简单的C风格的API,到抽象语法树(AST),被语言解析器所创建。

A Little Glossary Action

libClang API使用一些简单的概念,去建模你的代码,在AST形式下。

Translation Unity

实际上,它是创建一个AST的编译器的一次运行。我们可以思考它作为一个编译的文件+任何它包含的头文件。
在libClang的术语,它是一个基础层次的容器,并且是我们需要进行的数据收集工作的起点。

Cursor

一个Cursor表示一个语法构造,在AST中。它们可以表示一个完整的命名空间或者一个简单的变量名。
它们也保留父子/儿子关系,和其它cursors。对于我们的目的,cursors是在AST中的节点,我们需要去遍历的。
它们也包含引用到源文件位置,它们所找到的。

Type

这个是非常简单的。我们查看的cursors将经常引用一个类型。这些就是字面上的语言类型。
记在心里,Clang建模了整个类型系统。

The Plan

一旦解析完成,整个解决方案就非常轻松了。

1.设置环境
2.对于每个头文件,制作一个Translation Unit。
3.遍历AST,对于感兴趣的类型定义cursors。
4.对于每个类型定义,查找member data cursors,和其它信息。
5.一旦我们获得了关于类型的所有信息,就将文本转储到文件中。

Setup-Compiler Environment

我们需要使用相同的命令行预处理器定义(-D)就像同样的额外包含文件夹(-I)。

Setup-Header Environment

...

Time to Make the Doughnuts

当我们收集了所有的头文件路径,和预处理符号,调用clang非常轻松。
我们不可以只传递header到clang_parseTranslationUnit并且调用它。Clang不会知道如何去执行,当它不知道额外的参数的时候,去表示语言去使用。我也需要去包含PCH文件。
Clang支持内存中未保存的文件。

这里有一个基本步骤,用于构建一个translation unit,对于一个单一的头文件,叫做"MyEngineHeader.h"。

char const * args[] = {"-Wmicrosoft"
            , "-Wunknown-pragmas"
            , "-I\\MyEngine\\Src"
            , "-I\\MyEngine\\Src\\Core"
            , "-D_DEBUG=1" };

CXUnsavedFile dummyFile;
dummyFile.Filename = "dummy.cpp";
dummyFile.Contents = "#include \"MyEnginePCH.h\"\n#include \"MyEngineHeader.h\"";
dummyFile.Length = strlen( dummyFile.Contents );

CXIndex CIdx = clang_createIndex(1, 1);
CXTranslationUnit tu = clang_parseTranslationUnit( CIdx, "dummy.cpp"
                                 , args, ARRAY_SIZE(args)
                                 , &dummyFile, 1
                                 , CXTranslationUnit_None );

使用clang_getDiagnostic,clang_getDiagnosticSpelling,去获取人类可读的错误消息。

unsigned int numDiagnostics = clang_getNumDiagnostics( tu );
for ( unsigned int iDiagIdx=0; iDiagIdx < numDiagnostics; ++iDiagIdx )
{
  CXDiagnostic diagnostic = clang_getDiagnostic( tu, iDiagIdx );

  CXString diagCategory = clang_getDiagnosticCategoryText( diag );
  CXString diagText = clang_getDiagnosticSpelling( diag );
  CXDiagnosticSeverity severity = clang_getDiagnosticSeverity( diag );
  
  printf( "Diagnostic[%d] - %s(%d)- %s\n"
                               , iDiagIdx
                               , clang_getCString( diagCategory )
                               , severity
                               , clang_getCString( diagText ) );
                               
  clang_disposeString( diagText );
  clang_disposeString( diagCategory );

  clang_disposeDiagnostic( diagnostic );
}

Time to Start Digging!

编译阶段应当已经提供你一个有效的translation unit。当我们获取了顶层的top-level cursor,使用clang_getTranslationUnitCursor(),我们将translation unit放在一个安全的位置,并且使用cursor作为高层的对象。

C风格的Clang接口使用一个笨拙的回调API,叫做clang_visitChildren。Clang会调用你的回调,对于你的每个child cursor,它碰见的。你的回调,返回一个值,表示迭代器是否应当重复使用更深的儿子。

我们在这个阶段只对类型声明感兴趣,但是C++允许新的类型发生,在一些地方。
image

还有一些没有覆盖,比如函数私有的类型,还有union。

遍历类型:

MyTraversalContext typeTrav;
clang_visitChildren( clang_getTranslationUnitCursor( tu ), GatherTypesCB, &typeTrav );

enum CXChildVisitResult GatherTypesCB( CXCursor cursor, CXCursor parent, CXClientData client_data )
{
  MyTraversalContext * typeTrav = reinterpret_cast( client_data );
  CXCursorKind kind = clang_getCursorKind( cursor );

  CXChildVisitResult result = CXChildVisit_Continue;

  switch( kind )
  {
      case CXCursor_EnumConstantDecl:
        typeTrav->AddEnumCursor( cursor );
        break;

      case CXCursor_StructDecl:
      case CXCursor_ClassDecl:
        typeTrav->AddNewTypeCursor( cursor );
        result = CXChildVisit_Recurse;
        break;

      case CXCursor_TypedefDecl:
      case CXCursor_Namespace:
        result = CXChildVisit_Recurse;
        break;
  }

  return result;
}

枚举暂时看成整数吧。

Panning For Gold

我们现在有了一大串类型,我们想去过滤它们。

我们可以迭代我们之前步骤创建的type cursors,感兴趣的类型列表,并且询问每个,它们来自于哪个文件。
类型来自于其它文件将被安全地剔除。

Data Gathering-Internal

image

基础类型还有成员变量应当是清晰的,但是静态类成员可能怪异的,对于这个列表。

Data Gathering-External

...

标签:Engine,childType,Creation,Clang,cursor,Game,CXCursor,clang,类型
From: https://www.cnblogs.com/pixel-Teee/p/16612446.html

相关文章

  • 从 InfluxDB 到 TDengine,阳光氢能为什么会做出这个选择?
    小 T 导读:为了更好地支持阳光氢能PEM绿电制氢系统,本文作者所在的部门需要寻找一套满足业务和性能需求、而且具有国产知识产权的时序数据库,来替代原本使用的InfluxDB......
  • Link with Game Glitch(负环)
    题意有\(n\)个物品,\(m\)个转换,每\(ka_i\)个\(b_i\)类物品可以换\(w\cdotkc_i\)个\(d_i\)类物品。其中\(k\)为任意正实数。求最大的\(0\leqw\leq1\)使得不存在一种......
  • 2022/8/19日测试 (内含Ticket Game,生日蛋糕,最优贸易,装满的油箱,道路游戏)
    TicketGame标签:思维--------------------------------------------------------------------------------------------------------Alice和Bob生活在Berland。Berland......
  • Unity使用Font.GetCharacterInfo 和 Font.RequestCharactersInTexture获取UnityEngine
    usingUnityEngine;usingUnityEngine.UI;publicclassFontTest:MonoBehaviour{voidStart(){Test();}voidTest(){str......
  • Game Theory
    GameTheory目录博弈的基本概念组合游戏SG函数经典组合游戏模型导言:博弈的基本概念博弈论是研究具有斗争和竞争性质现象的数学理论和方法,博弈论,又称为对策论(GameTh......
  • CF1719A Chip Game 题解
    题目传送门。思路当其中一个人不能动的时候,这个人一定位于点\((n,m)\)上。令点\((n,m)\)为终点。当\(n\)和\(m\)都是奇数或当\(n\)和\(m\)都是偶数时,赢的人......
  • 搭建UnityGameFramework框架最低需求项目
    1、下载GameFramework包进入官网的下载页面下载2021.05.31版本https://gameframework.cn/download/2、新建Unity项目,然后把包导入3、新建Editor文件夹,并创建GameFr......
  • AI Engine core 初识
    AIEnginecore初识     其余的端口需要通过软件平台来使能  ......
  • CF1498F Christmas Game
    problem一棵树,有root,一个点只能向根跳k步直到不能走,问先手必败还是必胜。root从1到n,回答n次solution一次的话就是一个阶梯nim。多次的话,就要换根。换根的话,虽然会全......
  • 多校8 D Poker Game: Decision
    problem暴力sg,打牌code#include<bits/stdc++.h>#defineFOR(i,a,b)for(inti=a;i<=b;++i)#definelllonglongusingnamespacestd;constint_=1e6+7;//const......