美文网首页UnityEditorunity
[Unity 3d] 编辑器程序集编译API - 笔记

[Unity 3d] 编辑器程序集编译API - 笔记

作者: 雨落随风 | 来源:发表于2022-05-10 23:50 被阅读0次

    本文是个笔记,记录 2 个编辑器下编译程序集的逻辑。

    一 . 编译 Runtime 用的程序集

    Runtime 用的程序集:特征是会剔除 #if UNITY_EDITOR 注释的逻辑块)

      public static void OnAssemblyBuildRequired()
            {
                // todo 目前是全部都编译,有木有方法只编译需要的 程序集呢?
                var buildDir = Application.temporaryCachePath;
                var files = new DirectoryInfo(buildDir).GetFiles();
                foreach (var file in files)
                {
                    FileUtil.DeleteFileOrDirectory(file.FullName);
                }
                
                var target = EditorUserBuildSettings.activeBuildTarget;
                var group = BuildPipeline.GetBuildTargetGroup(target);
                ScriptCompilationSettings scriptCompilationSettings = default;
                scriptCompilationSettings.group = group;
                scriptCompilationSettings.target = target;
    
                ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
                var lib_dir = Path.Combine(Application.dataPath, "..", "Library\\ScriptAssemblies");
                foreach (var item in Instance.assemblies)
                {
                    if (item.IsValid)    // 如果配置正确则尝试转存储文件
                    {
                        var file = new FileInfo(Path.Combine(lib_dir, item.Dll));
                        var lastWriteTime = file.LastWriteTime.Ticks;
                        if (item.lastWriteTime < lastWriteTime)
                        {
                            item.lastWriteTime = lastWriteTime;
                            FileUtil.ReplaceFile(Path.Combine(buildDir, item.Dll), item.OutputPath);
                            item.UpdateInformation();
                        }
                    }
                    else
                    {
                        Debug.LogError($"{nameof(AssemblyHotfixManager)}: 请先完善 Hotfix Configuration 配置项!");
                    }
                }
                EditorUtility.SetDirty(Instance);
            }
    
    • 关键 API : PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir)
    • Build App 使用的这个API
    • Addressable 也是这个API

    二 . 编译指定 .asmdef 定义的程序集

       public static void SyncAssemblyRawData(bool forceCompilie = false)
        {       
               // 1.  dll 编译存放处
                var lib_dir = Path.Combine(Application.dataPath, "..", "Library\\ScriptAssemblies");
                foreach (var item in Instance.assemblies)
                {
                    // 如果配置正确则开始尝试编译
                    if (item.IsValid)
                    {
                        var data = JsonUtility.FromJson<SimplifiedAssemblyData>(item.assembly.text);
                        var dll = Path.Combine(lib_dir, $"{data.name}.dll");
                        var temp = Path.Combine(Application.temporaryCachePath, $"{data.name}.bytes");
                        var file = new FileInfo(dll);
                        if (file.Exists)
                        {
                            var lastWriteTime = file.LastWriteTime.Ticks;
                            if (forceCompilie || item.lastWriteTime < lastWriteTime)
                            {
                                item.lastWriteTime = lastWriteTime;
                                var assembly = CompilationPipeline.GetAssemblies(AssembliesType.Player).FirstOrDefault(v => v.name == item.assembly.name);
                                if (null != assembly)
                                {
                                    // Compiles scripts outside the Assets folder into a managed assembly that can be used inside the Assets folder.
                                    AssemblyBuilder builder = new AssemblyBuilder(temp, assembly.sourceFiles);
                                    builder.compilerOptions.AllowUnsafeCode = item.AllowUnsafeCode;
                                    BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
                                    builder.compilerOptions.ApiCompatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup);
                                    builder.additionalReferences = assembly.allReferences;
                                    builder.flags = AssemblyBuilderFlags.None;
                                    // todo: 以下动作会导致程序集完成编译后IDE 报错,待确认:减少编译频率,变成 aa build 时编译,同时看能不能将 csproj 回到原点
                                    builder.referencesOptions = ReferencesOptions.UseEngineModules;
                                    builder.buildTarget = EditorUserBuildSettings.activeBuildTarget;
                                    builder.buildTargetGroup = buildTargetGroup;
                                    builder.excludeReferences = new string[] { assembly.outputPath };
                                    builder.additionalDefines = assembly.defines;
                                    builder.compilerOptions = assembly.compilerOptions;
                                    builder.buildFinished += (arg1, arg2) =>
                                    {
                                        bool noErr = true;
                                        foreach (var msg in arg2)
                                        {
                                            if (msg.type == CompilerMessageType.Error)
                                            {
                                                Debug.LogError(msg.message);
                                                noErr = false;
                                            }
                                            else if (msg.type == CompilerMessageType.Warning)
                                            {
                                                Debug.LogWarning(msg.message);
                                            }
                                            else
                                            {
                                                Debug.Log(msg.message);
                                            }
                                        }
                                        if (noErr)
                                        {
                                            FileUtil.ReplaceFile(temp, item.OutputPath);
                                            item.UpdateInformation();
                                        }
    
                                    };
                                    if (!builder.Build())
                                    {
                                        Debug.LogError($"{nameof(AssemblyHotfixManager)}: Assembly {item.Dll} Build Fail!");
                                    }
                                    else
                                    {
                                        Debug.Log($"{nameof(AssemblyHotfixManager)} 热更程序集: <color=yellow>{item.Dll} </color> 完成构建!");
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        Debug.LogError($"{nameof(AssemblyHotfixManager)}: 请先完善 Hotfix Configuration 配置项!");
                    }
                    EditorUtility.SetDirty(Instance);
                    AssetDatabase.Refresh();
                }
            }
    
    • 关键 API: AssemblyBuilder.referencesOptions = ReferencesOptions.UseEngineModules; 编译为 Runtime 程序集
    • 这个类主要用于将 Assets 文件夹以外的 Assembly 进行编译并放回到 Assets 中使用
    • 这个类使用的编译器不同于 PlayerBuildInterface.CompilePlayerScripts ,编译时会修改所有的 .sln 和 .csproj 文件
    • 上述代码并不完善,剩余部分在:这里

    总结说明:

    1. 用 Assembly Definition File 定义的程序集在 Unity 中会编译成编辑器下使用的 dll 和 打包后使用的 dll 这 2种情况,编辑器环境加载的多为第一种,后者则是在用户 Build app 或者可寻址 build 时才会触发构建。
    2. 这两种情况的程序集,在 Unity 内部的概念种分别叫:EditorAssemblies 、PlayerAssembles;
    3. 这俩程序集最大特点是宏 #if UNITY_EDITOR 包裹的逻辑是否被剔除,以及是否引使用了 EngineModules.
    4. 按照自己的理解,有朋友会将 PlayerAssemblies 说成"Runtime 用的 dll ",或者说成 “Release 版本的 dll ”,虽五花八门,但经得起推敲哈。
    5. 当然,可以自己使用 Roslyn 编译哈,别问,问就是可行,我朋友试过了~

    相关文章

      网友评论

        本文标题:[Unity 3d] 编辑器程序集编译API - 笔记

        本文链接:https://www.haomeiwen.com/subject/zkprurtx.html