正确引用第三方module

假设已有一个第三方module,要在你自己的module中使用它。
第三方module命名为M3,自己的module命名为M1. 即M1中要使用M3.
正确的引用方法是在M1的M1.build.cs文件中设定如下字段:
 PublicDependencyModuleNames或PrivateDependencyModuleNames中添加M3,如果引用M3中功能的代码是在M1的Public源码中,则加到PublicDependency里,反之,如果是在M1的Private源码中引用M3中的功能,则加到PrivateDependency里。如果在M1的Public和Private源码中均引用了M3中的功能,则应该把M3同时添加到PublicDependency和PrivateDependency中。
上面对DependencyModule的设置对应toolchain里的静态链接,即保证M1对M3中的对象或功能的引用能找到实现。但是它不完全解决头文件包含层面的问题。不完全的意思是有时候不用处理头文件包含的事情也没问题发生,有时候不处理头文件包含的事情就有问题发生。不用处理也没有问题发生的情形是:M3中的功能实现,其对应的头文件都加到了M3的PublicIncludePaths中,那么M1中引用M3的该功能时,不用额外处理头文件包含事宜。相应的,有问题的情形是:M3中实现了某个功能,但其相关头文件没有加入到M3的PublicIncludePaths中。此时M1的某个cpp中调用M3里的一个函数时,编译器会报告找不到函数声明。这种有问题的情况,可以通过将M3中相应的路径加到M1的PublicIncludePaths或PrivateIncludePaths中来解决
 假设M3的某项功能实现在M3/Private中。当在M1的Public源码中使用M3的这项功能时,可将M3/Private添加到M1的PublicIncludePaths中。当在M1的Private源码中使用M3的这项功能时,可将M3/Private添加到M1的PrivateIncludePaths中。同时,在cpp中需用#include "M3/Private/xxx.h"来引用头文件。
 PrivateIncludePaths.AddRange(
			new string[] {
				// ... add other private include paths required here ...
				System.IO.Path.Combine(GetModuleDirectory("LevelEditor"), "Private"),
			}
			);
还有一种需求:引用第三方module里的C++模板定义或抽象接口等,一般就是一些类模板和函数模板的C++头文件。这些头文件由于只包括模板或抽象接口,所以是功能完备且独立的,此种需求下,我们只需要访问这些模板或抽象接口,不需要除此之外的整个第三方module,那就可以设置PrivateIncludePathModuleNamesPublicIncludePathModuleNames这两个属性。这两个属性给予对第三方module里某些路径的代码访问权限,同时不会将第三方module的dll或lib链接到最终的exe中。

module的build.cs文件里的bPrecompile要设置为true

当以二进制方式发布插件时,对于4.22.0(不包括4.22.0)之后的版本,需要显式的设置
 bPrecompile = true
然后对插件进行package操作,这样在插件的Intermediate目录中会生成对应的.precompiled文件,该文件用于指明obj文件。 发布后,还需要设置:
 bUsePrecompiled = true
这样,用户端就能直接Link precompiled文件中指明的obj了,不依赖插件源码来打包。
 在UE4.27里经过实测:package出来的Plugins,可以删除Intermediate目录,可以删除Binaries目录下的pdb文件,在module.build.cs里需要添加bUsePrecompiled=true;如此操作后,即便在visual studio里rebuild工程,也不会将插件rebuild,因此是安全的,但是rebuild操作会将插件Binaries目录下的dll文件删除,因此rebuild后需要将这些被删除的dll还原,无需其他操作。且整个过程中bPrecompile字段不是必须的。但与此同时,在保持这些设置的前提下,对整个工程进行打包时,又会提示找不到precompiled manifest文件,因此针对打包工程的需求,仍然需要插件的Intermediate目录。

module.build.cs文件常见字段

string path = Path.Combile(p1, p2, p3);
string absolutePath = Path.GetFullPath(path);
//https://docs.unrealengine.com/4.27/en-US/ProductionPipelines/BuildTools/UnrealBuildTool/ThirdPartyLibraries/
RuntimeDependencies.Add(Path.GetFullPath(absolutePath), StagedFileType.NonUFS);
if (Target.bBuildEditor)判断当前build配置是否包含Editor

PublicDependencyModuleNames/PrivateDependencyModuleNames属于静态链接,通常其PublicIncludePaths/PrivateIncludePaths会自行处理正确。
PublicIncludePathModuleNames/PrivateIncludePathModuleNames与DynamicallyLoadedModuleNames配合属于动态链接,因此如果你使用了非抽象函数,则会提示无法找到链接符号。这一对配置的典型用法参考 #474,一般就是LoadModuleChecked,然后调用接口的抽象函数。

关于PublicSystemLibraryPaths,PublicAdditionalLibraries,PublicLibraryPaths的问题

在(<)UE4.24的版本中,指定lib文件的方法跟visual studio里使用的方式一致:
  1. PublicLibraryPaths用于添加lib文件所在的目录
  2. PublicAdditionalLibraries用于添加lib文件,不包括路径信息
引擎寻找lib文件的方式就是将上面这两个选项指定的字符串进行组合拼接,验证拼接后字符串是否为有效路径。这个过程是很慢的,因此从UE4.24版本开始,引擎推荐如下使用方式解决这个问题:
  • 忽略PublicLibraryPaths字段,且PublicAdditionalLibraries字段直接添加lib文件绝对路径。
如果仍坚持老的使用方式,则会报Warning,用以下方式可以消除这个Warning,但并不能消除老的方式的效率低下的问题:
  1. PublicSystemLibraryPaths取代PublicLibraryPaths,用于添加lib文件所在的目录
  2. PublicSystemLibraries来添加库文件,但只需要库的名字即可,不需要后缀。或者直接在cpp中用#pragma comment(lib,"avcodec.lib")这种写法,会从PublicSystemLibraryPaths指定的目录下去寻找

定义宏macro

PublicDefinitions.Add("MacroName=MacroBody");