public MonoIsland ToMonoIsland(EditorScriptCompilationOptions options, string buildOutputDirectory, string projectPath = null)
        {
            bool buildingForEditor = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor;
            bool developmentBuild  = (options & EditorScriptCompilationOptions.BuildingDevelopmentBuild) == EditorScriptCompilationOptions.BuildingDevelopmentBuild;

            var references = ScriptAssemblyReferences.Select(a => AssetPath.Combine(a.OutputDirectory, a.Filename));

            var referencesArray = references.Concat(References).ToArray();

            var responseFileProvider = Language?.CreateResponseFileProvider();

            if (!string.IsNullOrEmpty(projectPath) && responseFileProvider != null)
            {
                responseFileProvider.ProjectPath = projectPath;
            }

            List <string> reposeFiles = responseFileProvider?.Get(OriginPath) ?? new List <string>();

            var outputPath = AssetPath.Combine(buildOutputDirectory, Filename);

            return(new MonoIsland(BuildTarget,
                                  buildingForEditor,
                                  developmentBuild,
                                  CompilerOptions.AllowUnsafeCode,
                                  CompilerOptions.ApiCompatibilityLevel,
                                  Files,
                                  referencesArray,
                                  Defines,
                                  outputPath,
                                  reposeFiles.ToArray()));
        }
        public static bool IsReferenceAssemblyUnchanged(ScriptAssembly assembly, string outputDirectory)
        {
            var referenceAssemblyPath = AssetPath.Combine(outputDirectory, assembly.ReferenceAssemblyFilename);
            var assemblyFileHashPath  = AssetPath.Combine(outputDirectory, $"{assembly.Filename}.hash");

            return(IsFileUnchanged(referenceAssemblyPath, assemblyFileHashPath));
        }
        public static void UpdateScriptAssemblyReference(ref ScriptAssembly scriptAssembly)
        {
            int referencesLength = scriptAssembly.References.Length;
            var newReferences    = new string[referencesLength + 1];

            Array.Copy(scriptAssembly.References, newReferences, referencesLength);
            newReferences[referencesLength] = AssetPath.Combine(EditorApplication.applicationContentsPath, "Managed", "Unity.CompilationPipeline.Common.dll");
            scriptAssembly.References       = newReferences;
        }
        public static ScriptAssembly[] GetAllScriptAssemblies(
            Dictionary <string, string> allSourceFiles,
            String projectDirectory,
            ScriptAssemblySettings settings,
            CompilationAssemblies assemblies,
            ISafeModeInfo safeModeInfo,
            TargetAssemblyType onlyIncludeType = TargetAssemblyType.Undefined,
            Func <TargetAssembly, bool> targetAssemblyCondition = null,
            ICompilationSetupWarningTracker warningSink         = null)
        {
            if (allSourceFiles == null || allSourceFiles.Count == 0)
            {
                return(new ScriptAssembly[0]);
            }

            var targetAssemblyFiles = new Dictionary <TargetAssembly, DirtyTargetAssembly>();

            foreach (var entry in allSourceFiles)
            {
                var scriptFile     = entry.Key;
                var assemblyName   = entry.Value;
                var targetAssembly = GetTargetAssembly(scriptFile, assemblyName, projectDirectory, assemblies.CustomTargetAssemblies);

                if (targetAssembly == null)
                {
                    continue;
                }

                if (!IsCompatibleWithPlatformAndDefines(targetAssembly, settings))
                {
                    continue;
                }

                if (targetAssemblyCondition != null && !targetAssemblyCondition(targetAssembly))
                {
                    continue;
                }

                // Optionally only include specific TargetAssemblyType assemblies.
                if (onlyIncludeType != TargetAssemblyType.Undefined && targetAssembly.Type != onlyIncludeType)
                {
                    continue;
                }

                DirtyTargetAssembly dirtyTargetAssembly;

                if (!targetAssemblyFiles.TryGetValue(targetAssembly, out dirtyTargetAssembly))
                {
                    dirtyTargetAssembly = new DirtyTargetAssembly();
                    targetAssemblyFiles[targetAssembly] = dirtyTargetAssembly;
                }

                dirtyTargetAssembly.SourceFiles.Add(AssetPath.Combine(projectDirectory, scriptFile));
            }

            return(ToScriptAssemblies(targetAssemblyFiles, settings, assemblies, warningSink, safeModeInfo));
        }
示例#5
0
        public MonoIsland ToMonoIsland(EditorScriptCompilationOptions options, string buildOutputDirectory)
        {
            bool editor                = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor;
            bool development_player    = (options & EditorScriptCompilationOptions.BuildingDevelopmentBuild) == EditorScriptCompilationOptions.BuildingDevelopmentBuild;
            IEnumerable <string> first = from a in this.ScriptAssemblyReferences
                                         select AssetPath.Combine(a.OutputDirectory, a.Filename);

            string[] references = first.Concat(this.References).ToArray <string>();
            string   output     = AssetPath.Combine(buildOutputDirectory, this.Filename);

            return(new MonoIsland(this.BuildTarget, editor, development_player, this.ApiCompatibilityLevel, this.Files, references, this.Defines, output));
        }
示例#6
0
        public static ScriptAssembly[] GetAllScriptAssemblies(IEnumerable <string> allSourceFiles, string projectDirectory, ScriptAssemblySettings settings, CompilationAssemblies assemblies, TargetAssemblyType onlyIncludeType = TargetAssemblyType.Undefined)
        {
            if (allSourceFiles == null || allSourceFiles.Count() == 0)
            {
                return(new ScriptAssembly[0]);
            }

            var targetAssemblyFiles = new Dictionary <TargetAssembly, HashSet <string> >();

            foreach (var scriptFile in allSourceFiles)
            {
                var targetAssembly = GetTargetAssembly(scriptFile, projectDirectory, assemblies.CustomTargetAssemblies);

                if (!IsCompatibleWithPlatform(targetAssembly, settings))
                {
                    continue;
                }

                // Optionally only include specific TargetAssemblyType assemblies.
                if (onlyIncludeType != TargetAssemblyType.Undefined && targetAssembly.Type != onlyIncludeType)
                {
                    continue;
                }

                var scriptExtension = ScriptCompilers.GetExtensionOfSourceFile(scriptFile);
                var scriptLanguage  = ScriptCompilers.GetLanguageFromExtension(scriptExtension);

                if (targetAssembly.Language == null && targetAssembly.Type == TargetAssemblyType.Custom)
                {
                    targetAssembly.Language = scriptLanguage;
                }

                HashSet <string> assemblySourceFiles;

                if (!targetAssemblyFiles.TryGetValue(targetAssembly, out assemblySourceFiles))
                {
                    assemblySourceFiles = new HashSet <string>();
                    targetAssemblyFiles[targetAssembly] = assemblySourceFiles;
                }

                assemblySourceFiles.Add(AssetPath.Combine(projectDirectory, scriptFile));
            }

            return(ToScriptAssemblies(targetAssemblyFiles, settings, assemblies, null));
        }
        public void Start()
        {
            var runner = Paths.Combine(EditorApplication.applicationContentsPath, "Tools", "ILPostProcessorRunner", "ILPostProcessorRunner.exe");

            if (!File.Exists(runner))
            {
                throw new Exception(string.Format($"'{runner}' not found. Is your Unity installation corrupted?"));
            }

            var assemblyPath            = AssetPath.GetFullPath(AssetPath.Combine(tempOutputDirectory, Assembly.Filename));
            var assemblyReferencesPaths = Assembly.GetAllReferences().ToArray();
            var assemblyFolderPaths     = ilPostProcessing.AssemblySearchPaths;

            var outputDirectory    = AssetPath.GetFullPath(tempOutputDirectory);
            var postProcessorPaths = ilPostProcessing.PostProcessorAssemblyPaths;

            var arguments = new List <string>
            {
                $"-a \"{assemblyPath}\"",
                $"-f \"{string.Join(",", assemblyFolderPaths)}\"",
                $"-r \"{string.Join(",", assemblyReferencesPaths)}\"",
                $"-d \"{string.Join(",", Assembly.Defines)}\"",
                $"-p \"{string.Join(",", postProcessorPaths)}\"",
                $"-o \"{outputDirectory}\"",
            };

            var responseFilePath = PrepareFileName(AssetPath.GetFullPath(CommandLineFormatter.GenerateResponseFile(arguments)));

            var args = $"@{responseFilePath}";

            // Always run on Mono until all ILPostProcessors have been fixed
            // to run on NET Core.
            //if (NetCoreRunProgram.IsSupported())
            //{
            //    process = new NetCoreRunProgram(runner, args, null);
            //}
            //else
            {
                process = new ManagedProgram(MonoInstallationFinder.GetMonoInstallation("MonoBleedingEdge"), null, runner, args, false, null);
            }

            process.Start();
        }
示例#8
0
        public MonoIsland ToMonoIsland(EditorScriptCompilationOptions options, string buildOutputDirectory)
        {
            bool buildingForEditor = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor;
            bool developmentBuild  = (options & EditorScriptCompilationOptions.BuildingDevelopmentBuild) == EditorScriptCompilationOptions.BuildingDevelopmentBuild;

            var references = ScriptAssemblyReferences.Select(a => AssetPath.Combine(a.OutputDirectory, a.Filename));

            var referencesArray = references.Concat(References).ToArray();

            var outputPath = AssetPath.Combine(buildOutputDirectory, Filename);

            return(new MonoIsland(BuildTarget,
                                  buildingForEditor,
                                  developmentBuild,
                                  CompilerOptions.AllowUnsafeCode,
                                  ApiCompatibilityLevel,
                                  Files,
                                  referencesArray,
                                  Defines,
                                  outputPath));
        }
        public static void UpdateCodeGenScriptAssembly(ref ScriptAssembly scriptAssembly)
        {
            scriptAssembly.ScriptAssemblyReferences = new ScriptAssembly[0];

            int newReferenceCount = 0;
            var references        = new string[scriptAssembly.References.Length];

            foreach (var reference in scriptAssembly.References)
            {
                var name = AssetPath.GetFileName(reference);
                if (!Utility.FastStartsWith(name, k_UnityEngineModules, k_UnityEngineModulesLower) &&
                    !Utility.FastStartsWith(name, k_UnityEditorModules, k_UnityEditorModulesLower))
                {
                    references[newReferenceCount] = reference;
                    newReferenceCount++;
                }
            }
            var result = new string[newReferenceCount + 1];

            Array.Copy(references, result, newReferenceCount);
            result[newReferenceCount] = AssetPath.Combine(EditorApplication.applicationContentsPath, "Managed", "Unity.CompilationPipeline.Common.dll");
            scriptAssembly.References = result;
        }
示例#10
0
        internal static TargetAssembly GetCustomTargetAssembly(string scriptPath, string projectDirectory, IDictionary <string, TargetAssembly> customTargetAssemblies)
        {
            if (customTargetAssemblies == null)
            {
                return(null);
            }

            int            highestPathDepth = -1;
            TargetAssembly resultAssembly   = null;

            // CustomScriptAssembly paths are absolute, so we convert the scriptPath to an absolute path, if necessary.
            bool isPathAbsolute = AssetPath.IsPathRooted(scriptPath);
            var  fullPath       = isPathAbsolute ? AssetPath.GetFullPath(scriptPath) : AssetPath.Combine(projectDirectory, scriptPath);

            foreach (var entry in customTargetAssemblies)
            {
                var assembly = entry.Value;

                if (assembly.MaxPathLength <= highestPathDepth)
                {
                    continue;
                }

                int pathDepth = assembly.PathFilter(fullPath);

                if (pathDepth <= highestPathDepth)
                {
                    continue;
                }

                resultAssembly   = assembly;
                highestPathDepth = pathDepth;
            }

            return(resultAssembly);
        }
        // Returns true when compilation is finished due to one of these reasons
        // * Was stopped (CompilationTask.Stopped will be true)
        // * Compilation had errors (CompilationTask.CompileErrors will be true)
        // * Compilation succesfully completed without errors.
        public bool Poll()
        {
            HandleOnCompilationTaskStarted();

            if (Stopped)
            {
                HandleOnCompilationTaskFinished();
                return(true);
            }

            Dictionary <ScriptAssembly, ScriptCompilerBase> finishedCompilerTasks = null;

            // Check if any compiler processes are finished.
            foreach (var task in compilerTasks)
            {
                var compiler = task.Value;

                // Did compiler task finish?
                if (compiler.Poll())
                {
                    if (finishedCompilerTasks == null)
                    {
                        finishedCompilerTasks = new Dictionary <ScriptAssembly, ScriptCompilerBase>();
                    }

                    var assembly = task.Key;
                    finishedCompilerTasks.Add(assembly, compiler);
                }
            }

            // Save compiler messages from finished compiler processes and check for compile errors.
            if (finishedCompilerTasks != null)
            {
                foreach (var task in finishedCompilerTasks)
                {
                    var assembly = task.Key;
                    var compiler = task.Value;

                    var messages     = compiler.GetCompilerMessages();
                    var messagesList = messages.ToList();

                    compiledAssemblies.Add(assembly, messagesList.ToArray());

                    bool havePostProcessors = ilPostProcessing != null && ilPostProcessing.HasPostProcessors;
                    bool isCodeGenAssembly  = codeGenAssemblies.Contains(assembly);
                    bool hasCompileErrors   = messagesList.Any(m => m.type == CompilerMessageType.Error);

                    if (isCodeGenAssembly)
                    {
                        if (hasCompileErrors)
                        {
                            notCompiledCodeGenAssemblies.Add(assembly);
                        }
                        else
                        {
                            compiledCodeGenAssemblies.Add(assembly);
                        }
                    }

                    if (havePostProcessors &&
                        notCompiledCodeGenAssemblies.Count == 0 &&
                        !hasCompileErrors &&
                        !isCodeGenAssembly)
                    {
                        var assemblySourcePath = AssetPath.Combine(buildOutputDirectory, assembly.Filename);
                        var pdbSourcePath      = AssetPath.Combine(buildOutputDirectory, assembly.PdbFilename);

                        try
                        {
                            if (assemblySourcePath != assembly.FullPath)
                            {
                                File.Copy(assemblySourcePath, assembly.FullPath, true);
                            }

                            if (pdbSourcePath != assembly.PdbFullPath)
                            {
                                File.Copy(pdbSourcePath, assembly.PdbFullPath, true);
                            }

                            var postProcessorTask = new PostProcessorTask(assembly, messagesList, buildOutputDirectory, ilPostProcessing);
                            pendingPostProcessorTasks.Add(postProcessorTask);
                        }
                        catch (IOException e)
                        {
                            UnityEngine.Debug.LogError($"Fail to copy {assemblySourcePath} or {pdbSourcePath} to {AssetPath.GetDirectoryName(assembly.FullPath)} before post processing the assembly. Skipping post processing.\n{e}");
                            // OnCompilationFinished callbacks might add more compiler messages
                            OnCompilationFinished?.Invoke(assembly, messagesList);
                            processedAssemblies.Add(assembly, messagesList.ToArray());
                        }
                    }
                    else
                    {
                        // OnCompilationFinished callbacks might add more compiler messages
                        OnCompilationFinished?.Invoke(assembly, messagesList);
                        processedAssemblies.Add(assembly, messagesList.ToArray());
                    }

                    if (!CompileErrors)
                    {
                        CompileErrors = messagesList.Any(m => m.type == CompilerMessageType.Error);
                    }

                    // If a codgen / IL Post processor has compile errors, clear
                    // pending assemblies waiting for compilation and assemblies
                    // waiting to get post processed.
                    if (isCodeGenAssembly && hasCompileErrors)
                    {
                        pendingPostProcessorTasks.Clear();
                        pendingAssemblies.Clear();
                    }

                    compilerTasks.Remove(assembly);
                    compiler.Dispose();
                }
            }


            if (ilPostProcessing != null && ilPostProcessing.HasPostProcessors)
            {
                PollPostProcessors();
            }

            // If StopOnFirstError is set, do not queue assemblies for compilation in case of compile errors.
            bool stopOnFirstError = (compilationTaskOptions & CompilationTaskOptions.StopOnFirstError) == CompilationTaskOptions.StopOnFirstError;

            if (stopOnFirstError && CompileErrors)
            {
                foreach (var pendingAssembly in pendingAssemblies)
                {
                    if (UnityCodeGenHelpers.IsCodeGen(pendingAssembly.Filename))
                    {
                        notCompiledCodeGenAssemblies.Add(pendingAssembly);
                    }
                }

                pendingAssemblies.Clear();

                if (FinishedCompilation)
                {
                    HandleOnCompilationTaskFinished();
                }

                return(FinishedCompilation);
            }

            // Queue pending assemblies for compilation if we have no running compilers or if compilers have finished.
            if (compilerTasks.Count == 0 || (finishedCompilerTasks != null && finishedCompilerTasks.Count > 0))
            {
                QueuePendingAssemblies();
            }

            if (FinishedCompilation)
            {
                HandleOnCompilationTaskFinished();
            }

            return(FinishedCompilation);
        }
示例#12
0
 public string FullPath(string outputDirectory, string filenameSuffix)
 {
     return(AssetPath.Combine(outputDirectory, FilenameWithSuffix(filenameSuffix)));
 }
示例#13
0
        public static ScriptAssembly[] GenerateChangedScriptAssemblies(GenerateChangedScriptAssembliesArgs args)
        {
            var dirtyTargetAssemblies = new Dictionary <TargetAssembly, HashSet <string> >();

            var allTargetAssemblies = args.Assemblies.CustomTargetAssemblies == null ?
                                      predefinedTargetAssemblies :
                                      predefinedTargetAssemblies.Concat(args.Assemblies.CustomTargetAssemblies).ToArray();

            // Mark all assemblies that the script updater must be run on as dirty.
            if (args.RunUpdaterAssemblies != null)
            {
                foreach (var assemblyFilename in args.RunUpdaterAssemblies)
                {
                    var targetAssembly = allTargetAssemblies.First(a => a.FilenameWithSuffix(args.Settings.FilenameSuffix) == assemblyFilename);
                    dirtyTargetAssemblies[targetAssembly] = new HashSet <string>();
                }
            }

            // Collect all dirty TargetAssemblies
            foreach (var dirtySourceFile in args.DirtySourceFiles)
            {
                var targetAssembly = GetTargetAssembly(dirtySourceFile, args.ProjectDirectory, args.Assemblies.CustomTargetAssemblies);

                if (!IsCompatibleWithPlatform(targetAssembly, args.Settings))
                {
                    continue;
                }

                HashSet <string> assemblySourceFiles;

                var scriptExtension = ScriptCompilers.GetExtensionOfSourceFile(dirtySourceFile);
                var scriptLanguage  = ScriptCompilers.GetLanguageFromExtension(scriptExtension);

                if (!dirtyTargetAssemblies.TryGetValue(targetAssembly, out assemblySourceFiles))
                {
                    assemblySourceFiles = new HashSet <string>();
                    dirtyTargetAssemblies[targetAssembly] = assemblySourceFiles;

                    if (targetAssembly.Type == TargetAssemblyType.Custom)
                    {
                        targetAssembly.Language = scriptLanguage;
                    }
                }

                assemblySourceFiles.Add(AssetPath.Combine(args.ProjectDirectory, dirtySourceFile));

                // If there are mixed languages in a custom script folder, mark the assembly to not be compiled.
                if (scriptLanguage != targetAssembly.Language)
                {
                    args.NotCompiledTargetAssemblies.Add(targetAssembly);
                }
            }

            bool isAnyCustomScriptAssemblyDirty = dirtyTargetAssemblies.Any(entry => entry.Key.Type == TargetAssemblyType.Custom);

            // If we have any dirty custom target assemblies, then the predefined target assemblies are marked as dirty,
            // as the predefined assemblies always reference the custom script assemblies.
            if (isAnyCustomScriptAssemblyDirty)
            {
                foreach (var assembly in predefinedTargetAssemblies)
                {
                    if (!IsCompatibleWithPlatform(assembly, args.Settings))
                    {
                        continue;
                    }

                    if (!dirtyTargetAssemblies.ContainsKey(assembly))
                    {
                        dirtyTargetAssemblies[assembly] = new HashSet <string>();
                    }
                }
            }

            // Collect any TargetAssemblies that reference the dirty TargetAssemblies, as they will also be dirty.
            int dirtyAssemblyCount;

            do
            {
                dirtyAssemblyCount = 0;

                foreach (var assembly in allTargetAssemblies)
                {
                    if (!IsCompatibleWithPlatform(assembly, args.Settings))
                    {
                        continue;
                    }

                    // If already dirty, skip.
                    if (dirtyTargetAssemblies.ContainsKey(assembly))
                    {
                        continue;
                    }

                    foreach (var reference in assembly.References)
                    {
                        if (dirtyTargetAssemblies.ContainsKey(reference))
                        {
                            dirtyTargetAssemblies[assembly] = new HashSet <string>();
                            dirtyAssemblyCount++;
                            break;
                        }
                    }
                }
            }while (dirtyAssemblyCount > 0);

            // Add any non-dirty source files that belong to dirty TargetAssemblies
            foreach (var sourceFile in args.AllSourceFiles)
            {
                var targetAssembly = GetTargetAssembly(sourceFile, args.ProjectDirectory, args.Assemblies.CustomTargetAssemblies);

                if (!IsCompatibleWithPlatform(targetAssembly, args.Settings))
                {
                    continue;
                }

                HashSet <string> assemblySourceFiles;

                var scriptExtension = ScriptCompilers.GetExtensionOfSourceFile(sourceFile);
                var scriptLanguage  = ScriptCompilers.GetLanguageFromExtension(scriptExtension);

                if (targetAssembly.Language == null && targetAssembly.Type == TargetAssemblyType.Custom)
                {
                    targetAssembly.Language = scriptLanguage;
                }

                // If there are mixed languages in a custom script folder, mark the assembly to not be compiled.
                if (scriptLanguage != targetAssembly.Language)
                {
                    args.NotCompiledTargetAssemblies.Add(targetAssembly);
                }

                if (dirtyTargetAssemblies.TryGetValue(targetAssembly, out assemblySourceFiles))
                {
                    assemblySourceFiles.Add(AssetPath.Combine(args.ProjectDirectory, sourceFile));
                }
            }

            // Remove any target assemblies which have no source files associated with them.
            dirtyTargetAssemblies = dirtyTargetAssemblies.Where(e => e.Value.Count > 0).ToDictionary(e => e.Key, e => e.Value);

            // Remove any target assemblies which have been marked as do not compile.
            foreach (var removeAssembly in args.NotCompiledTargetAssemblies)
            {
                dirtyTargetAssemblies.Remove(removeAssembly);
            }


            // Convert TargetAssemblies to ScriptAssembiles
            var scriptAssemblies = ToScriptAssemblies(dirtyTargetAssemblies, args.Settings, args.Assemblies, args.RunUpdaterAssemblies);

            return(scriptAssemblies);
        }
示例#14
0
 public string FullPath(string outputDirectory)
 {
     return(AssetPath.Combine(outputDirectory, Filename));
 }
        public void SetAllCustomScriptAssemblyReferenceJsonsContents(string[] paths, string[] contents)
        {
            var assemblyRefs = new List <CustomScriptAssemblyReference>();
            var exceptions   = new List <Exception>();

            // We only construct this lookup if it is required, which is when we are using guids instead of assembly names.
            Dictionary <string, CustomScriptAssembly> guidsToAssemblies = null;

            // To check if a path prefix is already being used we use a Dictionary where the key is the prefix and the value is the file path.
            var prefixToFilePathLookup = m_SkipCustomScriptAssemblyGraphValidation ?
                                         null :
                                         CustomScriptAssemblies.GroupBy(x => x.PathPrefix).ToDictionary(x => x.First().PathPrefix, x => new List <string>()
            {
                x.First().FilePath
            }, StringComparer.OrdinalIgnoreCase);

            for (var i = 0; i < paths.Length; ++i)
            {
                var path = paths[i];

                CustomScriptAssemblyReference loadedCustomScriptAssemblyReference = null;

                try
                {
                    var fullPath = AssetPath.IsPathRooted(path) ? AssetPath.GetFullPath(path) : AssetPath.Combine(m_ProjectDirectory, path);

                    if (contents != null)
                    {
                        var jsonContents = contents[i];
                        loadedCustomScriptAssemblyReference = LoadCustomScriptAssemblyReferenceFromJson(fullPath, jsonContents);
                    }
                    else
                    {
                        loadedCustomScriptAssemblyReference = LoadCustomScriptAssemblyReferenceFromJsonPath(fullPath);
                    }

                    if (!m_SkipCustomScriptAssemblyGraphValidation)
                    {
                        // Check both asmdef and asmref files.
                        if (prefixToFilePathLookup.TryGetValue(loadedCustomScriptAssemblyReference.PathPrefix, out var duplicateFilePaths))
                        {
                            var filePaths = new List <string> {
                                loadedCustomScriptAssemblyReference.FilePath
                            };
                            filePaths.AddRange(duplicateFilePaths);

                            throw new AssemblyDefinitionException(
                                      $"Folder '{loadedCustomScriptAssemblyReference.PathPrefix}' contains multiple assembly definition files", filePaths.ToArray());
                        }
                    }

                    // Convert GUID references to assembly names
                    if (GUIDReference.IsGUIDReference(loadedCustomScriptAssemblyReference.Reference))
                    {
                        // Generate the guid to assembly lookup?
                        guidsToAssemblies = guidsToAssemblies ?? CustomScriptAssemblies.ToDictionary(x => x.GUID);

                        var guid = Utility.FastToLower(GUIDReference.GUIDReferenceToGUID(loadedCustomScriptAssemblyReference.Reference));
                        if (guidsToAssemblies.TryGetValue(guid, out var foundAssembly))
                        {
                            loadedCustomScriptAssemblyReference.Reference = foundAssembly.Name;
                        }
                    }
                }
                catch (Exception e)
                {
                    m_CompilationSetupErrorsTracker.SetCompilationSetupErrors(CompilationSetupErrors.LoadError);
                    exceptions.Add(e);
                }

                if (loadedCustomScriptAssemblyReference != null)
                {
                    assemblyRefs.Add(loadedCustomScriptAssemblyReference);

                    if (m_SkipCustomScriptAssemblyGraphValidation)
                    {
                        continue;
                    }

                    if (!prefixToFilePathLookup.TryGetValue(loadedCustomScriptAssemblyReference.PathPrefix, out var duplicateFilePaths))
                    {
                        duplicateFilePaths = new List <string>();
                        prefixToFilePathLookup[loadedCustomScriptAssemblyReference.PathPrefix] = duplicateFilePaths;
                    }

                    duplicateFilePaths.Add(loadedCustomScriptAssemblyReference.FilePath);
                }
            }

            CustomScriptAssemblyReferences = assemblyRefs;
            Exceptions = exceptions.ToArray();
        }
示例#16
0
        // Returns true when compilation is finished due to one of these reasons
        // * Was stopped (CompilationTask.Stopped will be true)
        // * Compilation had errors (CompilationTask.CompileErrors will be true)
        // * Compilation succesfully completed without errors.
        public bool Poll()
        {
            HandleOnCompilationTaskStarted();

            if (Stopped)
            {
                HandleOnCompilationTaskFinished();
                return(true);
            }

            Dictionary <ScriptAssembly, ScriptCompilerBase> finishedCompilerTasks = null;

            // Check if any compiler processes are finished.
            foreach (var task in compilerTasks)
            {
                var compiler = task.Value;

                // Did compiler task finish?
                if (compiler.Poll())
                {
                    if (finishedCompilerTasks == null)
                    {
                        finishedCompilerTasks = new Dictionary <ScriptAssembly, ScriptCompilerBase>();
                    }

                    var assembly = task.Key;
                    finishedCompilerTasks.Add(assembly, compiler);
                }
            }

            // Save compiler messages from finished compiler processes and check for compile errors.
            if (finishedCompilerTasks != null)
            {
                foreach (var task in finishedCompilerTasks)
                {
                    var assembly = task.Key;
                    var compiler = task.Value;

                    var messages     = compiler.GetCompilerMessages();
                    var messagesList = messages.ToList();

                    compiledAssemblies.Add(assembly, messagesList.ToArray());

                    if (RunPostProcessors && !messagesList.Any(m => m.type == CompilerMessageType.Error))
                    {
                        var sourcePath = AssetPath.Combine(buildOutputDirectory, assembly.Filename);

                        try
                        {
                            File.Copy(sourcePath, assembly.FullPath, true);
                            var postProcessorTask = new PostProcessorTask(assembly, messagesList, buildOutputDirectory, postProcessFunc);

                            postProcessorTask.Poll();
                            OnPostProcessingStarted?.Invoke(assembly);

                            postProcessorTasks.Add(postProcessorTask);
                        }
                        catch (IOException e)
                        {
                            UnityEngine.Debug.LogError($"Fail to copy {sourcePath} to {assembly.FullPath} before post processing the assembly. Skipping post processing.\n{e}");
                            // OnCompilationFinished callbacks might add more compiler messages
                            OnCompilationFinished?.Invoke(assembly, messagesList);
                            processedAssemblies.Add(assembly, messagesList.ToArray());
                        }
                    }
                    else
                    {
                        // OnCompilationFinished callbacks might add more compiler messages
                        OnCompilationFinished?.Invoke(assembly, messagesList);
                        processedAssemblies.Add(assembly, messagesList.ToArray());
                    }

                    if (!CompileErrors)
                    {
                        CompileErrors = messagesList.Any(m => m.type == CompilerMessageType.Error);
                    }

                    compilerTasks.Remove(assembly);
                    compiler.Dispose();
                }
            }

            HashSet <PostProcessorTask> finishedPostProcessorTasks = null;

            foreach (var postProcessorTask in postProcessorTasks)
            {
                // We break out of this loop instead to continuing to ensure that
                // OnCompilationFinished events are emitted in the same order as
                // they finished compiling.

                if (!postProcessorTask.Poll())
                {
                    break;
                }

                // Do not copy the post processed assembly in OnCompilationFinished
                // if any of the running compilers have a reference to the assembly.
                // As we might copy it while the compiler has the assembly open.
                if (AnyRunningCompilerHasReference(postProcessorTask.Assembly))
                {
                    break;
                }

                var messagesList = postProcessorTask.CompilerMessages;

                // OnCompilationFinished callbacks might add more compiler messages
                OnCompilationFinished?.Invoke(postProcessorTask.Assembly, messagesList);
                processedAssemblies.Add(postProcessorTask.Assembly, messagesList.ToArray());

                if (!CompileErrors)
                {
                    CompileErrors = messagesList.Any(m => m.type == CompilerMessageType.Error);
                }

                if (finishedPostProcessorTasks == null)
                {
                    finishedPostProcessorTasks = new HashSet <PostProcessorTask>();
                }

                finishedPostProcessorTasks.Add(postProcessorTask);
            }

            if (finishedPostProcessorTasks != null)
            {
                foreach (var finishedPostProcessorTask in finishedPostProcessorTasks)
                {
                    postProcessorTasks.Remove(finishedPostProcessorTask);
                }
            }

            // If StopOnFirstError is set, do not queue assemblies for compilation in case of compile errors.
            bool stopOnFirstError = (compilationTaskOptions & CompilationTaskOptions.StopOnFirstError) == CompilationTaskOptions.StopOnFirstError;

            if (stopOnFirstError && CompileErrors)
            {
                pendingAssemblies.Clear();

                if (FinishedCompilation)
                {
                    HandleOnCompilationTaskFinished();
                }

                return(FinishedCompilation);
            }

            // Queue pending assemblies for compilation if we have no running compilers or if compilers have finished.
            if (compilerTasks.Count == 0 || (finishedCompilerTasks != null && finishedCompilerTasks.Count > 0))
            {
                QueuePendingAssemblies();
            }

            if (FinishedCompilation)
            {
                HandleOnCompilationTaskFinished();
            }

            return(FinishedCompilation);
        }
        public void SetAllCustomScriptAssemblyJsonContents(string[] paths, string[] contents, string[] guids)
        {
            var assemblies = new List <CustomScriptAssembly>();
            var assemblyLowercaseNamesLookup = new Dictionary <string, CustomScriptAssembly>();
            var exceptions        = new List <Exception>();
            var guidsToAssemblies = new Dictionary <string, CustomScriptAssembly>();
            HashSet <string> predefinedAssemblyNames = null;

            // To check if a path prefix is already being used we use a Dictionary where the key is the prefix and the value is the file path.
            var prefixToFilePathLookup = CustomScriptAssemblyReferences.ToDictionary(x => x.PathPrefix,
                                                                                     x => new List <string> {
                x.FilePath
            }, StringComparer.OrdinalIgnoreCase);

            m_CompilationSetupErrorsTracker.ClearCompilationSetupErrors(CompilationSetupErrors.LoadError);

            // Load first to setup guidsToAssemblies dictionary and convert guids to assembly names
            // before checking for assembly reference errors, so errors emit assembly names instead of guids.
            for (var i = 0; i < paths.Length; ++i)
            {
                var path = paths[i];
                var guid = guids[i];

                string lowerCaseName = null;
                CustomScriptAssembly loadedCustomScriptAssembly = null;

                try
                {
                    var fullPath = AssetPath.IsPathRooted(path)
                        ? AssetPath.GetFullPath(path)
                        : AssetPath.Combine(m_ProjectDirectory, path);

                    loadedCustomScriptAssembly =
                        contents != null
                        ? LoadCustomScriptAssemblyFromJson(fullPath, contents[i], guid)
                        : LoadCustomScriptAssemblyFromJsonPath(fullPath, guid);

                    loadedCustomScriptAssembly.References = loadedCustomScriptAssembly.References ?? new string[0];

                    lowerCaseName = Utility.FastToLower(loadedCustomScriptAssembly.Name);
                    guidsToAssemblies[Utility.FastToLower(guid)] = loadedCustomScriptAssembly;

                    if (!m_SkipCustomScriptAssemblyGraphValidation)
                    {
                        if (predefinedAssemblyNames == null)
                        {
                            predefinedAssemblyNames = new HashSet <string>(EditorBuildRules.PredefinedTargetAssemblyNames);
                            var netfw = MonoLibraryHelpers
                                        .GetSystemLibraryReferences(ApiCompatibilityLevel.NET_Unity_4_8).Select(Path.GetFileNameWithoutExtension);
                            var netstandard21 = MonoLibraryHelpers
                                                .GetSystemLibraryReferences(ApiCompatibilityLevel.NET_Standard).Select(Path.GetFileNameWithoutExtension);
                            predefinedAssemblyNames.UnionWith(netfw);
                            predefinedAssemblyNames.UnionWith(netstandard21);
                        }

                        CheckPredefinedAssemblyNames(
                            predefinedAssemblyNames,
                            assemblyLowercaseNamesLookup,
                            lowerCaseName,
                            prefixToFilePathLookup,
                            ref loadedCustomScriptAssembly);
                    }
                }
                catch (Exception e)
                {
                    m_CompilationSetupErrorsTracker.SetCompilationSetupErrors(CompilationSetupErrors.LoadError);
                    exceptions.Add(e);
                }

                if (loadedCustomScriptAssembly == null || m_SkipCustomScriptAssemblyGraphValidation && assemblyLowercaseNamesLookup.ContainsKey(lowerCaseName))
                {
                    continue;
                }

                loadedCustomScriptAssembly.References       = loadedCustomScriptAssembly.References ?? new string[0];
                assemblyLowercaseNamesLookup[lowerCaseName] = loadedCustomScriptAssembly;
                assemblies.Add(loadedCustomScriptAssembly);

                if (!prefixToFilePathLookup.TryGetValue(loadedCustomScriptAssembly.PathPrefix, out var duplicateFilePaths))
                {
                    duplicateFilePaths = new List <string>();
                    prefixToFilePathLookup[loadedCustomScriptAssembly.PathPrefix] = duplicateFilePaths;
                }

                duplicateFilePaths.Add(loadedCustomScriptAssembly.FilePath);
            }

            ConvertGUIDReferencesToAssemblyNames(assemblies, guidsToAssemblies);

            if (!m_SkipCustomScriptAssemblyGraphValidation)
            {
                CheckForReferenceErrors(assemblies, exceptions);
            }

            CustomScriptAssemblies = assemblies.ToArray();
            Exceptions             = exceptions.ToArray();
        }
示例#18
0
        void QueuePendingAssemblies()
        {
            if (pendingAssemblies.Count == 0)
            {
                return;
            }

            List <ScriptAssembly> assemblyCompileQueue    = null;
            List <ScriptAssembly> removePendingAssemblies = null;

            // Find assemblies that have all their references already compiled.
            foreach (var pendingAssembly in pendingAssemblies)
            {
                bool compileAssembly = true;

                int unchangedAssemblyReferencesCount = 0;

                foreach (var reference in pendingAssembly.ScriptAssemblyReferences)
                {
                    CompilerMessage[] messages;

                    if (unchangedCompiledAssemblies.Contains(reference))
                    {
                        unchangedAssemblyReferencesCount++;
                        continue;
                    }

                    if (!compiledAssemblies.TryGetValue(reference, out messages))
                    {
                        // If a reference is not compiling and not pending
                        // also remove this assembly from pending.
                        if (!compilerTasks.ContainsKey(reference) && !pendingAssemblies.Contains(reference))
                        {
                            if (removePendingAssemblies == null)
                            {
                                removePendingAssemblies = new List <ScriptAssembly>();
                            }

                            removePendingAssemblies.Add(pendingAssembly);
                        }

                        compileAssembly = false;
                        break;
                    }

                    // If reference has compile errors, do not compile the pending assembly.
                    bool compileErrors = messages.Any(m => m.type == CompilerMessageType.Error);

                    if (compileErrors)
                    {
                        if (removePendingAssemblies == null)
                        {
                            removePendingAssemblies = new List <ScriptAssembly>();
                        }

                        removePendingAssemblies.Add(pendingAssembly);

                        compileAssembly = false;
                        break;
                    }
                }

                // If the assembly exists and is up to date (no compile errors)
                // and it was dirtied because it is a reference to one or more
                // dirty assemblies and none of them changed, then we do not
                // need to recompile the assembly.
                // Most expensive checks at the bottom.
                if (UseReferenceAssemblies &&
                    BuildingForEditor &&
                    !pendingAssembly.HasCompileErrors &&
                    pendingAssembly.DirtySource == DirtySource.DirtyReference &&
                    unchangedAssemblyReferencesCount > 0 &&
                    unchangedAssemblyReferencesCount == pendingAssembly.ScriptAssemblyReferences.Length &&
                    File.Exists(pendingAssembly.FullPath))
                {
                    var assemblyOutputPath = AssetPath.Combine(pendingAssembly.OutputDirectory, pendingAssembly.Filename);

                    Console.WriteLine($"- Skipping compile {assemblyOutputPath} because all references are unchanged");

                    unchangedCompiledAssemblies.Add(pendingAssembly);

                    if (removePendingAssemblies == null)
                    {
                        removePendingAssemblies = new List <ScriptAssembly>();
                    }

                    removePendingAssemblies.Add(pendingAssembly);
                    compileAssembly = false;
                }

                if (compileAssembly)
                {
                    if (assemblyCompileQueue == null)
                    {
                        assemblyCompileQueue = new List <ScriptAssembly>();
                    }

                    assemblyCompileQueue.Add(pendingAssembly);
                }
            }

            if (removePendingAssemblies != null)
            {
                foreach (var assembly in removePendingAssemblies)
                {
                    pendingAssemblies.Remove(assembly);

                    // If a codegen assembly was removed fro pending assemblies,
                    // clear all pending compilation and post processing.
                    if (codeGenAssemblies.Contains(assembly))
                    {
                        notCompiledCodeGenAssemblies.Add(assembly);
                        pendingPostProcessorTasks.Clear();
                        pendingAssemblies.Clear();
                        assemblyCompileQueue = null;
                        break;
                    }
                }

                // All pending assemblies were removed and no assemblies
                // were queued for compilation.
                if (assemblyCompileQueue == null)
                {
                    return;
                }
            }

            // No assemblies to compile, need to wait for more references to finish compiling.
            if (assemblyCompileQueue == null)
            {
                if (compilerTasks.Count == 0)
                {
                    throw new Exception("No pending assemblies queued for compilation and no compilers running. Compilation will never finish.");
                }
                return;
            }

            // Begin compiling any queued assemblies
            foreach (var assembly in assemblyCompileQueue)
            {
                pendingAssemblies.Remove(assembly);

                if (assembly.CallOnBeforeCompilationStarted && OnBeforeCompilationStarted != null)
                {
                    OnBeforeCompilationStarted(assembly, compilePhase);
                }

                var compiler = compilerFactory.Create(assembly, buildOutputDirectory);

                compilerTasks.Add(assembly, compiler);

                // Start compiler process
                compiler.BeginCompiling();

                LogStartInfo($"# Starting compiling {assembly.Filename}", compiler.GetProcessStartInfo());

                if (OnCompilationStarted != null)
                {
                    OnCompilationStarted(assembly, compilePhase);
                }

                if (RunningMaxConcurrentProcesses)
                {
                    break;
                }
            }

            compilePhase++;
        }