# ModuleRelativePath - **功能描述:** 记录类型定义的的头文件路径,为其处于模块的内部相对路径。 - **使用位置:** Any - **引擎模块:** UHT - **元数据类型:** string="abc" - **常用程度:** 0 记录当前元类型定义的的头文件路径,为相对模块的相对路径。 对于开发者来说一般不用管,但是引擎编辑器会用它来定位某个类型是在哪个.h里定义的,从而在你双击类型的时候,可以为你在VS里打开相应的头文件。具体的逻辑可以去FSourceCodeNavigation里查看。 和IncludePath的区别是,ModuleRelativePath 在各种类型信息上都有,而IncludePath只用于UCLASS上。另外ModuleRelativePath 的值可以包含“Classes/Public/Internal/Private”这4个以开头,我们一般也确实会建议把.h.cpp划分到这4个文件夹里。而IncludeFilePath 的值就会去掉这个头。 ## 测试代码: ```cpp UCLASS(BlueprintType) class INSIDER_API UMyProperty_Template :public UObject { GENERATED_BODY() public: UFUNCTION(BlueprintCallable) int32 MyFunc(FString str){return 0;} UPROPERTY(EditAnywhere, BlueprintReadWrite) int32 MyProperty = 123; }; ``` ## 其元类型信息打印: 可以发现ModuleRelativePath 在类,属性和函数上都有该信息。 而IncludePath只有在UCLASS上才有。 ```cpp [class MyProperty_Template Class->Struct->Field->Object /Script/Insider.MyProperty_Template] (BlueprintType = true, IncludePath = Property/MyProperty_Template.h, ModuleRelativePath = Property/MyProperty_Template.h) ObjectFlags: RF_Public | RF_Standalone | RF_Transient Outer: Package /Script/Insider ClassHierarchy: MyProperty_Template:Object ClassFlags: CLASS_MatchedSerializers | CLASS_Native | CLASS_RequiredAPI | CLASS_TokenStreamAssembled | CLASS_Intrinsic | CLASS_Constructed Size: 56 Within: Object ClassConfigName: Engine { (Category = MyProperty_Template, ModuleRelativePath = Property/MyProperty_Template.h) 48-[4] int32 MyProperty; PropertyFlags: CPF_Edit | CPF_BlueprintVisible | CPF_ZeroConstructor | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic ObjectFlags: RF_Public | RF_MarkAsNative | RF_Transient Outer: Class /Script/Insider.MyProperty_Template Path: IntProperty /Script/Insider.MyProperty_Template:MyProperty [func MyFunc Function->Struct->Field->Object /Script/Insider.MyProperty_Template:MyFunc] (ModuleRelativePath = Property/MyProperty_Template.h) ObjectFlags: RF_Public | RF_Transient Outer: Class /Script/Insider.MyProperty_Template FunctionFlags: FUNC_Final | FUNC_Native | FUNC_Public | FUNC_BlueprintCallable NumParms: 2 ParmsSize: 20 ReturnValueOffset: 16 RPCId: 0 RPCResponseId: 0 public int32 MyFunc(FString str)final; { 0-[16] FString str; PropertyFlags: CPF_Parm | CPF_ZeroConstructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic ObjectFlags: RF_Public | RF_MarkAsNative | RF_Transient Outer: Function /Script/Insider.MyProperty_Template:MyFunc Path: StrProperty /Script/Insider.MyProperty_Template:MyFunc:str 16-[4] int32 ReturnValue; PropertyFlags: CPF_Parm | CPF_OutParm | CPF_ZeroConstructor | CPF_ReturnParm | CPF_IsPlainOldData | CPF_NoDestructor | CPF_HasGetValueTypeHash | CPF_NativeAccessSpecifierPublic ObjectFlags: RF_Public | RF_MarkAsNative | RF_Transient Outer: Function /Script/Insider.MyProperty_Template:MyFunc Path: IntProperty /Script/Insider.MyProperty_Template:MyFunc:ReturnValue }; }; ``` ## 原理: 在UHT分析的时候,自动的为类型加上头文件的路径信息。 从源码逻辑可以看出,ModuleRelativePath 的值可以包含“Classes/Public/Internal/Private”这4个以开头,我们一般也确实会建议把.h.cpp划分到这4个文件夹里。而IncludeFilePath 的值就会去掉这个头。 ```cpp public enum UhtHeaderFileType { /// /// Classes folder /// Classes, /// /// Public folder /// Public, /// /// Internal folder /// Internal, /// /// Private folder /// Private, } public static void AddModuleRelativePathToMetaData(UhtMetaData metaData, UhtHeaderFile headerFile) { metaData.Add(UhtNames.ModuleRelativePath, headerFile.ModuleRelativeFilePath); } //分析文件路径 private void StepPrepareHeaders(UhtPackage package, IEnumerable headerFiles, UhtHeaderFileType headerFileType) { string typeDirectory = headerFileType.ToString() + '/'; headerFile.ModuleRelativeFilePath = normalizedFullFilePath[stripLength..]; if (normalizedFullFilePath[stripLength..].StartsWith(typeDirectory, true, null)) { stripLength += typeDirectory.Length; } headerFile.IncludeFilePath = normalizedFullFilePath[stripLength..]; } ```