本文主要是介绍【UE4源代码观察】观察Core模块,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
话题
Core模块是整个引擎中最核心的模块,在之前的博客【UE4源代码观察】可视化所有模块的依赖情况中有统计,它被983个模块引用,恐怕除了第三方的模块外基本所有模块都有引用。我想首先观察其中的内容,然后再做测试:将Core模块拷贝到之前【UE4源代码观察】手动建立一个使用UBT进行编译的空白工程建立的空白工程中,看能否将它成功编译,理论上讲,“核心”不应再依赖太多其他的东西,所以我应该不会再需要补充太多它所依赖的东西。
观察
Core模块包含了九百个h文件和近四百个cpp文件,有相当多的内容。在VS的解决方案资源管理器中观察它的文件层级结构是这样的:
在“Public”层级下分为了35个文件夹和7个头文件,我想在这个层级下观察每个文件夹和头文件都代表了哪些内容。
I.平台相关的文件夹
Android
Apple
Clang
HoloLens
IOS
Linux
Lumin
Mac
Unix
Windows
文件夹都是对应各个平台的内容,而GenericPlatform
是平台抽象类,它其中包含很多其他平台中的类的基类。UE4在跨平台上的语法是这样的:
以FMemory为例,打开UnrealMemory.h:
struct CORE_API FMemory
{/** @name Memory functions (wrapper for FPlatformMemory) */static FORCEINLINE void* Memmove( void* Dest, const void* Src, SIZE_T Count ){return FPlatformMemory::Memmove( Dest, Src, Count );}static FORCEINLINE int32 Memcmp( const void* Buf1, const void* Buf2, SIZE_T Count ){return FPlatformMemory::Memcmp( Buf1, Buf2, Count );}
会发现FMemory中使用了很多FPlatformMemory的成员函数。
而FPlatformMemory是什么要看它include的"HAL/PlatformMemory.h":
#include COMPILED_PLATFORM_HEADER(PlatformMemory.h)
这个宏会根据不同的平台扩展为对应平台的文件,比如我现在是Windows,则扩展为了WindowsPlatformMemory.h:
在这个文件中会看到:
typedef FWindowsPlatformMemory FPlatformMemory;
而FWindowsPlatformMemory这个类的基类是FGenericPlatformMemory
II.其他文件夹
algo
: algorithm(算法)。包含众多算法,如二分法查找等
Async
:异步。多线程相关的内容,很重要,TaskGraphInterfaces就在这里。
Container
:容器类
Delegates
:应该是一个重要的部分,看名字似乎是入口函数?对此理解不深,待后续理解。
FramePro
:看名字似乎是Frame Profiler?
HAL
:Hardware Abstraction Layer(硬件抽象层)
Hash
:看名字似乎和哈希有关?
Internationalization
:包含本地化相关内容,包括FText的定义。
Logging
:打Log相关
Math
:数学库
MemPro
:看名字是Memory Profiler?
Misc
:杂项
Modules
:模块相关的基本功能
ProfilingDebugging
:看名字似乎是性能分析调试相关。
Serialization
:序列化相关。
Templates
:模板类,包括智能指针。
UObject
:虽然UObject的定义有专门的模块,但Core模块似乎需要一些提前定义的内容,比如UObjectHierarchyFwd.h中存放的前向声明,其他还包含一些XXXVersion.h,待后续研究。
IO
看名字本以为是个有分量的部分,但其中只有一个IoDispatcher文件,目前还不清楚是做什么用的。
Memory
看名字本以为是个有分量的部分,但其中只有一个MemoryArena文件,目前还不清楚是做什么用的。
MSVC
其中只包括了一个头文件,在这个头文件中只有一个宏。
还有一些目前并不太清楚和什么相关的:
Concepts
Features
Stats
Traits
。其中Stats或许应该研究下。
III.头文件
Core.h
中include了大量的h文件,本身不包含其他定义,目前还不清楚在什么情况下需要include“Core.h”。
CoreMinimal.h
被前者include,它很重要,通常都能在其他头文件中看到它第一个被include。这个文件会include一些最基本的头文件,它和UE4的IWYU规则有关。
CoreTypes.h
它include了一些最底层的定义,被CoreMinimal所include,
CoreFwd.h
包含了很多基本的类的前向声明,它也被CoreMinimal所include。
CoreSharedPCH.h
中也include了大量的头文件,但也不清楚什么情况下需要include它。
CoreGlobals.h
中有很多内容,应该非常重要,待后续研究。
PixelFormat.h
还不清楚作用。
测试
完整工程见GIT上的完整工程,我把步骤与遇到的问题记录下来:
1.拷贝模块
虽然Core模块很核心,但是它本身还是依赖了两个模块:BuildSettings 和 TraceLog。这两个模块本身内容量不多,而且并没有再依赖于更多的模块了,因此这里就直接将他们一起拷贝过来了。
2.注释掉PrivateIncludePathModuleNames
1>UnrealBuildTool : error : Could not find definition for module 'TargetPlatform', (referenced via Target -> TestA.Build.cs -> Core.Build.cs)
我发现在PrivateIncludePathModuleNames中,Core模块还指定一些模块中的文件会被include
PrivateIncludePathModuleNames.AddRange(new string[] {"TargetPlatform","DerivedDataCache","InputDevice","Analytics","RHI"});
这些模块本身又会依赖更多的模块,因此若将它们拷贝过来会耗费很大的力气,于是我选择先将这部分注释掉。这一操作一定会导致后续有include找不到,但如果牵扯到的内容不多的话,那再继续注释掉相关的功能也可以接受。
3.拷贝第三方库
1>UnrealBuildTool : error : Could not find definition for module 'zlib', (referenced via Target -> TestA.Build.cs -> Core.Build.cs)
有些第三方库的模块找不到,于是我拷贝了这些模块过来,包括zlib
IntelTBB
IntelVTune
ICU
。这些库似乎.lib文件也需要一块拷贝(我并不确定能否用源码编译出来)。一下子让工程的体积变大了。
4.注释掉相关的功能
第2步的“恶果”来了:
1> [5/18] Module.Core.9_of_12.cpp
1>D:/0_WorkSpace/UEYaksueTest/Engine/Source/Runtime/Core/Private/Serialization/Archive.cpp(25): fatal error C1083: 无法打开包括文件: “Interfaces/ITargetPlatform.h”: No such file or directory
1> [6/18] Module.Core.7_of_12.cpp
1>D:/0_WorkSpace/UEYaksueTest/Engine/Source/Runtime/Core/Private/Misc/CoreMisc.cpp(18): fatal error C1083: 无法打开包括文件: “DerivedDataCacheInterface.h”: No such file or directory
但万幸所牵扯的内容很少,先注释掉h文件的include,然后再注释掉使用的地方就好了。
5.处理链接错误
1>Module.Core.2_of_12.cpp.obj : error LNK2001: 无法解析的外部符号 "wchar_t * GInternalProjectName" (?GInternalProjectName@@3PA_WA)
1>Module.Core.7_of_12.cpp.obj : error LNK2001: 无法解析的外部符号 "wchar_t * GInternalProjectName" (?GInternalProjectName@@3PA_WA)
1>Module.Core.8_of_12.cpp.obj : error LNK2001: 无法解析的外部符号 "wchar_t * GInternalProjectName" (?GInternalProjectName@@3PA_WA)
1>Module.Core.11_of_12.cpp.obj : error LNK2001: 无法解析的外部符号 "wchar_t * GInternalProjectName" (?GInternalProjectName@@3PA_WA)
1>Module.Core.2_of_12.cpp.obj : error LNK2001: 无法解析的外部符号 "wchar_t const * const GForeignEngineDir" (?GForeignEngineDir@@3PEB_WEB)
1>D:\0_WorkSpace\UEYaksueTest\Engine\Binaries\Win64\Test1.exe : fatal error LNK1120: 2 个无法解析的外部命令
这两个没找到的变量都是extern,在CoreGlobals.h
中有定义:
extern CORE_API TCHAR GInternalProjectName[64];
extern CORE_API const TCHAR* GForeignEngineDir;
他们的定义都在UE4Game.cpp中:
TCHAR GInternalProjectName[64] = TEXT("");
IMPLEMENT_FOREIGN_ENGINE_DIR()
由于在源代码的Target,UE4Editor.Target.cs中有:
ExtraModuleNames.Add("UE4Game");
所以这两个变量定义能够找到。但是现在我的工程里没有UE4Game模块,所以并不能找到定义。
于是,我临时将 GInternalProjectName 的 extern符号去掉,将 GForeignEngineDir 使用的地方注掉,便可以保证了编译通过。
6.完成!测试
为了测试Core模块能否可以正常使用,我在TestA.cpp中尝试使用了TArray:
#include"../../Runtime/Core/Public/CoreMinimal.h"#include<iostream>int main()
{TArray<int> testList;testList.Add(3);testList.Add(4);std::cout << testList[0]- testList[1]<< std::endl;return 0;
}
最终可以成功编译,并且运行:
这篇关于【UE4源代码观察】观察Core模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!