赞
踩
年底了,把之前的草稿文章整理一下,整理好的发出来
参考:https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/BuildTools/UnrealBuildTool/
UE里的项目代码、包括UE本身的源码,都是划分成一个个module的dll的,每个Module用build.cs
文件来控制对应module的相关信息,比如对其他module的依赖、include路径等,然后这些dll会一起编译成最后的single executable里,后面还会详细介绍下。
看到一个新创建的名为MyDemo的C++工程,里面的这三个文件让我产生了疑惑,它们的路径如下:
Source文件夹下出现了X和XEditor名字的target.cs文件,而Source\X文件夹下出现了X名字的build.cs文件。俩target.cs文件内容差不多:
// MyDemo.Target.cs using UnrealBuildTool; using System.Collections.Generic; public class MyDemoTarget : TargetRules { public MyDemoTarget(TargetInfo Target) : base(Target) { Type = TargetType.Game;// build目标类型为Game DefaultBuildSettings = BuildSettingsVersion.V2; IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1; ExtraModuleNames.Add("MyDemo"); } } // MyDemoEditor.Target.cs using UnrealBuildTool; using System.Collections.Generic; public class MyDemoEditorTarget : TargetRules { public MyDemoEditorTarget(TargetInfo Target) : base(Target) { Type = TargetType.Editor;// build目标类型为Editor DefaultBuildSettings = BuildSettingsVersion.V2; IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_1; ExtraModuleNames.Add("MyDemo"); } }
build.cs文件则貌似是个runtime only的东西:
using UnrealBuildTool;
public class MyDemo : ModuleRules
{
public MyDemo(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "EnhancedInput" });
}
}
看了下它们的内容,可以大概了解这些文件的干啥的了。Visual Studio里,一个正常的Solution会有多个projects,在这里,相当于每个Module对应一个project,而且Module的output类型都是dll,这里的文件作用分别为:
大概意思是,像Configuration、引擎版本、编译器这种所有Module对应的dll都共享的内容,可以放到Target.cs文件里,至于各自Module的依赖关系、PCH引用关系,则使用各自Module的Build.cs文件来记录
所以这里的target.cs表示了项目的build类型,一共也没多少种,无非就是类似于Debug、Release这种类型的设置,而build.cs
则相当于记录了每个module的project的相关project settings信息。比如说我新创建的UE C++工程,自然会有Runtime的Game类型和Editor下的编辑类型,所以会有MyDemo.Target.cs
和MyDemoEditor.Target.cs
俩文件产生。而我如果是创建一个Plugin,那不需要创建任何.Target.cs文件,只需要创建Runtime和Editor下各自对应的Build.cs文件即可
在UE源码里,有四种主要的引擎对应的Target.cs文件:
引擎里的所有Plugin和各自Module,应该都是随着引擎一起共享Target.cs文件,所以项目里,build.cs文件应该是更多的,UE源码里我验证了一下,确实是这样,里面的build.cs文件有1923个,但target.cs只有124个
另外,可以在BuildConfiguration.cs
文件里选择一些全局的引擎build设置,这个文件属于引擎源码级别的代码,里面基本都是一堆bool值,具体路径为:
参考:https://community.gamedev.tv/t/could-not-be-compiled-try-rebuilding-from-source-manually/7953/25
加了点新东西常常就会编译失败,提示could not be compiled Try rebuilding from source
,如果是生成VS项目失败,可以打开对应的LOG文件:
MyDemo\Saved\Logs\MyDemo.log
参考:https://forums.unrealengine.com/t/what-does-the-additionaldependencies-field-mean-in-uproject-modules-section/589091
貌似都是用来描述Module之间的依赖情况的,貌似在.uproject文件里写AdditionalDependencies的方式已经过时了
多的不说了,网上都有,主要是源码Attach到具体的项目的设置:
我发现路径里好像不能有空格,而且Epic Games这玩意儿可开可不开,attach之后如果还让选择项目,应该就是前面输入的路径不对了
二者好像Debug方法不一样,参考:https://answers.unrealengine.com/questions/449653/how-to-run-visual-studio-debugger-on-ue4-source.html
如果用对应的UE4的exe(应该是源码搞出来的exe)打开了项目,然后用vs源码工程attach到对应的process即可
如果要Debug蓝图项目,直接在UE4的C++工程里,F5,打开对应的项目即可。如果是Debug C++项目,这样做好像不行,不知道为啥会报错。这种情况下,好像只能在Source里创建对应的C++工程,然后打开对应C++工程的sln文件,在里面可以Debug UE4的源码,不过这里好像要rebuild ue4源码
感觉很麻烦,不知道有没有更好的方法
E:\UnrealEngine\Engine\Content\Editor\Slate\
参考:https://www.reddit.com/r/unrealengine/comments/d2dqen/unreal_engine_source_code_overviewguidestutorials/
在Runtime或者Editor文件夹里,里面有很多文件夹,每一个都包含一个或者多个modules,每个module都有一个build.cs
文件来表明如何build这个模块,它也表明了模块之间的依赖关系。
当编译和启动UE4引擎时,它会启动一个UnreaBuildTool工具,它会去寻找所有modules里的build.cs文件,使用它来Compile和Link模块,感觉这玩意儿类似于CmakeList和Premake5.lua文件,对于每个module,它生成的东西会放到Binary文件夹里,比如dll、obj等文件,会在run Editor的时候加载这些玩意儿。把引擎module化是为了防止每次修改内容,都需要rebuild整个引擎,而是
只会rebuild对应的module,和受其影响的其他部分。
I recommend looking at Rama’s tutorials on the wiki for building modules and looking at his plugins he’s released. You’ll get a good idea about how the editor works.
详细的参考:https://www.cnblogs.com/FlyingZiming/p/15017445.html
这玩意儿还挺恶心的,比如我引入了一个类的头文件,然后编译报错,提示找不到对应类的函数定义,然后查了半天才发现,要在项目对应的Build.cs文件里添加对应的模块的引用,而这玩意儿貌似是不会反映到VS的项目属性上的
参考:https://zhuanlan.zhihu.com/p/107270501
由于有的API是可以暴露出去的,有的不可以,所以UE4把所有导出的API的对应头文件放到了Public文件夹下,如果这里的模块不会被任何模块引用,那么可以不区分Public和Private目录
最近很容易一不小心改了代码,就改到了PCH里的东西,就要全部Rebuild,很头疼
看了下UE4的核心Engine.Build.cs文件,发现里面有这个:
PrivatePCHHeaderFile = "Private/EnginePrivatePCH.h";
SharedPCHHeaderFile = "Public/EngineSharedPCH.h";
然后发现我改动的一个文件叫AnimationAsset.h,在两个文件里都出现了,表示它是PCH里的东西,好吧,下次不改这个了。
不过PrivatePCH和SharedPCH有啥区别呢?
PrivatePCH是给本模块用的PCH,Shared PCH是给依赖本模块的模块用的PCH,可以看到EngineSharedPCH里的内容比EnginePrivatePCH的内容略多
参考:https://forums.unrealengine.com/t/how-to-compile-in-non-unity-mode/94863/3
参考:https://forums.unrealengine.com/t/waiting-for-git-status-command-to-complete-making-for-long-compile-times/412358/3
就算我有一个不重要的cpp的微小改动,也会重新编译整个工程,耗时很久。看了下,好像跟UE默认的unity build有关。Build信息如下所示:
19>------ Build started: Project: SlateViewer, Configuration: Development_Program x64 ------
7>Log file: D:\UnrealSource\UnrealEngine\Engine\Programs\UnrealBuildTool\Log.txt
7>Using 'git status' to determine working set for adaptive non-unity build (D:\UnrealSource\UnrealEngine).
上面提示,可以使用git status来决定使用non-unity build,查了下,好像跟引擎默认的Build设置有关,默认设置是只要有git,就会使用它,把它记录的这些文件从unity build里排除掉,从而减少编译时间。
排除掉之后,应该是走的正常的Build流程了,不过看他这个意思,开着这玩意儿不是能减少编译时间的?
具体做法如下,在路径UnrealSource\UnrealEngine\Engine\Saved\UnrealBuildTool
下,把文件改成:
<?xml version="1.0" encoding="utf-8" ?>
<Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<SourceFileWorkingSet>
<Provider>None</Provider>
<RepositoryPath></RepositoryPath>
<GitPath></GitPath>
</SourceFileWorkingSet>
</Configuration>
还有一些类似的设置:
<?xml version="1.0" encoding="utf-8" ?><Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
<BuildConfiguration>
<bUseUnityBuild>false</bUseUnityBuild>
<bUsePCHFiles>false</bUsePCHFiles>
</BuildConfiguration>
</Configuration>
然后又要重新整个编译。。。。。
试了下这个黑科技http://www.morecpp.cn/ue-opensource-project-trigger-compile/,没用
主要是看到UE里创建的C++项目类型为Makefile,而且相关的属性配置设置非常少,所以有这个疑问,如下图所示:
参考:https://learn.microsoft.com/en-us/cpp/build/reference/creating-a-makefile-project?view=msvc-170
A makefile is a text file that contains instructions for how to compile and link (or build) a set of source code files. A program (often called a make program) reads the makefile and invokes a compiler, linker, and possibly other programs to make an executable file. The Microsoft program is called NMAKE.
什么是Makefile,其实我是知道的,早在没有VS这种大型IDE之前,就是使用makefile来把各个cpp和头文件整合到一起,编译出结果的,Makefile本质就是个text文件。但这里的Makefile Project,我就不是特别清楚了。
这里创建一个Windows上的起始Makefile项目看看,需要输入这些东西:
创建之后,发现仍然可以加入cpp文件:
但是加入cpp之后,直接编译项目,并没有什么东西生成,而是提示我没有加commandline:
warning MSB8005: The property 'NMakeReBuildCommandLine' doesn't exist. Skipping...
所以我理解的是,VS里的makefile project,应该就是把传统makefile的规则,存到了vsproject里,用于自定义命令行的项目构建,就是套了VS的壳,再用makefile的方式去构建项目。
拿我这个UE项目对应的makefile project举例,它的两个重要设置为:
最后我rebuild工程时执行的命令是这样的:
Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" MyProjectEditor Win64 DebugGame -Project="F:\UnrealProjects\MyProject\MyProject.uproject" -WaitMutex -FromMsBuild -Rebuild
就是调用UnrealBuildTool去分析这个MyProject.uproject
文件而已,后续应该做了具体的项目build设置。
总结下来就是,这个Makefile Project没有做真正的build工作,在build这个工程时,它只是调用了UE的UnrealBuildTool
,然后基于项目的uproject文件,让UnrealBuildTool去进行真正的build工作。
参考:https://docs.unrealengine.com/5.2/en-US/include-what-you-use-iwyu-for-unreal-engine-programming/
我之前搭建引擎的时候,引擎用到的核心头文件,都放到hzpch.h文件里,然后引擎里的每个cpp都要在第一行#include "hzpch.h"
,大概是这样:
#pragma once
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <memory>
#include <map>
#include <unordered_map>
#include <set>
#include <functional>
#include "Hazel/Core/Log.h" // include了引擎自定义的头文件
#include <fstream>
#include <filesystem>
...
老版本的UE里,比如UE4.0的引擎源码里,基本也是这种模式,它把核心常用的文件全部放到了Engine.h
里,内部有众多Include文件:
// 它这里应该没用啥标准库的东西, 所以都是include的自定义头文件
#include "BlueprintUtilities.h"
#include "Tickable.h" // FTickableGameObject interface.
#include "RenderingThread.h" // for FRenderCommandFence
#include "GenericOctreePublic.h" // for FOctreeElementId
#include "RenderResource.h" // for FRenderResource
#include "HitProxies.h" // Hit proxy definitions.
#include "Engine/EngineBaseTypes.h"
...
然后每个cpp都在第一行引用Engine,h
,也就是常用的pch模式,Editor模块下的代码应该是统一引用UnrealEd.h
这种做法,叫做including monolithic header files
,对于引擎里的cpp而言,很多时候其实没必要include这么多内容,所以UE引入了IWYU,Include What You Use,这项技术一般只有引擎内部会使用IMYU,而项目是禁用IMYU的。注意IMYU并不是传统的cpp include header的方法,它仍然使用了PCH文件,只不过是不再需要在cpp的第一行include pch文件了,相关操作会借助UBT在命令行参数里执行
相关要点如下:
UseExplicitOrSharedPCHs
编译源码工程的时候出现的提示,貌似只是说这些代码不在原本的联合编译里,需要单独编译而已,应该不影响最终编译结果
参考:https://forums.unrealengine.com/t/how-to-prevent-plugin-recompilation/473557/5
参考:https://forums.unrealengine.com/t/engine-constantly-recompiles/438846/3
分为以下几种细分情况:
有几个疑问:
Build.cs
文件里可以设置bUsePrecompiled = true
,貌似可以防止Plugin Rebuild,这个参数怎么用?仔细看看Configuration,需要确保VS项目跟源码工程的Configuration Type相同,如果不是,改下VS项目的Configuration即可,应该就不需要Rebuild了
参考:https://docs.unrealengine.com/5.0/en-US/unreal-engine-build-tool-target-reference/
几个问题:
正常Build VS工程时,拿我写的游戏引擎举例,里面有这么些项目,除了Glad和GLFW里都是c语言的文件,其他的都是cpp工程:
一共七个项目,其中HazelEditor为启动项目,它依赖Hazel,而Hazel又依赖其他的五个项目
如果此时从零开始Build,此时会多线程一起开始build这五个前置项目,命令行输出的为:
Build started... 1>------ Build started: Project: imgui, Configuration: Debug x64 ------ 2>------ Build started: Project: YAML_CPP, Configuration: Debug x64 ------ 3>------ Build started: Project: Glad, Configuration: Debug x64 ------ 4>------ Build started: Project: GLFW, Configuration: Debug x64 ------ 5>------ Build started: Project: 2DPhysicsEngine, Configuration: Debug x64 ------ 1>imgui.cpp 2>binary.cpp 3>glad.c 4>context.c 5>b2_broad_phase.cpp 5>b2_chain_shape.cpp 4>egl_context.c 2>graphbuilder.cpp 5>b2_circle_shape.cpp 5>b2_collide_circle.cpp ... 3>Glad.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\Glad\bin\Debug-windows-x86_64\Glad\Glad.lib ... 1>Generating Code... ... 1>imgui.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\imgui\bin\Debug-windows-x86_64\imgui\imgui.lib 5>Generating Code... ... 4>Generating Code... ... 5>Generating Code... 5>Compiling... 5>b2_weld_joint.cpp 4>GLFW.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\GLFW\bin\Debug-windows-x86_64\GLFW\GLFW.lib 5>Generating Code... 5>2DPhysicsEngine.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\box2D\bin\Debug-windows-x86_64\2DPhysicsEngine\2DPhysicsEngine.lib ... 2>Generating Code... 2>Compiling... 2>Generating Code... 2>YAML_CPP.vcxproj -> D:\GitRepositories\Hazel\Hazel\vendor\yaml-cpp\bin\Debug-windows-x86_64\YAML_CPP\YAML_CPP.lib.
大概流程应该是:
Generating Code...
、或者Compiling...
之类的指令,应该是隔一段时间或编译一些文件就会打一次这个Log接下来也是类似的:
6>------ Build started: Project: Hazel, Configuration: Debug x64 ------ hzpch.cpp ... 6>Generating Code... ... 6>Compiling... 6>Ws2_32.lib(WS2_32.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored 6>Bcrypt.lib(bcrypt.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored 6>Version.lib(VERSION.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored 6>Winmm.lib(WINMM.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored 6>shaderc_sharedd.lib(shaderc_sharedd.dll) : warning LNK4006: __NULL_IMPORT_DESCRIPTOR already defined in opengl32.lib(OPENGL32.dll); second definition ignored 6>Hazel.vcxproj -> D:\GitRepositories\Hazel\bin\Debug-windows-x86_64\Hazel\Hazel.lib 6>Done building project "Hazel.vcxproj". 7>------ Build started: Project: HazelEditor, Configuration: Debug x64 ------ xxx.cpp ... 7>Defining YAML_CPP_API for DLL import ... 7>Generating Code... 7>D:\GitRepositories\Hazel\Hazel\Src\Hazel\Scripting\Scripting.h(36): warning C4172: returning address of local variable or temporary: value 7>Hazel.lib(object.obj) : warning LNK4099: PDB '' was not found with 'Hazel.lib(object.obj)' or at ''; linking object as if no debug info ... 7>HazelEditor.vcxproj -> D:\GitRepositories\Hazel\bin\Debug-windows-x86_64\HazelEditor\HazelEditor.exe 7>Done building project "HazelEditor.vcxproj". ========== Build: 7 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== ========== Build started at 4:25 PM and took 44.797 seconds ==========
当每个单独的Project build完毕后,打印一个总结
再来看看UE的build日志,UE5的build start project就叫UE5,它只依赖UnrealBuildTool
,如下图所示:
由于它使用了UBT,其Build Log会不太一样,因为工程太大了,这里选择Build而不是Rebuild,开头如下所示:
Build started...
1>------ Build started: Project: UE5, Configuration: Debug_Editor x64 ------
1>Using bundled DotNet SDK version: 6.0.302
1>Running UnrealBuildTool: dotnet "..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" -Target="UnrealEditor Win64 Debug" -Target="ShaderCompileWorker Win64 Development -Quiet" -WaitMutex -FromMsBuild
第三行并没有直接编译cpp的log信息,是因为UE5的Project Configuration Type并不是exe或者lib,而是Makefile类型,可以看到当前项目下的它的build命令行:
这意味着它会去调用Build.bat文件,看了下该文件,大概是以下步骤:
Build.bat文件信息如下,可以参考下:
setlocal enabledelayedexpansion // 1. cd到Source文件夹 if not exist "%~dp0..\..\Source" goto Error_BatchFileInWrongLocation pushd "%~dp0\..\..\Source" if not exist ..\Build\BatchFiles\Build.bat goto Error_BatchFileInWrongLocation // UBTPath为UnrealBuildTool.dll的相对路径 set UBTPath="..\..\Engine\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" // 2. 调用当前目录的GetDotnetPath.bat,获取.NET call "%~dp0GetDotnetPath.bat" if errorlevel 1 goto Error_NoDotnetSDK REM ## Skip msbuild detection if using dotnet as this is done for us by dotnet-cli rem ## If this is an installed build, we don't need to rebuild UBT. Go straight to building. if exist ..\Build\InstalledBuild.txt goto ReadyToBuild rem ## Compile UBT if the project file exists :ReadyToBuildUBT set ProjectFile="Programs\UnrealBuildTool\UnrealBuildTool.csproj" if not exist %ProjectFile% goto NoProjectFile rem ## Only build if UnrealBuildTool.dll is missing, as Visual Studio or GenerateProjectFiles should be building UnrealBuildTool rem ## Note: It is possible UnrealBuildTool will be out of date if the solution was generated with -NoDotNet or is VS2019 rem ## Historically this batch file did not compile UnrealBuildTool if not exist %UBTPath% ( rem ## If this script was called from Visual Studio 2022, build UBT with Visual Studio to prevent unnecessary rebuilds. if "%VisualStudioVersion%" GEQ "17.0" ( echo Building UnrealBuildTool with %VisualStudioEdition%... "%VSAPPIDDIR%..\..\MSBuild\Current\Bin\MSBuild.exe" %ProjectFile% -t:Build -p:Configuration=Development -verbosity:quiet -noLogo if errorlevel 1 goto Error_UBTCompileFailed ) else ( echo Building UnrealBuildTool with dotnet... dotnet build %ProjectFile% -c Development -v quiet if errorlevel 1 goto Error_UBTCompileFailed ) ) :NoProjectFile rem ## Run UBT :ReadyToBuild if not exist %UBTPath% goto Error_UBTMissing echo Running UnrealBuildTool: dotnet %UBTPath% %* dotnet %UBTPath% %* EXIT /B !ERRORLEVEL! :Error_BatchFileInWrongLocation echo ERROR: The batch file does not appear to be located in the Engine/Build/BatchFiles directory. This script must be run from within that directory. EXIT /B 999 :Error_NoDotnetSDK echo ERROR: Unable to find an install of Dotnet SDK. Please make sure you have it installed and that `dotnet` is a globally available command. EXIT /B 999 :Error_UBTCompileFailed echo ERROR: Failed to build UnrealBuildTool. EXIT /B 999 :Error_UBTMissing echo ERROR: UnrealBuildTool.dll not found in %UBTPath% EXIT /B 999
总的来说,在Build UE5这个project时,它这个Makefile工程所做的,其实就是调用UnrealBuildTool.exe而已,只是个空壳子,我试了下,可以直接在Build.bat路径下,直接在命令行输入以下指令,一样会触发编译:
F:\UnrealEngine\Engine\Build\BatchFiles>dotnet "..\..\Binaries\DotNET\UnrealBuildTool\UnrealBuildTool.dll" -Target="UnrealEditor Win64 Debug" -Target="ShaderCompileWorker Win64 Development -Quiet" -WaitMutex -FromMsBuild
这里的dotnet貌似是.NET Core提供的命令行关键字,用于调用.NET程序,不过这里居然调用的是dll,不是exe,也是挺奇怪的,如下图所示是该命令的介绍:
参考:UE4 UnrealBuildTool 执行流程
参考:Build flow of the Unreal Engine4 project
Build.bat会把参数都传给UnrealBuildTool.exe,参数可以在bat里看到:
rem ## %1 is the game name
rem ## %2 is the platform name
rem ## %3 is the configuration name
rem ## additional args are passed directly to UnrealBuildTool
命令行举例:
三个参数分别为:game name、 platform name、configuration name
UnrealBuildTool.exe MyTest Win64 Development "C:\Users\visionsmile\Documents\Unreal Projects\Examples\MyTest \MyTest .uproject" -WaitMutex -FromMsBuild
对应到下面的参数,就是这上面的六个参数,最后一个为-FromMsBuild
/// <summary>
/// Main entry point. Parses any global options and initializes the logging system, then invokes the appropriate command.
/// NB: That the entry point is deliberately NOT async, since we have a single-instance mutex that cannot be disposed from a different thread.
/// </summary>
/// <param name="ArgumentsArray">Command line arguments</param>
/// <returns>Zero on success, non-zero on error</returns>
private static int Main(string[] ArgumentsArray)
{
...
虽然这里的Build.bat
传入了三个参数,但UBT实际需要四个参数:
%1 is the game name
%2 is the platform name
%3 is the configuration name
%4 is the ProjectPath
直接打开UBT对应的.sln
文件,在Main函数里可以输入Commandline参数,直接Debug进行编译:
private static int Main(string[] ArgumentsArray)
{
ArgumentsArray = new string[]
{
"-Target=UnrealEditor Win64 Debug",
"-Target=ShaderCompileWorker Win64 Development -Quiet",
"-WaitMutex",
"-FromMsBuild"
};
...
}
UBT会创建帮助编译的Makefile.bin
文件,比如生成以下路径的MakeFile:
F:\UnrealEngine\Engine\Intermediate\Build\Win64\x64\UnrealEditor\Debug\Makefile.bin
这玩意儿是个二进制文件,很难直接阅读,这里来研究一下UBT写入了什么内容。为了生成MakeFile,UBT首先要确定build的目标,因而创建一个UEBuildTarget
类的对象,如下所示:
// If we couldn't load a makefile, create a new one
if(Makefile == null)
{
// Create the target
UEBuildTarget Target;
...
}
看了下创建出来的BuildTarget对象,貌似它要Build的分为四种Module
这个Extra Module是在Target.cs里决定的,如下所示是引擎的UnrealEditor.Target.cs
:
public class UnrealEditorTarget : TargetRules
{
public UnrealEditorTarget( TargetInfo Target ) : base(Target)
{
Type = TargetType.Editor;
IncludeOrderVersion = EngineIncludeOrderVersion.Latest;
BuildEnvironment = TargetBuildEnvironment.Shared;
bBuildAllModules = true;
ExtraModuleNames.Add("UnrealGame");
}
}
各自的Module都对应了各自的Build.cs文件,路径依次为:
ModuleNameToModuleFile["Launch"] {F:\UnrealEngine\Engine\Source\Runtime\Launch\Launch.Build.cs} EpicGames.Core.FileReference
数了下引擎里有1743个Build.cs文件,这里创建的BuildTarget里的Binaries数组有1453个元素,感觉是差不多对应的上的,这里会先处理Launch Module,处理的过程应该是个DFS的过程,如下图所示,可以看到它依赖了63个Module,应该是全游戏需要的Module的Root
Launch Module对应了文件,也即UE提供的四个引擎Target.cs文件之一,
TargetRulesFile {F:\UnrealEngine\Engine\Source\UnrealEditor.Target.cs} EpicGames.Core.FileReference
这个cpp是由UBT生成的,可以看下里面的内容:
// This file is automatically generated at compile-time to include some subset of the user-created cpp files.
#include "../Plugins/Experimental/Animation/PoseSearch/Intermediate/Build/Win64/UnrealEditor/Inc/PoseSearchEditor/UHT/AnimationBlendStackGraph.gen.cpp"
...
#include "../Plugins/Experimental/Animation/PoseSearch/Source/Editor/Private/AnimationBlendStackGraphSchema.cpp"
...
貌似是把项目里所有的cpp
文件和.gen.cpp
文件,都include进来了,这里有几个问题:
我顺便查了下我之前写的AnimationPreviewLibrary
的Editor Plugin,里面创建了四个cpp,UE的UBT同样在对应的intermediate文件夹里生成了Module.AnimationPreviewLibrary.cpp
,如下所示:
// This file is automatically generated at compile-time to include some subset of the user-created cpp files.
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/AnimationPreviewLibrary.cpp"
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/AnimationPreviewLibraryCommands.cpp"
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/AnimationPreviewLibraryStyle.cpp"
#include "F:/UnrealProjects/MyProjectUE5_1_0/Plugins/AnimationPreviewLibrary/Source/AnimationPreviewLibrary/Private/SAnimPreviewLibraryWindowMenu.cpp"
我理解这个文件,就是为了方便编译的,搞个unity file,把一个模块的所有的cpp都引入进去,方便管理,这样一来,比如UE有130个Module,那就只需要编译和link这130个各自Module对应的cpp文件(类似于Translation Unit)即可
如下是UBT的流程
UBT会为Module生成一个特殊的cpp文件,Build的时候去编译这个cpp,Link对应的object即可,在此过程中,UBT还生成了涉及到宏的Definition.xxx.h文件,如下图所示:
几个问题:
这个文件还有别于这里的Module.xxxx.cpp,因为实际工程里是不需要后者这个unity file的,而这个Definitions.xxx.h里的宏则是实际工程里需要的,如下图所示,我这里的工程貌似没找到此文件,所以辨认不出这个宏:
宏的颜色应该是紫色的,这里的intellisense都没辨认出来是宏,所以相关的intellisense都失效了,虽然build是没有任何问题的,但这个问题很影响我看代码了,我可以临时参照Definition文件加一句这个:
#ifndef POSESEARCH_API
#define POSESEARCH_API DLLIMPORT
#endif
但还是挺难受的,所以这里的问题是,这里面定义的宏,是如何影响到VS项目里的高亮的,为啥有的项目里F12能直接跳转到Definition.xxx.h文件,但是工程里又搜不到此文件:
C++工程创建插件时报错,显示Unable to create plugin,如下图所示:
有时候删除所有的中间文件(包括Plugin的中间文件)、在Regenerate Sln文件后,就可以打开了。但我在创建第三方插件时,怎么做都会报这个错。图中的Output log应该指的是Console,重点信息如下:
Building 5 actions with 5 processes...
[1/5] Resource Default.rc2
[2/5] Link [x64] UnrealEditor-ffff3213213-Win64-DebugGame.dll cancelled
[3/5] Link [x64] UnrealEditor-ffff3213213-Win64-DebugGame.lib cancelled
[4/5] Compile [x64] ffff3213213.cpp
F:\UnrealProjects\MotionMatchingDemoDebug\Plugins\ffff3213213\Source\ffff3213213\Private\ffff3213213.cpp(7): fatal error C1083: Cannot open include file: 'ffff3213213Library/ExampleLibrary.h': No such file or directory
[5/5] WriteMetadata MotionMatchingDemoEditor-Win64-DebugGame.target cancelled
最后大概找到原因了,我是用自己的引擎版本创建的VS工程,然后我删除中间文件后,右键uproject Regenerate Sln文件却是用的安装好的UE引擎,此时去创建就会有问题(具体原因是为什么,我还不确定,中间文件不是都删除了么,跟引擎版本应该没有关系啊?)
我把中间文件全删了,然后源码直接attach uproject文件,再在Editor里生成VS工程,再去创建第三方插件,就可以了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。