public static CustomScriptAssembly Create(string name, string directory)
        {
            var customScriptAssembly = new CustomScriptAssembly();

            var modifiedDirectory = AssetPath.ReplaceSeparators(directory);

            if (modifiedDirectory.Last() != AssetPath.Separator)
            {
                modifiedDirectory += AssetPath.Separator.ToString();
            }

            customScriptAssembly.Name                  = name;
            customScriptAssembly.RootNamespace         = name ?? string.Empty;
            customScriptAssembly.FilePath              = modifiedDirectory;
            customScriptAssembly.PathPrefix            = modifiedDirectory;
            customScriptAssembly.References            = new string[0];
            customScriptAssembly.PrecompiledReferences = new string[0];
            customScriptAssembly.CompilerOptions       = new ScriptCompilerOptions();
            customScriptAssembly.AutoReferenced        = true;

            return(customScriptAssembly);
        }
Пример #2
0
        public static CustomScriptAssembly FromCustomScriptAssemblyData(string path, CustomScriptAssemblyData customScriptAssemblyData)
        {
            CustomScriptAssembly result;

            if (customScriptAssemblyData == null)
            {
                result = null;
            }
            else
            {
                string pathPrefix = path.Substring(0, path.Length - AssetPath.GetFileName(path).Length);
                CustomScriptAssembly customScriptAssembly = new CustomScriptAssembly();
                customScriptAssembly.Name       = customScriptAssemblyData.name;
                customScriptAssembly.References = customScriptAssemblyData.references;
                customScriptAssembly.FilePath   = path;
                customScriptAssembly.PathPrefix = pathPrefix;
                customScriptAssemblyData.optionalUnityReferences = (customScriptAssemblyData.optionalUnityReferences ?? new string[0]);
                string[] optionalUnityReferences = customScriptAssemblyData.optionalUnityReferences;
                for (int i = 0; i < optionalUnityReferences.Length; i++)
                {
                    string value = optionalUnityReferences[i];
                    OptionalUnityReferences optionalUnityReferences2 = (OptionalUnityReferences)Enum.Parse(typeof(OptionalUnityReferences), value);
                    customScriptAssembly.OptionalUnityReferences |= optionalUnityReferences2;
                }
                if (customScriptAssemblyData.includePlatforms != null && customScriptAssemblyData.includePlatforms.Length > 0)
                {
                    customScriptAssembly.IncludePlatforms = (from name in customScriptAssemblyData.includePlatforms
                                                             select CustomScriptAssembly.GetPlatformFromName(name)).ToArray <CustomScriptAssemblyPlatform>();
                }
                if (customScriptAssemblyData.excludePlatforms != null && customScriptAssemblyData.excludePlatforms.Length > 0)
                {
                    customScriptAssembly.ExcludePlatforms = (from name in customScriptAssemblyData.excludePlatforms
                                                             select CustomScriptAssembly.GetPlatformFromName(name)).ToArray <CustomScriptAssemblyPlatform>();
                }
                result = customScriptAssembly;
            }
            return(result);
        }
        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;
        }
Пример #4
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);
        }
Пример #5
0
        internal static TargetAssembly GetPredefinedTargetAssembly(string scriptPath)
        {
            TargetAssembly resultAssembly = null;

            var extension        = AssetPath.GetExtension(scriptPath).Substring(1).ToLower();
            var lowerPath        = ("/" + scriptPath.ToLower()).ConvertSeparatorsToUnity();
            int highestPathDepth = -1;

            foreach (var assembly in predefinedTargetAssemblies)
            {
                if (extension != assembly.Language.GetExtensionICanCompile())
                {
                    continue;
                }

                var pathFilter = assembly.PathFilter;
                int pathDepth  = -1;

                if (pathFilter == null)
                {
                    pathDepth = 0;
                }
                else
                {
                    pathDepth = pathFilter(lowerPath);
                }

                if (pathDepth > highestPathDepth)
                {
                    resultAssembly   = assembly;
                    highestPathDepth = pathDepth;
                }
            }

            return(resultAssembly);
        }
Пример #6
0
        public static Dictionary <string, string> GetUnityReferences(ScriptAssembly scriptAssembly, TargetAssembly targetAssembly, PrecompiledAssembly[] unityAssemblies, HashSet <string> predefinedCustomTargetReferences, EditorScriptCompilationOptions options, UnityReferencesOptions unityReferencesOptions)
        {
            var references = new Dictionary <string, string>();

            bool assemblyEditorOnly        = (scriptAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly;
            bool buildingForEditor         = (options & EditorScriptCompilationOptions.BuildingForEditor) == EditorScriptCompilationOptions.BuildingForEditor;
            bool excludeUnityModules       = unityReferencesOptions == UnityReferencesOptions.ExcludeModules;
            bool isOverridingUnityAssembly = false;

            // Add Unity assemblies (UnityEngine.dll, UnityEditor.dll) referencees.
            if (unityAssemblies == null)
            {
                return(references);
            }

            foreach (var unityAssembly in unityAssemblies)
            {
                if ((unityAssembly.Flags & (AssemblyFlags.UserOverride | AssemblyFlags.UserOverrideCandidate)) != AssemblyFlags.None)
                {
                    var unityAssemblyFileName = AssetPath.GetFileName(unityAssembly.Path);

                    // This scriptAssembly is overriding this unityAssembly so it should probably not depend on itself.
                    if (unityAssemblyFileName == scriptAssembly.Filename)
                    {
                        isOverridingUnityAssembly = true;
                        continue;
                    }

                    // Custom targets may override Unity references, do not add them to avoid duplicated references.
                    if (predefinedCustomTargetReferences != null && predefinedCustomTargetReferences.Contains(unityAssemblyFileName))
                    {
                        continue;
                    }

                    // If this scriptAssembly/targetAssembly explicitly references another
                    // scriptAssembly that has actually overridden this unityAssembly, we should
                    // not add the unityAssembly to the references as well. It's possible
                    // that this scriptAssembly is using new APIs that don't exist in the shipped
                    // copy of the unityAssembly.
                    if (targetAssembly != null && targetAssembly.References.Any(ta => ta.Filename == unityAssemblyFileName))
                    {
                        continue;
                    }
                }

                var isUnityModule = (unityAssembly.Flags & AssemblyFlags.UnityModule) == AssemblyFlags.UnityModule;

                if (isUnityModule && excludeUnityModules)
                {
                    continue;
                }

                var moduleExcludedForRuntimeCode = (unityAssembly.Flags & AssemblyFlags.ExcludedForRuntimeCode) == AssemblyFlags.ExcludedForRuntimeCode;

                // Add Unity editor assemblies (UnityEditor.dll) to all assemblies when building inside the editor
                if ((buildingForEditor && !moduleExcludedForRuntimeCode) || assemblyEditorOnly)
                {
                    if ((unityAssembly.Flags & AssemblyFlags.UseForMono) != 0)
                    {
                        references[Path.GetFileName(unityAssembly.Path)] = unityAssembly.Path;
                    }
                }
                else
                {
                    bool unityAssemblyEditorOnly = (unityAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly;

                    // Add Unity runtime assemblies (UnityEngine.dll) to all assemblies
                    if (!unityAssemblyEditorOnly && !moduleExcludedForRuntimeCode)
                    {
                        if (IsPrecompiledAssemblyCompatibleWithBuildTarget(unityAssembly, scriptAssembly.BuildTarget))
                        {
                            references[Path.GetFileName(unityAssembly.Path)] = unityAssembly.Path;
                        }
                    }
                }
            }

            // UserOverride assemblies should not have a dependency on Editor assemblies.
            if (isOverridingUnityAssembly && !assemblyEditorOnly)
            {
                references = references.Where(kvp => !kvp.Key.Contains("UnityEditor")).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
            }

            return(references);
        }
Пример #7
0
 public static bool IsPrecompiledAssemblyNunit(ref PrecompiledAssembly precompiledAssembly)
 {
     return(AssetPath.GetFileName(precompiledAssembly.Path) == k_NunitAssemblyName);
 }
Пример #8
0
 public static bool ShouldAddNunitReferences(EditorBuildRules.TargetAssembly targetAssembly)
 {
     return(!targetAssembly.PrecompiledReferences.Any(x => AssetPath.GetFileName(x.Path) == k_NunitAssemblyName) &&
            (PlayerSettings.playModeTestRunnerEnabled || (targetAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly));
 }
Пример #9
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);
        }
Пример #10
0
 public static EditorBuildRules.TargetAssembly[] CreateTargetAssemblies(IEnumerable <CustomScriptAssembly> customScriptAssemblies)
 {
     EditorBuildRules.TargetAssembly[] result;
     if (customScriptAssemblies == null)
     {
         result = null;
     }
     else
     {
         using (IEnumerator <CustomScriptAssembly> enumerator = customScriptAssemblies.GetEnumerator())
         {
             while (enumerator.MoveNext())
             {
                 CustomScriptAssembly customAssembly = enumerator.Current;
                 if (EditorBuildRules.predefinedTargetAssemblies.Any((EditorBuildRules.TargetAssembly p) => AssetPath.GetAssemblyNameWithoutExtension(p.Filename) == customAssembly.Name))
                 {
                     throw new Exception(string.Format("Assembly cannot be have reserved name '{0}'. Defined in '{1}'", customAssembly.Name, customAssembly.FilePath));
                 }
             }
         }
         List <EditorBuildRules.TargetAssembly> list = new List <EditorBuildRules.TargetAssembly>();
         Dictionary <string, EditorBuildRules.TargetAssembly> dictionary = new Dictionary <string, EditorBuildRules.TargetAssembly>();
         using (IEnumerator <CustomScriptAssembly> enumerator2 = customScriptAssemblies.GetEnumerator())
         {
             while (enumerator2.MoveNext())
             {
                 EditorBuildRules.< CreateTargetAssemblies > c__AnonStorey2 <CreateTargetAssemblies> c__AnonStorey2 = new EditorBuildRules.< CreateTargetAssemblies > c__AnonStorey2();
Пример #11
0
 public static string Combine(string path1, string path2)
 {
     return(AssetPath.ReplaceSeparators(Path.Combine(path1, path2)));
 }
        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();
        }
Пример #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 static TargetAssembly[] CreateTargetAssemblies(IEnumerable <CustomScriptAssembly> customScriptAssemblies)
        {
            if (customScriptAssemblies == null)
            {
                return(null);
            }


            foreach (var customAssembly in customScriptAssemblies)
            {
                if (predefinedTargetAssemblies.Any(p => AssetPath.GetAssemblyNameWithoutExtension(p.Filename) == customAssembly.Name))
                {
                    throw new Exception(string.Format("Assembly cannot be have reserved name '{0}'. Defined in '{1}'", customAssembly.Name, customAssembly.FilePath));
                }
            }

            var targetAssemblies     = new List <TargetAssembly>();
            var nameToTargetAssembly = new Dictionary <string, TargetAssembly>();


            // Create TargetAssemblies
            foreach (var customAssembly in customScriptAssemblies)
            {
                var lowerPathPrefix = customAssembly.PathPrefix.ToLower(CultureInfo.InvariantCulture);

                var targetAssembly = new TargetAssembly(customAssembly.Name + ".dll",
                                                        null,
                                                        customAssembly.AssemblyFlags,
                                                        TargetAssemblyType.Custom,
                                                        customAssembly.PathPrefix,
                                                        path => FastStartsWith(path, customAssembly.PathPrefix, lowerPathPrefix) ? customAssembly.PathPrefix.Length : -1,
                                                        (BuildTarget target, EditorScriptCompilationOptions options) => customAssembly.IsCompatibleWith(target, options),
                                                        customAssembly.CompilerOptions)
                {
                    OptionalUnityReferences = customAssembly.OptionalUnityReferences,
                };

                targetAssemblies.Add(targetAssembly);
                nameToTargetAssembly[customAssembly.Name] = targetAssembly;
            }

            var targetAssembliesEnumerator = targetAssemblies.GetEnumerator();

            // Setup references for TargetAssemblies
            foreach (var customAssembly in customScriptAssemblies)
            {
                targetAssembliesEnumerator.MoveNext();
                var targetAssembly = targetAssembliesEnumerator.Current;

                if (customAssembly.References == null)
                {
                    continue;
                }

                foreach (var reference in customAssembly.References)
                {
                    TargetAssembly referenceAssembly = null;

                    if (!nameToTargetAssembly.TryGetValue(reference, out referenceAssembly))
                    {
                        UnityEngine.Debug.LogWarning(string.Format("Could not find reference '{0}' for assembly '{1}'", reference, customAssembly.Name));
                        continue;
                    }

                    targetAssembly.References.Add(referenceAssembly);
                }
            }

            return(targetAssemblies.ToArray());
        }
Пример #15
0
 public string FullPath(string outputDirectory)
 {
     return(AssetPath.Combine(outputDirectory, Filename));
 }
Пример #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());

                    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);
        }
        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();
        }
Пример #18
0
        internal static ScriptAssembly[] ToScriptAssemblies(IDictionary <TargetAssembly, HashSet <string> > targetAssemblies, ScriptAssemblySettings settings,
                                                            CompilationAssemblies assemblies, HashSet <string> runUpdaterAssemblies)
        {
            var scriptAssemblies = new ScriptAssembly[targetAssemblies.Count];

            var targetToScriptAssembly = new Dictionary <TargetAssembly, ScriptAssembly>();
            int index = 0;

            bool buildingForEditor = settings.BuildingForEditor;

            foreach (var entry in targetAssemblies)
            {
                var targetAssembly = entry.Key;
                var sourceFiles    = entry.Value;
                var scriptAssembly = new ScriptAssembly();

                // Setup TargetAssembly -> ScriptAssembly mapping for converting references
                scriptAssemblies[index] = scriptAssembly;
                targetToScriptAssembly[targetAssembly] = scriptAssemblies[index++];

                // Setup ScriptAssembly
                scriptAssembly.Flags       = targetAssembly.Flags;
                scriptAssembly.BuildTarget = settings.BuildTarget;
                scriptAssembly.Language    = targetAssembly.Language;

                var editorOnlyTargetAssembly = (targetAssembly.Flags & AssemblyFlags.EditorOnly) == AssemblyFlags.EditorOnly;

                if (editorOnlyTargetAssembly || (buildingForEditor && settings.ApiCompatibilityLevel == ApiCompatibilityLevel.NET_4_6))
                {
                    scriptAssembly.ApiCompatibilityLevel = (EditorApplication.scriptingRuntimeVersion == ScriptingRuntimeVersion.Latest) ? ApiCompatibilityLevel.NET_4_6 : ApiCompatibilityLevel.NET_2_0;
                }
                else
                {
                    scriptAssembly.ApiCompatibilityLevel = settings.ApiCompatibilityLevel;
                }

                if (!string.IsNullOrEmpty(settings.FilenameSuffix))
                {
                    var basename = AssetPath.GetAssemblyNameWithoutExtension(targetAssembly.Filename);
                    scriptAssembly.Filename = string.Concat(basename, settings.FilenameSuffix, ".dll");
                }
                else
                {
                    scriptAssembly.Filename = targetAssembly.Filename;
                }

                if (runUpdaterAssemblies != null && runUpdaterAssemblies.Contains(scriptAssembly.Filename))
                {
                    scriptAssembly.RunUpdater = true;
                }

                scriptAssembly.OutputDirectory = settings.OutputDirectory;
                scriptAssembly.Defines         = settings.Defines;
                scriptAssembly.Files           = sourceFiles.ToArray();

                if (targetAssembly.Type == TargetAssemblyType.Predefined)
                {
                    scriptAssembly.CompilerOptions = settings.PredefinedAssembliesCompilerOptions;
                }
                else
                {
                    scriptAssembly.CompilerOptions = targetAssembly.CompilerOptions;
                }

                // Script files must always be passed in the same order to the compiler.
                // Otherwise player builds might fail for partial classes.
                Array.Sort(scriptAssembly.Files);
            }

            // Setup ScriptAssembly references
            index = 0;
            foreach (var entry in targetAssemblies)
            {
                AddScriptAssemblyReferences(ref scriptAssemblies[index++], entry.Key, settings,
                                            assemblies, targetToScriptAssembly, settings.FilenameSuffix);
            }

            return(scriptAssemblies);
        }
Пример #19
0
 public static string GetFullPath(string path)
 {
     return(AssetPath.ReplaceSeparators(Path.GetFullPath(path.NormalizePath())));
 }
Пример #20
0
 public string FullPath(string outputDirectory, string filenameSuffix)
 {
     return(AssetPath.Combine(outputDirectory, FilenameWithSuffix(filenameSuffix)));
 }
Пример #21
0
 public static string GetDirectoryName(string path)
 {
     return(AssetPath.ReplaceSeparators(Path.GetDirectoryName(path.NormalizePath())));
 }
Пример #22
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++;
        }