public void Compile() { Profiler.BeginSample("UdonSharp Compile"); System.Diagnostics.Stopwatch compileTimer = new System.Diagnostics.Stopwatch(); compileTimer.Start(); int totalErrorCount = 0; try { EditorUtility.DisplayProgressBar("UdonSharp Compile", "Parsing Syntax Trees...", 0f); UdonSharpProgramAsset[] allPrograms = UdonSharpProgramAsset.GetAllUdonSharpPrograms(); List <(UdonSharpProgramAsset, string)> programAssetsAndPaths = new List <(UdonSharpProgramAsset, string)>(); foreach (UdonSharpProgramAsset programAsset in allPrograms) { if (programAsset == null || programAsset.sourceCsScript == null) { continue; } programAssetsAndPaths.Add((programAsset, AssetDatabase.GetAssetPath(programAsset.sourceCsScript))); } UdonSharpProgramAsset[] programAssetsToCompile = modules.Select(e => e.programAsset).Where(e => e != null && e.sourceCsScript != null).ToArray(); try { beforeCompile?.Invoke(programAssetsToCompile); } catch (System.Exception e) { Debug.LogError($"Exception thrown by pre compile listener\n{e}"); } object syntaxTreeLock = new object(); List <(UdonSharpProgramAsset, Microsoft.CodeAnalysis.SyntaxTree)> programsAndSyntaxTrees = new List <(UdonSharpProgramAsset, Microsoft.CodeAnalysis.SyntaxTree)>(); Dictionary <UdonSharpProgramAsset, (string, Microsoft.CodeAnalysis.SyntaxTree)> syntaxTreeSourceLookup = new Dictionary <UdonSharpProgramAsset, (string, Microsoft.CodeAnalysis.SyntaxTree)>(); string[] defines = UdonSharpUtils.GetProjectDefines(isEditorBuild); Parallel.ForEach(programAssetsAndPaths, (currentProgram) => { string programSource = UdonSharpUtils.ReadFileTextSync(currentProgram.Item2); Microsoft.CodeAnalysis.SyntaxTree programSyntaxTree = CSharpSyntaxTree.ParseText(programSource, CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.None).WithPreprocessorSymbols(defines)); lock (syntaxTreeLock) { programsAndSyntaxTrees.Add((currentProgram.Item1, programSyntaxTree)); syntaxTreeSourceLookup.Add(currentProgram.Item1, (programSource, programSyntaxTree)); } });
public static void Compile(UdonSharpCompileOptions options = null) { if (options == null) options = new UdonSharpCompileOptions(); if (UdonSharpUtils.DoesUnityProjectHaveCompileErrors()) { UdonSharpUtils.LogError("All Unity C# compiler errors must be resolved before running an UdonSharp compile."); return; } if (CurrentJob != null) { _compileQueued = true; _queuedOptions = options; return; } Localization.Loc.InitLocalization(); UdonSharpProgramAsset[] allPrograms = UdonSharpProgramAsset.GetAllUdonSharpPrograms(); bool hasError = !ValidateProgramAssetCollisions(allPrograms); Dictionary<string, ProgramAssetInfo> rootProgramLookup = new Dictionary<string, ProgramAssetInfo>(); foreach (UdonSharpProgramAsset udonSharpProgram in allPrograms) { if (udonSharpProgram.sourceCsScript == null) { UdonSharpUtils.LogError($"Source C# script on {udonSharpProgram} is null", udonSharpProgram); hasError = true; continue; } string assetPath = AssetDatabase.GetAssetPath(udonSharpProgram.sourceCsScript); if (string.IsNullOrEmpty(assetPath)) { UdonSharpUtils.LogError($"Source C# script on {udonSharpProgram} is null", udonSharpProgram); hasError = true; continue; } rootProgramLookup.Add(assetPath.Replace('\\', '/'), new ProgramAssetInfo() { programAsset = udonSharpProgram ? udonSharpProgram : null, scriptClass = udonSharpProgram != null ? udonSharpProgram.GetClass() : null }); } if (hasError) { UdonSharpEditorCache.Instance.LastCompileDiagnostics = new [] { new UdonSharpEditorCache.CompileDiagnostic() { file = "", message = "Compile validation failed, check console output for details.", severity = DiagnosticSeverity.Error, } }; return; } // var allSourcePaths = new HashSet<string>(UdonSharpProgramAsset.GetAllUdonSharpPrograms().Where(e => e.isV1Root).Select(e => AssetDatabase.GetAssetPath(e.sourceCsScript).Replace('\\', '/'))); HashSet<string> allSourcePaths = new HashSet<string>(CompilationContext.GetAllFilteredSourcePaths(options.IsEditorBuild)); if (!ValidateUdonSharpBehaviours(allPrograms, allSourcePaths)) return; CompilationContext compilationContext = new CompilationContext(options); string[] defines = UdonSharpUtils.GetProjectDefines(options.IsEditorBuild); EditorApplication.LockReloadAssemblies(); Task compileTask = new Task(() => Compile(compilationContext, rootProgramLookup, allSourcePaths, defines)); CurrentJob = new CompileJob() { Context = compilationContext, Task = compileTask, CompileTimer = Stopwatch.StartNew(), CompileOptions = options }; compileTask.Start(); }
public void Compile() { Profiler.BeginSample("UdonSharp Compile"); System.Diagnostics.Stopwatch compileTimer = new System.Diagnostics.Stopwatch(); compileTimer.Start(); int totalErrorCount = 0; try { EditorUtility.DisplayProgressBar("UdonSharp Compile", "Initializing...", 0f); UdonSharpProgramAsset[] allPrograms = UdonSharpProgramAsset.GetAllUdonSharpPrograms(); List <(UdonSharpProgramAsset, string)> programAssetsAndPaths = new List <(UdonSharpProgramAsset, string)>(); foreach (UdonSharpProgramAsset programAsset in allPrograms) { if (programAsset == null) { continue; } if (programAsset.sourceCsScript == null) { Debug.LogWarning($"[<color=#FF00FF>UdonSharp</color>] Program asset '{AssetDatabase.GetAssetPath(programAsset)}' is missing a source C# script"); continue; } programAssetsAndPaths.Add((programAsset, AssetDatabase.GetAssetPath(programAsset.sourceCsScript))); programAsset.compileErrors.Clear(); // Clear compile errors to keep them from stacking if not resolved } CheckProgramAssetCollisions(allPrograms); UdonSharpProgramAsset[] programAssetsToCompile = modules.Select(e => e.programAsset).Where(e => e != null && e.sourceCsScript != null).ToArray(); EditorUtility.DisplayProgressBar("UdonSharp Compile", "Executing pre-build events...", 0f); try { beforeCompile?.Invoke(programAssetsToCompile); } catch (System.Exception e) { Debug.LogError($"Exception thrown by pre compile listener\n{e}"); } EditorUtility.DisplayProgressBar("UdonSharp Compile", "Parsing Syntax Trees...", 0f); object syntaxTreeLock = new object(); List <(UdonSharpProgramAsset, Microsoft.CodeAnalysis.SyntaxTree)> programsAndSyntaxTrees = new List <(UdonSharpProgramAsset, Microsoft.CodeAnalysis.SyntaxTree)>(); Dictionary <UdonSharpProgramAsset, (string, Microsoft.CodeAnalysis.SyntaxTree)> syntaxTreeSourceLookup = new Dictionary <UdonSharpProgramAsset, (string, Microsoft.CodeAnalysis.SyntaxTree)>(); string[] defines = UdonSharpUtils.GetProjectDefines(isEditorBuild); Parallel.ForEach(programAssetsAndPaths, (currentProgram) => { string programSource = UdonSharpUtils.ReadFileTextSync(currentProgram.Item2); #pragma warning disable CS1701 // Warning about System.Collections.Immutable versions potentially not matching Microsoft.CodeAnalysis.SyntaxTree programSyntaxTree = CSharpSyntaxTree.ParseText(programSource, CSharpParseOptions.Default.WithDocumentationMode(DocumentationMode.None).WithPreprocessorSymbols(defines)); #pragma warning restore CS1701 lock (syntaxTreeLock) { programsAndSyntaxTrees.Add((currentProgram.Item1, programSyntaxTree)); syntaxTreeSourceLookup.Add(currentProgram.Item1, (programSource, programSyntaxTree)); } });
private static bool UpgradeScripts(UdonSharpProgramAsset[] programAssets) { if (programAssets.Length == 0) { return(false); } if (programAssets.All(e => e.ScriptVersion >= UdonSharpProgramVersion.CurrentVersion)) { return(false); } CompilationContext compilationContext = new CompilationContext(new UdonSharpCompileOptions()); ModuleBinding[] bindings = compilationContext.LoadSyntaxTreesAndCreateModules(CompilationContext.GetAllFilteredSourcePaths(false), UdonSharpUtils.GetProjectDefines(false)); CSharpCompilation compilation = CSharpCompilation.Create( $"UdonSharpRoslynUpgradeAssembly{_assemblyCounter++}", bindings.Select(e => e.tree), CompilationContext.GetMetadataReferences(), new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); bool scriptUpgraded = false; bool versionUpgraded = false; foreach (var programAsset in programAssets) { string assetPath = AssetDatabase.GetAssetPath(programAsset.sourceCsScript); ModuleBinding binding = bindings.FirstOrDefault(e => e.filePath == assetPath); if (binding == null) { continue; } if (programAsset.ScriptVersion < UdonSharpProgramVersion.V1SerializationUpdate) { SyntaxTree bindingTree = binding.tree; SemanticModel bindingModel = compilation.GetSemanticModel(bindingTree); SerializationUpdateSyntaxRewriter rewriter = new SerializationUpdateSyntaxRewriter(bindingModel); SyntaxNode newRoot = rewriter.Visit(bindingTree.GetRoot()); if (rewriter.Modified) { try { File.WriteAllText(binding.filePath, newRoot.ToFullString(), Encoding.UTF8); scriptUpgraded = true; UdonSharpUtils.Log($"Upgraded field serialization attributes on U# script '{binding.filePath}'", programAsset.sourceCsScript); } catch (Exception e) { UdonSharpUtils.LogError($"Could not upgrade U# script, exception: {e}"); } } // We expect this to come through a second time after scripts have been updated and change the version on the asset. else { programAsset.ScriptVersion = UdonSharpProgramVersion.V1SerializationUpdate; EditorUtility.SetDirty(programAsset); versionUpgraded = true; } } } if (scriptUpgraded) { AssetDatabase.Refresh(); return(true); } if (versionUpgraded) { UdonSharpCompilerV1.CompileSync(new UdonSharpCompileOptions()); } return(false); }