- Home /
Detect compilation errors in Editor script?
Hello,
I have a custom editor script that creates an android build which takes around 5-10 minutes to compile. Does anybody know if there is a way to detect C# compilation errors in an Editor script so I can prevent the script from running at all if the code has errors?
I already use EditorApplication.isCompiling to detect if compilation is currently in progress.
Cheers!
As far as I know, the script won't run anyway if you get errors. Unity will tell you in the console that there is an error.
That is true, however it takes 4 $$anonymous$$utes to get to the point where the build fails. It would be nice to be able do what the run button in the Editor does when you have a compile error.
Answer by 3zanders · Jun 28, 2013 at 05:31 PM
I found a solution! The following function will clear the unity console and throw an exception if you have compile errors. This works because clearing the log view doesn't remove compilation error logs.
static void ClearLog()
{
Assembly assembly = Assembly.GetAssembly(typeof(SceneView));
Type logEntries = assembly.GetType("UnityEditorInternal.LogEntries");
logEntries.GetMethod("Clear").Invoke (new object (), null);
int count = (int)logEntries.GetMethod("GetCount").Invoke(new object (), null);
if (count > 0)
throw new Exception("Cannot build because you have compile errors!");
}
Answer by Deepscorn · Sep 22, 2019 at 12:58 PM
You can use CompilationPipeline.assemblyCompilationFinished:
[InitializeOnLoad]
class NoErrorsValidator
{
static NoErrorsValidator()
{
if (Application.isBatchMode)
CompilationPipeline.assemblyCompilationFinished += ProcessBatchModeCompileFinish;
}
private void ProcessBatchModeCompileFinish(string s, CompilerMessage[] compilerMessages)
{
if (compilerMessages.Count(m => m.type == CompilerMessageType.Error) > 0)
EditorApplication.Exit(-1);
}
}
Also, it may be helpful to move it to separate assembly. To put to another assembly, you can use asmdef https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html
To receive compile error in batchmode, I subscribe to it as early as possible. The only way, I found, is use InitializeOnLoad https://docs.unity3d.com/ScriptReference/InitializeOnLoadAttribute.html
$$anonymous$$oving that code to separate assembly is helpful because that way validator assembly will always compile even when you have compilation errors in another assemblies
Answer by LevonRavel · Oct 31, 2018 at 09:02 PM
You can simply do this..
The Update to listen if compiling is just non sense. The most upvoted answer is also crazy..
using UnityEngine;
using UnityEditor;
[InitializeOnLoad]
class CompileListener
{
static CompileListener()
{
Application.logMessageReceived += Application_logMessageReceived;
}
private static void Application_logMessageReceived(string condition, string stackTrace, LogType type)
{
Debug.Log("Condition" + condition + " StackTrace " + stackTrace + " LogType " + type);
if (type == LogType.Error)
{
//Do stuff
}
}
}
Answer by steffen-itterheim · Feb 01, 2018 at 09:29 AM
Rather than clearing the console log, the more elegant solution is to hook into Application.LogMessageReceived during the compilation. Inside the UnityLog callback method check if the LogType is "Error". If so, you can be certain that compilation failed.
A complete but untested (I stripped down my version to a minimum) script that records and logs script compile time, but only if the script compilation did not fail by adding and removing itself from the LogMessageReceived event:
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
class CompileTimeMonitor : ScriptableObject
{
static bool s_isTrackingTime;
static double s_startTime;
// since class has InitializeOnLoad, these values are re-set for every compilation
static bool s_compilationSucceeded = true;
static string s_messages = string.Empty;
static CompileTimeMonitor()
{
EditorApplication.update += Update;
s_startTime = PlayerPrefs.GetFloat("CompileStartTime", 0);
if (s_startTime > 0)
s_isTrackingTime = true;
}
static void Update()
{
if (EditorApplication.isCompiling && s_isTrackingTime == false)
{
s_isTrackingTime = true;
StartRecordingCompileTime();
}
else if (EditorApplication.isCompiling == false && s_isTrackingTime)
{
s_isTrackingTime = false;
StopRecordingCompileTime();
LogTimes();
}
}
static void UnityDebugLog(string message, string stackTrace, LogType logType)
{
// if we receive a Debug.LogError we can assume that compilation failed
if (logType == LogType.Error)
s_compilationSucceeded = false;
}
static void StartRecordingCompileTime()
{
Application.logMessageReceived += UnityDebugLog;
s_startTime = EditorApplication.timeSinceStartup;
PlayerPrefs.SetFloat("CompileStartTime", (float)s_startTime);
}
static void StopRecordingCompileTime()
{
Application.logMessageReceived -= UnityDebugLog;
var finishTime = EditorApplication.timeSinceStartup;
s_lastCompileTime = (float)(finishTime - s_startTime);
PlayerPrefs.DeleteKey("CompileStartTime");
}
static void LogTimes()
{
if (s_lastCompileTime <= 0f)
return;
if (s_compilationSucceeded)
Debug.Log("Compilation Success. Congratulations, you are awesome!");
else
Debug.LogError("Compilation FAILED. #$%*&§!!!!");
if (s_compilationSucceeded)
Debug.Log("It took " + s_lastCompileTime + "s to compile scripts.");
}
}
Your answer
Follow this Question
Related Questions
Automate exclusion of specific Android plugin from build? 0 Answers
Multiple Cars not working 1 Answer
Android APK acts different than in Editor 1 Answer
Initialising List array for use in a custom Editor 1 Answer
Distribute terrain in zones 3 Answers