[UE4 source code observation] Manually create a blank project compiled with UBT

[UE4 source code observation] Manually create a blank project compiled with UBT

I want to observe how UE4 is compiled, so I checked the official documentation and learned that UE4 has its own set of compilation tools: UnrealBuildTool, or UBT for short. About UBT's official documents refer to: Unreal Compilation Tools . I want to try to manually create a blank project compiled with UBT. But first, first understand the role played by some files in the UBT compilation process

The role of some files in the UBT compilation process

Module

Each module is declared by a .build.cs file, which is stored in the Source directory. The C++ source code belonging to a module is stored side-by-side with the .build.cs file, or in its subdirectories. Each .build.cs file declares a class, inheriting ModuleRules. For detailed concepts and configuration properties of the module, see the official documentation.

aims

Each target is declared by a .target.cs file and stored in the Source directory. Each .target.cs file declares a class, inheriting TargetRules. For detailed concepts and configuration properties of the target, refer to the official documentation.
It is worth mentioning that the target will specify a launch module (LaunchModuleName) , that is, from which module the program is launched. It is defined as follows:

///<summary> ///Specifies the name of the launch module. For modular builds, this is the module that is compiled into the target's executable. ///</summary> public string LaunchModuleName { get { return ( LaunchModuleNamePrivate == null && Type != global:: UnrealBuildTool . TargetType . Program )? "Launch" : LaunchModuleNamePrivate ; } set { LaunchModuleNamePrivate = value; } }

Its logic is: if you do not manually specify a startup module, and the target type is not Program, it will start from the "Launch" module by default.

Project file in VS

The official documentation states: It is important to understand that the build process executes independently of any project files for the development environment, such as .sln or .vcproj files (for Visual Studio) (There is an important thing to understand: compiled The process has nothing to do with the project files in the development environment (such as .sln and .vcproj in VS). That is, UE4 can be compiled without the project file in VS, and the project file is only helpful for editing in VS.
Open the properties of the BlankProgram project in the UE4 source code to view:
View Image
found that the "generate", "regenerate" and "clear" commands actually call the batch script and pass it a target in the parameters.
Then open Build.bat:

@echo off setlocal enabledelayedexpansion REM The %~dp0 specifier resolves to the path to the directory where this .bat is located in. REM We use this so that regardless of where the .bat file was executed from, we can change to REM directory relative to where we know the .bat is stored. pushd "%~dp0\..\..\Source" REM %1 is the game name REM %2 is the platform name REM %3 is the configuration name IF EXIST ../../Engine\Binaries\DotNET\UnrealBuildTool.exe ( ../../Engine\Binaries\DotNET\UnrealBuildTool.exe %* popd REM Ignore exit codes of 2 ("ECompilationResult.UpToDate") from UBT ; it's not a failure. if "!ERRORLEVEL!"=="2" ( EXIT/B 0 ) EXIT/B ! ERRORLEVEL ! ) ELSE ( ECHO UnrealBuildTool.exe not found in ../../Engine\Binaries\DotNET\UnrealBuildTool.exe popd EXIT/B 999 )

Found that it actually opened UnrealBuildTool.exe and passed the parameters to it.

Start hands-on practice!

The idea is to first compile UnrealBuildTool.exe, then configure a target with an empty startup module, and finally compile the target with UBT. There were many problems during the whole process, and I recorded them all. The complete code can be seen: complete code GIT

0. Build an empty solution

View Image

1. Create UnrealBuildTool project and compile

1.1

Copy the project/Engine\Source\Programs\UnrealBuildTool in the source code engine directory to your solution directory. Be careful to keep the directory level the same.

1.2

Add UnrealBuildTool.csproj to your own solution, and find that there is an error immediately after adding

[Failure] The file "D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\DotNETCommon\MetaData.cs" could not be found.

I opened the properties of the solution of the UE4 source code and found that: UnrealBuildTool is dependent on DotNETCommon's
View Image
so copy the DotNETCommon project and add it.

1.3

Start the build:

1>------ Generation has started: Project: DotNETUtilities, Configuration: Debug Any CPU ------ 1> DotNETUtilities -> D:\0_WorkSpace\UEYaksueTest\Engine\Binaries\DotNET\DotNETUtilities.dll 2>------ Build has started: Project: UnrealBuildTool, Configuration: Debug Any CPU ------ 2>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(2110,5): warning MSB3245: This reference could not be resolved. The assembly "Ionic.Zip.Reduced" could not be found. Please check if the assembly exists on the disk. If your code requires this reference, a compilation error may occur. 2>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\Microsoft.Common.CurrentVersion.targets(2110,5): warning MSB3245: This reference could not be resolved. The assembly "Microsoft.VisualStudio.Setup.Configuration.Interop" could not be found. Please check if the assembly exists on the disk. If your code requires this reference, a compilation error may occur. 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\Mac\MacToolChain.cs(11,7,11,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\Mac\UEDeployMac.cs(10,7,10,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\TVOS\TVOSToolChain.cs(13,7,13,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\TVOS\TVOSToolChain.cs(14,7,14,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\Android\AndroidAARHandler.cs(13,7,13,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\IOS\IOSToolChain.cs(14,7,14,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\IOS\IOSToolChain.cs(15,7,15,12): error CS0246: Could not find type or namespace name "Ionic" (whether Missing using directive or assembly reference?) 2>D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Platform\Windows\UEBuildWindows.cs(11,17,11,29): error CS0234: The type or namespace name does not exist in the namespace "Microsoft" "VisualStudio" (are you missing an assembly reference?) ========== Generation: 1 success, 1 failure, 0 latest, 0 skipped ==========

Found that DotNet was successfully generated, but UBT still failed. Looking at the log, the assembly "Ionic.Zip.Reduced" and assembly "Microsoft.VisualStudio.Setup.Configuration.Interop" should not be found.

1.4

I found the dll "Microsoft.VisualStudio.Setup.Configuration.Interop" in the/Engine\Binaries\ThirdParty\VisualStudio folder in the source code directory, so I copied this folder over and it worked!
"Ionic.Zip.Reduced" can also be found in ThirdParty, but unfortunately I copied it in the same way and it didn’t work.

1.5

I searched Ionic.Zip.Reduced in the source code directory and found that there are four places where
View Image exists.
I don’t know how the program finds dll mechanism, but/Engine\Binaries\DotNET is the output directory of UnrealBuildTool, exe will be placed Here, so I tried to put the dll in this directory and it worked.

1.6

Start the build, it succeeded

1>------ Build has started: Project: UnrealBuildTool, Configuration: Debug Any CPU ------ 1> UnrealBuildTool -> D:\0_WorkSpace\UEYaksueTest\Engine\Binaries\DotNET\UnrealBuildTool.exe ========== Generation: 1 successful, 0 failed, 1 latest, 0 skipped ==========

2. Configure module, target, project

Refer to BlankProgram during configuration. But compared to it, I want a more blank project. BlankProgram depends on Core Projects modules, and I don't want to depend on them.

2.1 Configuration module

2.1.1 Module folder location The
first thing to determine is that the module must be located in the Source directory, but whether it still needs to be placed in the Runtime or Editor subfolders in Source, I am not sure. But I observed that the modules in the source code are all under subfolders, and there is hard-coded about this in the C# code of UnrealBuildTool:

///<summary> ///Full path to the Engine/Source/Runtime directory ///</summary> public static readonly DirectoryReference EngineSourceRuntimeDirectory = DirectoryReference .Combine( EngineSourceDirectory , "Runtime"); ///<summary> ///Full path to the Engine/Source/Developer directory ///</summary> public static readonly DirectoryReference EngineSourceDeveloperDirectory = DirectoryReference .Combine( EngineSourceDirectory , "Developer"); ///<summary> ///Full path to the Engine/Source/Editor directory ///</summary> public static readonly DirectoryReference EngineSourceEditorDirectory = DirectoryReference .Combine( EngineSourceDirectory , "Editor"); ///<summary> ///Full path to the Engine/Source/Programs directory ///</summary> public static readonly DirectoryReference EngineSourceProgramsDirectory = DirectoryReference .Combine( EngineSourceDirectory , "Programs"); ///<summary> ///Full path to the Engine/Source/ThirdParty directory ///</summary> public static readonly DirectoryReference EngineSourceThirdPartyDirectory = DirectoryReference .Combine( EngineSourceDirectory , "ThirdParty");

So I decided to put the module in a subfolder.
I think the module I want to add belongs to a "independent program", so it should be placed in the Programs folder (the modules created by BlankProgram are also under Programs). I named the module TestA, and the final directory hierarchy is:

\Engine\Source\Programs\TestA

2.1.2 Create the TestA.Build.cs file in the newly created folder.
It basically has no content, but inherits ModuleRules

using UnrealBuildTool ; public class TestA : ModuleRules { public TestA(ReadOnlyTargetRules Target ) : base( Target ) { } }

2.1.3 Create the TestA.cpp file in the newly created folder.
It is a blank file containing only one main function

int main() { return 0; }
2.2 Configuration goals

Copy the BlankProgram.Target.cs file in the source code to our Source directory and rename it to Test1.Target.cs. Test1 is the name of our target. Open the file and change the name of the class to Test1, and change the LaunchModuleName to TestA, leaving the rest unchanged.

//Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. using UnrealBuildTool ; using System . Collections . Generic ; [SupportedPlatforms( UnrealPlatformClass . Desktop )] public class Test1Target : TargetRules { public Test1Target(TargetInfo the Target ) : base( the Target ) { the Type = the TargetType . Program ; the LinkType = TargetLinkType . Monolithic ; LaunchModuleName = "TestA"; //Lean and mean bBuildDeveloperTools = false; //Never use malloc profiling in Unreal Header Tool. We set this because often UHT is compiled right before the engine //automatically by Unreal Build Tool, but if bUseMallocProfiler is defined, UHT can operate incorrectly. bUseMallocProfiler = false; //Editor-only data, however, is needed bBuildWithEditorOnlyData = true; //Currently this app is not linking against the engine, so we'll compile out references from Core to the rest of the engine bCompileAgainstEngine = false; bCompileAgainstCoreUObject = false; bCompileAgainstApplicationCore = false; //UnrealHeaderTool is a console application, not a Windows app (sets entry point to main(), instead of WinMain()) bIsBuildingConsoleApplication = true; } }
2.3 configuration items

2.3.1 Project file location
There is a GenerateProject.bat batch file in the UE4 source code directory to automatically generate project files, and the .vcxproj file will be placed in the/Engine\Intermediate\ProjectFiles folder. I decided to also put the .vcxproj file here to maintain the same level, which will reduce subsequent path configuration changes.

2.3.2 Create a new blank project
View Image
However, the hierarchical directory of the .vcxproj file is different from expected. The directly generated is this:

\Engine\Intermediate\ProjectFiles\Test1\Test1.vcxproj

And the expectation is this:
\Engine\Intermediate\ProjectFiles\Test1.vcxproj

Therefore, only Test1.vcxproj and the supporting files in the same directory can be put into the upper level, and then this project needs to be added again to the solution.

2.3.3 Configure the project to compile with UBT.
1. change the configuration type to "Generate File". After
View Image
click Apply, the NMake column will appear, imitating BlankProgram to configure it, but you need to change BlankProgram to Test1, because Test1 Is the target
View Image

2.3.4 3.scripts that will be used: Build.bat Rebuild.bat Clean.bat are copied from the source code directory. They are in the/Engine\Build\BatchFiles directory, pay attention to keep the same level directory.

3. Make sure the compilation is successful

First set the platform to x64, (because the platform we just configured is x64)
View Image
and then build the Test1 project, there will be a series of problems, the following steps to solve:

3.1

UnrealBuildTool: error: Unhandled exception: System.TypeInitializationException: The type initializer of "UnrealBuildTool.InstalledPlatformInfo" caused an exception. ---> System.IO.DirectoryNotFoundException: Could not find part of the path "D:\0_WorkSpace\UEYaksueTest\Engine\Config".

It seems that the Config file is needed, so I directly copy all the Config folder

3.2

UnrealBuildTool: error: Version file is missing (D:\0_WorkSpace\UEYaksueTest\Engine\Build\Build.version)

It seems that the Build.version file is needed, copy it over.

3.3

Then I encountered this error:

1>------ Build has started: Project: Test1, Configuration: Debug x64 ------ 1>Creating makefile for Test1 (no existing makefile) 1>UnrealBuildTool: error: Unhandled exception: Tools.DotNETCommon.JsonParseException: Unable to parse D:\0_WorkSpace\UEYaksueTest\Engine\Intermediate\Build\BuildRules\UE4ProgramRulesManifest.json: The index exceeds the array limit. 1> In Tools.DotNETCommon.JsonObject.Read(FileReference File) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\DotNETCommon\DotNETUtilities\JsonObject.cs: line number 57 1> In UnrealBuildTool.DynamicCompilation.RequiresCompilation(HashSet`1 SourceFiles, FileReference AssemblyManifestFilePath, FileReference OutputAssemblyPath) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\System\DynamicCompilation.cs: line number 67 1> In UnrealBuildTool.DynamicCompilation.CompileAndLoadAssembly(FileReference OutputAssemblyPath, HashSet`1 SourceFileNames, List`1 ReferencedAssembies, List`1 PreprocessorDefines, Boolean DoNotCompile, Boolean TreatWarningsAsBuildErrors) location D:\0_WorkSpace\Unreal\Programs\Test\Programs/\DynamicCompilation.cs: line number 405 1> In UnrealBuildTool.RulesAssembly..ctor(RulesScope Scope, DirectoryReference BaseDir, IReadOnlyList`1 Plugins, Dictionary`2 ModuleFileToContext, List`1 TargetFiles, FileReference AssemblyFileName, Boolean bContainsEngineModules, Nullable`1 DefaultBuildSettings, Boolean Rules bReadOnly, Boolean Rules bReadOnly, Boolean bSkembly Parent ) Location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\System\RulesAssembly.cs: line number 115 1> In UnrealBuildTool.RulesCompiler.CreateEngineOrEnterpriseRulesAssembly(RulesScope Scope, List`1 RootDirectories, String AssemblyPrefix, IReadOnlyList`1 Plugins, Boolean bReadOnly, Boolean bSkipCompile, RulesAssembly Parent) location D:\0_WorkSpace\UEYaksueTest\Engine\RealSource\Programs\Engine/System\RulesCompiler.cs: line number 501 1> In UnrealBuildTool.RulesCompiler.CreateEngineRulesAssembly(Boolean bUsePrecompiled, Boolean bSkipCompile) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\System\RulesCompiler.cs: line number 394 1> In UnrealBuildTool.RulesCompiler.CreateTargetRulesAssembly(FileReference ProjectFile, String TargetName, Boolean bSkipRulesCompile, Boolean bUsePrecompiled, FileReference ForeignPlugin) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\System\RulesCompil: line number658 1> In UnrealBuildTool.UEBuildTarget.Create(TargetDescriptor Descriptor, Boolean bSkipRulesCompile, Boolean bUsePrecompiled) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Configuration\UEBuildTarget.cs: line number 606 1> In UnrealBuildTool.BuildMode.CreateMakefile(BuildConfiguration BuildConfiguration, TargetDescriptor TargetDescriptor, ISourceFileWorkingSet WorkingSet) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Modes\BuildMode.cs: line number 433 1> In UnrealBuildTool.BuildMode.Build(List`1 TargetDescriptors, BuildConfiguration BuildConfiguration, ISourceFileWorkingSet WorkingSet, BuildOptions Options, FileReference WriteOutdatedActionsFile) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Modes\BuildMode.cs: line number 220 1> In UnrealBuildTool.BuildMode.Execute(CommandLineArguments Arguments) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Modes\BuildMode.cs: line number 192 1> In UnrealBuildTool.UnrealBuildTool.Main(String[] ArgumentsArray) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.cs: line number 520 1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Microsoft.MakeFile.Targets(44,5): error MSB3075: command "..\..\Build/BatchFiles\Build.bat Test1 Win64 Development -WaitMutex -FromMsBuild" has exited with code 5. Please verify that you have sufficient permissions to run this command. 1>The operation of generating the project "Test1.vcxproj" has been completed-failed. ========== Generation: 0 success, 1 failure, 0 latest, 0 skipped ==========

I don’t understand this error, but I observe

\Engine\Intermediate\Build
This folder is generated in the build. I think this is an intermediate file. I think the previous error may cause an incorrect intermediate file to be generated. So I deleted this folder and clicked generate again.

1>------ Build has started: Project: Test1, Configuration: Debug x64 ------ 1>Creating makefile for Test1 (no existing makefile) 1>While compiling D:\0_WorkSpace\UEYaksueTest\Engine\Intermediate\Build\BuildRules\UE4ProgramRules.dll: 1>EXEC: warning CS1668: The search path specified in "LIB Environment Variables" "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\atlmfc\lib\x64 "Invalid--"The system cannot find the path specified. " 1>UnrealBuildTool: error: Unable to find ISPC compiler path under D:\0_WorkSpace\UEYaksueTest\Engine\Source\ThirdParty\IntelISPC\bin\Windows\ispc.exe 1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Microsoft.MakeFile.Targets(44,5): error MSB3075: command "..\..\Build/BatchFiles\Build.bat Test1 Win64 Development -WaitMutex -FromMsBuild" has exited with code 5. Please verify that you have sufficient permissions to run this command. 1>The operation of generating the project "Test1.vcxproj" has been completed-failed. ========== Generation: 0 success, 1 failure, 0 latest, 0 skipped ==========

Fortunately, this time the prompt is clear: no ISPC compiler was found. So copy this exe.

3.4

Next build error:

EXEC: fatal error RC1110: could not open D:\0_WorkSpace\UEYaksueTest\Engine\Build\Windows\Resources\Default.rc2

It seems that/Engine\Build\Windows/is needed, so copy this folder.

3.5

The next error:

D:\0_WorkSpace\UEYaksueTest\Engine\Build\Windows\Resources\Default.rc2(5): fatal error RC1015: cannot open include file'../../../Source/Runtime/Launch/Resources/Windows/resource.h'.

It seems that some files included in Default.rc2 are not found:

#include "../../../Source/Runtime/Launch/Resources/Windows/resource.h" #include "../../../Source/Runtime/Core/Public/Misc/CoreMiscDefines.h" #include "../../../Source/Runtime/Launch/Resources/Version.h"

These files are in the Core module and the Launch module. Fortunately, these files themselves did not include more header files. Finally, I copied all the header files involved. They are:
\Engine\Source\Runtime\Core\Public\HAL\PreprocessorHelpers.h
\Engine\Source/Runtime\Core\Public\Misc\CoreMiscDefines.h
\Engine\Source\Runtime\Launch\Resources\Windows\resource.h
\Engine\Source\Runtime\Launch\Resources\Version.h

3.6

Finally, the build succeeded!

1>------ Build has started: Project: Test1, Configuration: Debug x64 ------ 1>Building Test1... 1>Using Visual Studio 2017 14.16.27035 toolchain (C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023) and Windows 10.0.17763.0 SDK (C:\Program Files (x86)\Windows Kits\10). 1>Building 3 actions with 8 processes... 1> [1/3] Default.rc2 1> [2/3] Test1.exe 1> [3/3] Test1.target 1>Total time in Parallel executor: 0.58 seconds 1>Total execution time: 0.77 seconds ========== Generation: 1 success, 0 failure, 0 latest, 0 skipped ==========

View Image

other problems

1

'"D:\0_WorkSpace\UEYaksueTest\Engine\Build\BatchFiles\GetMSBuildPath.bat"' is not an internal or external command, nor is it an executable program

Copy GetMSBuildPath.bat to solve

2 Failed when starting the cleanup command
1>------ Cleanup has started: Project: Test1, Configuration: Debug x64 ------ 1>Cleaning Test1 and UnrealHeaderTool binaries... 1>UnrealBuildTool: error: Unhandled exception: System.NullReferenceException: The object reference is not set to the instance of the object. 1> In UnrealBuildTool.RulesAssembly.CreateTargetRules(String TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, String Architecture, FileReference ProjectFile, CommandLineArguments Arguments) position D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\System\RulesAssembly.cs: line No. 599 1> In UnrealBuildTool.RulesAssembly.CreateTargetRules(String TargetName, UnrealTargetPlatform Platform, UnrealTargetConfiguration Configuration, String Architecture, FileReference ProjectFile, CommandLineArguments Arguments) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\System\RulesAssembly.cs: line No. 614 1> In UnrealBuildTool.CleanMode.Execute(CommandLineArguments Arguments) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\Modes\CleanMode.cs: line number 94 1> In UnrealBuildTool.UnrealBuildTool.Main(String[] ArgumentsArray) location D:\0_WorkSpace\UEYaksueTest\Engine\Source\Programs\UnrealBuildTool\UnrealBuildTool.cs: line number 517 1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Microsoft.MakeFile.Targets(39,5): error MSB3073: command "..\..\Build/BatchFiles\Clean.bat Test1 Win64 Development -WaitMutex -FromMsBuild" has exited with code -1. 1>The operation of generating the project "Test1.vcxproj" has been completed-failed. ========== Cleanup: 0 succeeded, 1 failed, 0 skipped ==========

This problem has not been solved yet, and it may be related to UnrealHeaderTool, which is to be observed later.


Reference : https://blog.csdn.net/u013412391/article/details/104455608