【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;
}

最终可以成功编译,并且运行:
在这里插入图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值