适用于自定义编译平台和编译符合,把C#源码文件编译成dll。(用于InjectFix之类的热更方案)
适用于unity2017环境,代码暂时不方便贴出记述一下思路。
参考:Unity官方C#源码 https://github.com/Unity-Technologies/UnityCsReference
1. 通过反射取用一些访问不到的Editor代码
- GetCompilationDefines(EditorScriptCompilationOptions, BuildTargetGroup, BuildTarget)
- GetUnityAssmblies(bool, BuildTargetGroup, BuildTarget)
- GetPrecompiledAssemblies(bool, BuildTargetGroup, BuildTarget)
- CompatibilityProfileToClassLibFolder(ApiCompatibilityLevel)
直接复制源码过来改动
- struct PrecompiledAssembly
- enum EditorScriptCompilationOptions
- class MonoInstallationFinder
2. Unity编译dll的原理
- 先生成一个编译参数的清单文件,包括编译符号定义、源代码文件、库引用等,可以在项目目录下的
Temp/UnityTempFile-XXXXX
查看。 - 之后会通过类似
mono.exe mcs.exe @Temp/UnityTempFile-XXX
的命令来启动编译器进行编译
已经很明显了,要实现自定义编译dll,主要解决两个问题:
- 怎么找到mono和mcs的路径
- 怎么生成清单文件
3. 找到mono和mcs的路径
在MonoInstallationFinder.cs
中直接增加函数
public static string GetMonoProfileLibDirectory(BuildTarget group)
{
ApiCompatibilityLevel compatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(group);
string profile;
string monoInstall;
// 因为生产环境配置比较固定, 写的比较糙
// 具体可查阅"mono"和"MonoBleedingEdge"文件夹的区别(旧版本|新版本)
if (compatibilityLevel == ApiCompatibilityLevel.NET_2_0)
{
profile = "2.0-api";
monoInstall = MonoBleedingEdgeInstallation;
}
else
{
profile = "unity"; // .net-2.0-subset
monoInstall = MonoInstallation;
}
}
4. 生成清单文件
unity2017对自定义dll名称有一定支持,但不是太好,还是使用默认的"Assembly-CSharp"这些,参考官方说明 https://docs.unity3d.com/2017.4/Documentation/Manual/ScriptCompileOrderFolders.html
写一个枚举方便使用
enum UnityDllNames
{
Assembly_CSharp_firstpass,
Assembly_CSharp,
Assembly_CSharp_Editor_firstpass,
Assembly_CSharp_Editor,
}
可以写出根据文件路径判断所属dll的函数UnityDllNames GetDllType(string path)
, 根据这四个dll的依赖关系,可以写出判断dll是否需要引用的参数bool NeedDllRef(UnityDllNames dll, UnityDllNames refDll)
,源代码文件很容易就可以列出来了
项目内的dll文件,结合路径和PluginImporter的值来判断是否引用;比较难处理的是Unity自己提供的引用
- 通过最开始提到的
GetUnityAssemblies()
和GetPrecompiledAssemblies()
可以获取部分,非编辑器构建下需要额外排除名字带有"Editor"的引用 - 还有一些额外的固定引用,通过
GetMonoProfileLibDirectory()
获取路径拼接,System.Runtime.Serialization.dll
,System.Xml.Linq.dll
,UnityScript.dll
,UnityScript.Lang.dll
,Boo.Lang.dll
- 可能还有一些遗漏或不一致的。如果不是直接在实际游戏中用到这个编译出来的dll,不需要做到和Unity生成的完全一致
通过GetCompilationDefines()
获取编译符号定义
存在mcs.rsp
的加一下
5. 执行编译
生成清单文件后,找到对应的mono、mcs路径,拼接执行即可,一般是MonoBleedingEdge/bin/mono.exe
和MonoBleedingEdge/lib/mono/4.5/mcs.exe