前文说到ue3开始,虚幻就使用了unrealbuildtool(以下简称ubt)来编译和生成代码。
为什么这么做而不是使用vs是很好理解的:因为vs跨平台会比较麻烦。像虚幻这样体量的工程,单为工程做一次vs配置就基本是一天的时间
而且ue4还不像ue3那样就十几个工程,把所有uproject都看做工程的话,得几十了。依赖关系复杂度几何增长,用vs的工具去维护……而且要维护各个平台和配置……再加上维护完后mac、linux还得维护一遍……
但是为什么不使用成熟的cmake呢,私以为可能是因为ubt里有一系列错综复杂的规则,用cmake制作出来,即便可读性ok,调试也比较麻烦。而且cmake对引擎使用者提出了一定的要求,而ubt则相对简单——只要你不纠结它如何实现。
官网的这篇文章详细解释了为什么要做一个build tool出来:
what are the advantages of generating project files?
可以先看看ubt的基本规则:
目前说来,虚幻的所有代码集中在下面几个文件夹里:
<root>的source,这个文件夹里主要是引擎代码。
其中:
source/runtime里主要是引擎的核心代码。
source/developer里似乎主要是一些工具工程。
source/editor里是编辑器相关代码。
source/programs里是引擎使用中需要用到的工具。比如ubt、unrealheadertool、swarm(分布式光照计算系统)等等。
source/thirdparty里是各种第三方库。
<root>的plugin,这个文件夹里有各式各样的plugin实现。特殊的是plugin的组织中需要多一个uplugin,可能是plugin下可能会有一些资源什么的吧。我们后面再来看uplugin。
<工程项目>的source,如果是代码工程的话。
ubt目前只认这几个文件夹,也就是说,如果你要为引擎扩展功能,您只能在这些文件夹里创建自己的工程。这一点是在ubt里写死的,有代码的可以关注一下ubt工程的findallrulessourcefiles这个方法。
在这些文件夹里,您可以搜索到大量的*.build.cs文件,这些build.cs就是虚幻的工程组织核心,基本上,每个build文件都可以被视为一个工程文件,而build文件所在的文件夹可以被视为此工程的根目录。接下来,我们不妨称这些拥有build.cs的文件夹为工程。ubt一开始会先去找所有的build.cs,把它们放在一起生成一个临时的dll。然后基于它们逐个进行一系列的代码分析工作,最后调用命令行进行编译和连接过程。
对于每个工程而言,代码一般都散落在下面几个文件夹:
classes:如果你在工程根目录下写了个classes,就相当于告诉ubt这些文件是要用unrealheadertool来生成运行时反射信息的。所以,这个文件夹里头文件的写法必须符合可反射类的写法规范。
还记得虚幻的哪些类是可反射的吗?对了,所有uobject的派生类包括aactor的派生类。具体是否有所验证还没看,不过最好是按照这个节奏来。
规范上无非主要就是ustruct、uclass这些宏,抄几个就能找到感觉,或者用编辑器的类生成功能也可。
看起来,虚幻引擎发布时(不是通过编译生成,而是通过launcher下载的那种),这些classes文件是随引擎发布的,方便不具备全代码的mod爱好者和blueprint开发者们来制作游戏。
public:公共头文件,跟classes一样随着引擎发布而发布,所以这里一般都是些比较开放的接口,比如模块入口、功能核心接口什么的。基本上这些接口没有废话,很清晰,跟实现相关的细节隐藏得非常好。与classes相同,如果你的工程里有public,那么里面的.h就会被当作public来。
private:这个文件夹似乎不是虚幻定死的,也就是似乎可以不用private的名字,或者多来几个文件夹什么的。除了uht中有一段代码与之有一定关联之外,ubt里是完全没有跟这个有关的东西。它里面基本上就是各种实现代码,以及要在实现间共享的头文件。你也可以创建其他类似的文件夹,只需要build.cs里写上相应的文件夹名即可:

此外还有需要注意的地方是source根目录下的target.cs文件,target的最终目标一般都是可执行文件,可以说,target是整个生成期的入口,生成会首先从找到target开始,如果没有target或者找不到,就会直接失败。
此外,需要注意的是,target.cs里面写的类的类名,必须是target.cs的文件名加target,例如:sample.target.cs,其类名必须是sampletarget。ubt的gettargettypeandrulesinstance方法里印证了这一点。
ubt里面还是有不少限定用法的,target就是其中之一,虚幻是一个比较强调命名的引擎,改名有很多麻烦,最好是能够一步到位。
今天抽空看了看文档,大概跟了跟ubt的流程,明天继续。