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); }
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; }
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); }
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); }
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); }
public static bool IsPrecompiledAssemblyNunit(ref PrecompiledAssembly precompiledAssembly) { return(AssetPath.GetFileName(precompiledAssembly.Path) == k_NunitAssemblyName); }
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)); }
// 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 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();
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(); }
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); }
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()); }
public string FullPath(string outputDirectory) { return(AssetPath.Combine(outputDirectory, Filename)); }
// 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(); }
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); }
public static string GetFullPath(string path) { return(AssetPath.ReplaceSeparators(Path.GetFullPath(path.NormalizePath()))); }
public string FullPath(string outputDirectory, string filenameSuffix) { return(AssetPath.Combine(outputDirectory, FilenameWithSuffix(filenameSuffix))); }
public static string GetDirectoryName(string path) { return(AssetPath.ReplaceSeparators(Path.GetDirectoryName(path.NormalizePath()))); }
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++; }